Adding foreign key to auto forms

This commit is contained in:
2025-01-20 11:31:57 +01:00
parent fe84d6de2f
commit 35448385c5
4 changed files with 94 additions and 3 deletions

View File

@@ -2,16 +2,17 @@ from uuid import UUID, uuid4
from enum import Enum from enum import Enum
from sqlmodel import Field, SQLModel, select from sqlmodel import Field, SQLModel, select
from pydantic import Field as PydField
from category.models import CategoryRead from category.models import CategoryRead
class AccountType(Enum): class AccountType(Enum):
Asset = "Asset" # < Denotes a generic asset account. Asset = "Asset" # < Denotes a generic asset account.
Checkings = "Checkings" # < Standard checking account Checkings = "Checkings" # < Standard checking account
Savings = "Savings" # < Typical savings account Savings = "Savings" # < Typical savings account
Cash = "Cash" # < Denotes a shoe-box or pillowcase stuffed with cash Cash = "Cash" # < Denotes a shoe-box or pillowcase stuffed with cash
Liability = "Liability" # < Denotes a generic liability account. Liability = "Liability" # < Denotes a generic liability account.
CreditCard = "CreditCard" # < Credit card accounts CreditCard = "CreditCard" # < Credit card accounts
Loan = "Loan" # < Loan and mortgage accounts (liability) Loan = "Loan" # < Loan and mortgage accounts (liability)
@@ -69,10 +70,19 @@ class Account(AccountBaseId, table=True):
session.commit() session.commit()
class AccountRead(AccountBaseId): class AccountRead(AccountBaseId):
default_category: CategoryRead # default_category: CategoryRead
pass
class AccountWrite(AccountBase): class AccountWrite(AccountBase):
pass default_category_id: UUID = PydField(default=None, json_schema_extra={
"foreign_key": {
"reference": {
"resource": "categories",
"schema": "CategoryRead",
"label": "name"
}
}
})
class AccountCreate(AccountWrite): class AccountCreate(AccountWrite):
pass pass

View File

@@ -1,8 +1,11 @@
import validator from "@rjsf/validator-ajv8"; import validator from "@rjsf/validator-ajv8";
import Form from "@rjsf/mui"; import Form from "@rjsf/mui";
import { RegistryWidgetsType } from "@rjsf/utils";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { jsonschemaProvider } from "../../providers/jsonschema-provider"; import { jsonschemaProvider } from "../../providers/jsonschema-provider";
import { useForm } from "@refinedev/core"; import { useForm } from "@refinedev/core";
//import TextWidget from "@rjsf/core/src/components/widgets/TextWidget";
import CrudTextWidget from "./widgets/crud-text-widget";
type Props = { type Props = {
schemaName: string, schemaName: string,
@@ -11,6 +14,8 @@ type Props = {
//onSubmit: (data: IChangeEvent, event: FormEvent<any>) => void //onSubmit: (data: IChangeEvent, event: FormEvent<any>) => void
} }
const customWidgets: RegistryWidgetsType = { TextWidget: CrudTextWidget };
export const CrudForm: React.FC<Props> = ({schemaName, resource, id}) => { export const CrudForm: React.FC<Props> = ({schemaName, resource, id}) => {
const { onFinish, query, formLoading } = useForm({ const { onFinish, query, formLoading } = useForm({
resource: resource, resource: resource,
@@ -47,6 +52,7 @@ export const CrudForm: React.FC<Props> = ({schemaName, resource, id}) => {
onSubmit={(e) => onFinish(e.formData)} onSubmit={(e) => onFinish(e.formData)}
validator={validator} validator={validator}
omitExtraData={true} omitExtraData={true}
widgets={customWidgets}
/> />
) )
} }

View File

@@ -0,0 +1,15 @@
import TextWidget from "@rjsf/core/lib/components/widgets/TextWidget";
import {FormContextType, getTemplate, RJSFSchema, StrictRJSFSchema, WidgetProps} from "@rjsf/utils";
import {ForeignKeyWidget} from "./foreign-key";
export default function CrudTextWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
props: WidgetProps<T, S, F>
) {
if (props.schema.hasOwnProperty("foreign_key")) {
return (<ForeignKeyWidget {...props} />);
}else {
return (<CrudTextWidget {...props} />);
}
}

View File

@@ -0,0 +1,60 @@
import { RJSFSchema, UiSchema, WidgetProps, RegistryWidgetsType } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
import {Autocomplete, AutocompleteRenderInputParams, debounce} from "@mui/material";
import {useAutocomplete} from "@refinedev/mui";
import { Controller } from "react-hook-form";
import {useState, useEffect, useCallback} from "react";
import TextField from "@mui/material/TextField";
import {axiosInstance} from "@refinedev/simple-rest";
import {useList} from "@refinedev/core";
export const ForeignKeyWidget = (props: WidgetProps) => {
const [inputValue, setInputValue] = useState("");
const [selectedValue, setSelectedValue] = useState<string | null>(null);
const resource = props.schema.foreign_key.reference.resource
const { data, isLoading } = useList({
resource: resource,
pagination: { current: 1, pageSize: 10 },
sorters: [{ field: "name", order: "asc" }],
filters: [{ field: "name", operator: "contains", value: "input" }],
});
const options = data?.data || [];
// const fetchOptions = async (input: string) => {
// try {
//
// } catch (error) {
// console.error("Error fetching options:", error);
// }
// };
// // Debounced version of the fetch function
// const debouncedFetch = useCallback(debounce(fetchOptions, 300), []);
// // Trigger fetch whenever the inputValue changes
// useEffect(() => {
// if (inputValue) {
// debouncedFetch(inputValue);
// } else {
// setOptions([]); // Clear options when input is empty
// }
// }, [inputValue, debouncedFetch]);
return (
<Autocomplete
value={selectedValue}
onChange={(event, newValue) => setSelectedValue(String(newValue))}
inputValue={inputValue}
onInputChange={(event, newInputValue) => setInputValue(newInputValue)}
options={options}
getOptionLabel={(option) => option.name}
loading={isLoading}
renderInput={(params) => (
<TextField {...params} label="Search" variant="outlined" />
)}
/>
);
};