diff --git a/gui/rpk-gui/src/lib/crud/components/widgets/foreign-key.tsx b/gui/rpk-gui/src/lib/crud/components/widgets/foreign-key.tsx index f0b1b48..22cc8ae 100644 --- a/gui/rpk-gui/src/lib/crud/components/widgets/foreign-key.tsx +++ b/gui/rpk-gui/src/lib/crud/components/widgets/foreign-key.tsx @@ -1,15 +1,23 @@ -import {FormContextType, RJSFSchema, WidgetProps} from '@rjsf/utils'; -import { Autocomplete, CircularProgress, TextField } from "@mui/material"; +import { FormContextType, RJSFSchema, UiSchema, WidgetProps } from '@rjsf/utils'; +import { Autocomplete, Button, CircularProgress, Container, Grid2, InputAdornment, Modal, TextField, Box } from "@mui/material"; +import ClearIcon from '@mui/icons-material/Clear'; +import EditIcon from '@mui/icons-material/Edit'; +import NoteAddIcon from '@mui/icons-material/NoteAdd'; import React, { useState, useEffect, useContext } from "react"; import { useList, useOne } from "@refinedev/core"; import { ResourceContext } from "../../contexts/ResourceContext"; +import { CrudForm } from "../crud-form"; + +type ForeignKeyReference = { + resource: string, + label: string, + displayedFields: [string], + schema: string +} type ForeignKeySchema = RJSFSchema & { foreignKey?: { - reference: { - resource: string, - label: string - } + reference: ForeignKeyReference } } @@ -19,26 +27,105 @@ export default function ForeignKeyWidget {setInitialState(false); onChange(null)}}/> - } - return ( - - ) + const { value: originalValue, onChange } = props; + const [currentValue, setCurrentValue] = useState(originalValue) + + if (currentValue) { + return {setCurrentValue(null); onChange(null)}}/> + } + return {setCurrentValue(value); onChange(value)}}/> }; -const InitialValue = ( +const RealAutocomplete = ( + props: WidgetProps +) => { + if (props.schema.foreignKey === undefined) { + return; + } + const { onChange, label } = props + + const [openFormModal, setOpenFormModal] = useState(false); + const [searchString, setSearchString] = useState(""); + const [debouncedInputValue, setDebouncedInputValue] = useState(); + useEffect(() => { + const handler = setTimeout(() => setDebouncedInputValue(searchString), 300); // Adjust debounce delay as needed + return () => clearTimeout(handler); + }, [searchString]); + + const { resource, schema, label: labelField = "label" } = props.schema.foreignKey.reference + const { basePath } = useContext(ResourceContext) + const { data, isLoading } = useList({ + resource: `${basePath}/${resource}`, + pagination: { current: 1, pageSize: 10, mode: "server" }, + filters: [{ field: "label", operator: "contains", value: debouncedInputValue }], + sorters: [{ field: "label", order: "asc" }], + }); + + return ( + <> + { + onChange(value ? value.id : null); + return true; + }} + onInputChange={(event, value) => { + setSearchString(value) + }} + options={data ? data.data : []} + getOptionLabel={(option) => option ? option[labelField] : ""} + loading={isLoading} + forcePopupIcon={false} + renderInput={(params) => ( + setOpenFormModal(true)} color="success" > + + + ), + }, + }} + /> + )} + /> + setOpenFormModal(false)} + aria-labelledby="modal-modal-title" + aria-describedby="modal-modal-description" + > + { + setOpenFormModal(false) + onChange(data.data.id); + }} + /> + + + ); +} + +const ChosenValue = ( props: WidgetProps & { onClear: () => void } ) => { const { onClear, value } = props; + const [openFormModal, setOpenFormModal] = React.useState(false); + if (props.schema.foreignKey === undefined) { return; } - const { resource, label: labelField = "label" } = props.schema.foreignKey.reference + const { resource, schema, label: labelField = "label", displayedFields } = props.schema.foreignKey.reference const { basePath } = useContext(ResourceContext) const { data, isLoading } = useOne({ @@ -51,60 +138,97 @@ const InitialValue = onClear()} - onInputChange={() => onClear()} - options={[data.data]} - getOptionLabel={(option) => option ? option[labelField] : ""} - loading={isLoading} - renderInput={(params) => ( - - )} - /> + <> + + + + ), + }, + }} + /> + { displayedFields && } + setOpenFormModal(false)} + aria-labelledby="modal-modal-title" + aria-describedby="modal-modal-description" + > + setOpenFormModal(false)} + /> + + ) } -const RealAutocomplete = ( - props: WidgetProps -) => { - if (props.schema.foreignKey === undefined) { - return; - } - const { onChange } = props +const modalStyle = { + position: 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + width: 400, + bgcolor: 'background.paper', + border: '2px solid #000', + boxShadow: 24, + pt: 2, + px: 4, + pb: 3, +}; - const [searchString, setSearchString] = useState(""); - const [debouncedInputValue, setDebouncedInputValue] = useState(); - useEffect(() => { - const handler = setTimeout(() => setDebouncedInputValue(searchString), 300); // Adjust debounce delay as needed - return () => clearTimeout(handler); - }, [searchString]); +type FormContainerProps = { + schemaName: string, + resourceBasePath: string, + resource: string, + uiSchema?: UiSchema, + id?: string, + onSuccess: (data: any) => void +} - const { resource, label: labelField = "label" } = props.schema.foreignKey.reference - const { basePath } = useContext(ResourceContext) - const { data, isLoading } = useList({ - resource: `${basePath}/${resource}`, - pagination: { current: 1, pageSize: 10, mode: "server" }, - filters: [{ field: "label", operator: "contains", value: debouncedInputValue }], - sorters: [{ field: "label", order: "asc" }], - }); +const FormContainer = (props: FormContainerProps) => { + const { schemaName, resourceBasePath, resource, uiSchema = {}, id = undefined, onSuccess } = props; return ( - { - onChange(value ? value.id : null); - return true; - }} - onInputChange={(event, newInputValue) => { - setSearchString(newInputValue) - console.log(newInputValue) - }} - options={data ? data.data : []} - getOptionLabel={(option) => option ? option[labelField] : ""} - loading={isLoading} - renderInput={(params) => ( - - )} - /> + + + + ) +} + +const Preview = (props: {id: string, resource: string, basePath: string, displayedFields: [string]}) => { + const { basePath, resource, id, displayedFields } = props + + const { data, isLoading } = useOne({ + resource: `${basePath}/${resource}`, + id + }); + + if (isLoading || data === undefined) { + return + } + + return ( + + {displayedFields.map((field: string) => { + return ( + <> + {field} + + + ) + })} + ); }