Migrating foreign-key to his new fish tank

This commit is contained in:
2025-04-21 20:24:43 +02:00
parent 9e823d003e
commit 7b6ca62d9a

View File

@@ -1,11 +1,11 @@
import {FormContextType, RJSFSchema, StrictRJSFSchema, WidgetProps} from '@rjsf/utils'; import {FormContextType, RJSFSchema, WidgetProps} from '@rjsf/utils';
import { Autocomplete } from "@mui/material"; import { Autocomplete, CircularProgress, TextField } from "@mui/material";
import { useState, useEffect } from "react"; import React, { useState, useEffect, useContext } from "react";
import TextField from "@mui/material/TextField"; import { useList, useOne } from "@refinedev/core";
import {BaseRecord, useList, useOne} from "@refinedev/core"; import { ResourceContext } from "../../contexts/ResourceContext";
type ForeignKeySchema = RJSFSchema & { type ForeignKeySchema = RJSFSchema & {
foreign_key?: { foreignKey?: {
reference: { reference: {
resource: string, resource: string,
label: string label: string
@@ -16,59 +16,90 @@ type ForeignKeySchema = RJSFSchema & {
export default function ForeignKeyWidget<T = any, S extends ForeignKeySchema = ForeignKeySchema, F extends FormContextType = any>( export default function ForeignKeyWidget<T = any, S extends ForeignKeySchema = ForeignKeySchema, F extends FormContextType = any>(
props: WidgetProps<T, S, F> props: WidgetProps<T, S, F>
) { ) {
if (props.schema.foreign_key === undefined) { if (props.schema.foreignKey === undefined) {
return; return;
} }
const resource = props.schema.foreign_key.reference.resource const { onChange, value: originalValue } = props;
const labelField = props.schema.foreign_key.reference.label const [initialState, setInitialState] = useState(true);
if (originalValue != null && initialState) {
return <InitialValue {...props} onClear={() => {setInitialState(false); onChange(null)}}/>
}
const valueResult = useOne({ return (
resource: resource, <RealAutocomplete {...props}/>
id: props.value != null ? props.value : undefined )
};
const InitialValue = <T = any, S extends ForeignKeySchema = ForeignKeySchema, F extends FormContextType = any>(
props: WidgetProps<T, S, F> & { onClear: () => void }
) => {
const { onClear, value } = props;
if (props.schema.foreignKey === undefined) {
return;
}
const { resource, label: labelField = "label" } = props.schema.foreignKey.reference
const { basePath } = useContext(ResourceContext)
const { data, isLoading } = useOne({
resource: `${basePath}/${resource}`,
id: value
}); });
const empty_option: BaseRecord = { if (isLoading || data === undefined) {
id: undefined return <CircularProgress />
}
empty_option[labelField] = "(None)"
const [inputValue, setInputValue] = useState<string>("");
const [selectedValue, setSelectedValue] = useState(valueResult.data?.data || null);
const [debouncedInputValue, setDebouncedInputValue] = useState<string>(inputValue);
useEffect(() => {
const handler = setTimeout(() => setDebouncedInputValue(inputValue), 300); // Adjust debounce delay as needed
return () => clearTimeout(handler);
}, [inputValue]);
const listResult = useList({
resource: resource,
pagination: { current: 1, pageSize: 10 },
filters: [{ field: "name", operator: "contains", value: debouncedInputValue }],
sorters: [{ field: "name", order: "asc" }],
});
const options = listResult.data?.data || [];
if (! props.required) {
options.unshift(empty_option);
}
const isLoading = listResult.isLoading || valueResult.isLoading;
if(! selectedValue && valueResult.data) {
setSelectedValue(valueResult.data?.data)
} }
return ( return (
<Autocomplete <Autocomplete
value={selectedValue} value={data.data}
onChange={(event, newValue) => { onChange={() => onClear()}
setSelectedValue(newValue ? newValue : empty_option); onInputChange={() => onClear()}
props.onChange(newValue ? newValue.id : null); options={[data.data]}
getOptionLabel={(option) => option ? option[labelField] : ""}
loading={isLoading}
renderInput={(params) => (
<TextField {...params} label={ props.label } variant="outlined" />
)}
/>
)
}
const RealAutocomplete = <T = any, S extends ForeignKeySchema = ForeignKeySchema, F extends FormContextType = any>(
props: WidgetProps<T, S, F>
) => {
if (props.schema.foreignKey === undefined) {
return;
}
const { onChange } = props
const [searchString, setSearchString] = useState<string>("");
const [debouncedInputValue, setDebouncedInputValue] = useState<string>();
useEffect(() => {
const handler = setTimeout(() => setDebouncedInputValue(searchString), 300); // Adjust debounce delay as needed
return () => clearTimeout(handler);
}, [searchString]);
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" }],
});
return (
<Autocomplete
onChange={(event, value) => {
onChange(value ? value.id : null);
return true; return true;
}} }}
//inputValue={inputValue} onInputChange={(event, newInputValue) => {
onInputChange={(event, newInputValue) => setInputValue(newInputValue)} setSearchString(newInputValue)
options={options} console.log(newInputValue)
}}
options={data ? data.data : []}
getOptionLabel={(option) => option ? option[labelField] : ""} getOptionLabel={(option) => option ? option[labelField] : ""}
loading={isLoading} loading={isLoading}
renderInput={(params) => ( renderInput={(params) => (
@@ -76,4 +107,4 @@ export default function ForeignKeyWidget<T = any, S extends ForeignKeySchema = F
)} )}
/> />
); );
}; }