Migrating foreign-key to his new fish tank
This commit is contained in:
@@ -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
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user