diff --git a/frontend/.changeset/khaki-schools-move.md b/frontend/.changeset/khaki-schools-move.md new file mode 100644 index 0000000..3efbd4f --- /dev/null +++ b/frontend/.changeset/khaki-schools-move.md @@ -0,0 +1,5 @@ +--- +'pydantic-forms': patch +--- + +Fixes form labels diff --git a/frontend/.changeset/loose-boxes-fetch.md b/frontend/.changeset/loose-boxes-fetch.md new file mode 100644 index 0000000..fd24dcf --- /dev/null +++ b/frontend/.changeset/loose-boxes-fetch.md @@ -0,0 +1,5 @@ +--- +'pydantic-forms': patch +--- + +Makes rowRenderer configurable diff --git a/frontend/packages/pydantic-forms/src/components/fields/FieldWrap.tsx b/frontend/packages/pydantic-forms/src/components/fields/FieldWrap.tsx index 5915678..b7745c7 100644 --- a/frontend/packages/pydantic-forms/src/components/fields/FieldWrap.tsx +++ b/frontend/packages/pydantic-forms/src/components/fields/FieldWrap.tsx @@ -8,9 +8,7 @@ * */ import React from 'react'; -import type { ControllerFieldState } from 'react-hook-form'; -import ResetNullableFieldTrigger from '@/components/form/ResetNullableFieldTrigger'; import { usePydanticFormContext } from '@/core'; import { PydanticFormField } from '@/types'; @@ -18,36 +16,27 @@ import { FormRow } from './FormRow'; interface FieldWrapProps { pydanticFormField: PydanticFormField; - fieldState: ControllerFieldState; children: React.ReactNode; } -export const FieldWrap = ({ - pydanticFormField, - fieldState, - children, -}: FieldWrapProps) => { - const { errorDetails } = usePydanticFormContext(); - +export const FieldWrap = ({ pydanticFormField, children }: FieldWrapProps) => { + const { errorDetails, rhf, config } = usePydanticFormContext(); + const RowRenderer = config?.rowRenderer ? config.rowRenderer : FormRow; + const fieldState = rhf.getFieldState(pydanticFormField.id); const errorMsg = errorDetails?.mapped?.[pydanticFormField.id]?.msg ?? fieldState.error?.message; const isInvalid = errorMsg ?? fieldState.invalid; return ( - - {pydanticFormField.title} - - - } +
{children}
-
+ ); }; diff --git a/frontend/packages/pydantic-forms/src/components/fields/FormRow.tsx b/frontend/packages/pydantic-forms/src/components/fields/FormRow.tsx index fc79d36..2d73e57 100644 --- a/frontend/packages/pydantic-forms/src/components/fields/FormRow.tsx +++ b/frontend/packages/pydantic-forms/src/components/fields/FormRow.tsx @@ -3,7 +3,7 @@ import type { HTMLAttributes, ReactElement, ReactNode } from 'react'; type FormRowProps = { children: ReactElement; - label?: ReactNode; + title: string; isInvalid?: boolean; error?: ReactNode | ReactNode[]; description?: string; @@ -12,19 +12,17 @@ type FormRowProps = { export const FormRow = ({ children, - label, - isInvalid, + title, error, - ...rest + description, + required, }: FormRowProps) => { - // TODO: readd required, description, classname return ( -
)}> - {label && ( - - )} +
+ + {description &&
{description}
} {children} {error}
diff --git a/frontend/packages/pydantic-forms/src/components/render/RenderForm.tsx b/frontend/packages/pydantic-forms/src/components/render/RenderForm.tsx index e2d4ecb..f3fa168 100644 --- a/frontend/packages/pydantic-forms/src/components/render/RenderForm.tsx +++ b/frontend/packages/pydantic-forms/src/components/render/RenderForm.tsx @@ -67,7 +67,9 @@ const RenderForm = (contextProps: PydanticFormContextProps) => { return (
- {title !== false &&

{title ?? pydanticFormSchema.title}

} + {title !== false && title !== 'undefined' && ( +

{title ?? pydanticFormSchema.title}

+ )} {headerComponent} diff --git a/frontend/packages/pydantic-forms/src/core/PydanticFormContextProvider.tsx b/frontend/packages/pydantic-forms/src/core/PydanticFormContextProvider.tsx index 2a69f5d..9734c28 100644 --- a/frontend/packages/pydantic-forms/src/core/PydanticFormContextProvider.tsx +++ b/frontend/packages/pydantic-forms/src/core/PydanticFormContextProvider.tsx @@ -135,7 +135,7 @@ function PydanticFormContextProvider({ const { pydanticFormSchema, isLoading: isParsingSchema } = usePydanticFormParser( rawSchema, - formLabels, + formLabels?.labels, fieldDetailProvider, formStructureMutator, ); @@ -223,7 +223,7 @@ function PydanticFormContextProvider({ } const initialData = getFormValuesFromFieldOrLabels(pydanticFormSchema, { - ...formLabels, + ...formLabels?.data, ...customData, }); diff --git a/frontend/packages/pydantic-forms/src/core/WrapFieldElement.tsx b/frontend/packages/pydantic-forms/src/core/WrapFieldElement.tsx index b9aab3f..f96f47f 100644 --- a/frontend/packages/pydantic-forms/src/core/WrapFieldElement.tsx +++ b/frontend/packages/pydantic-forms/src/core/WrapFieldElement.tsx @@ -18,7 +18,7 @@ export const WrapFieldElement = ({ { + render={({ field }) => { const { onChange, onBlur, value, name, ref } = field; const onChangeHandle = (val: string) => { onChange(val); @@ -30,10 +30,7 @@ export const WrapFieldElement = ({ }; return ( - + { */ export const getFormValuesFromFieldOrLabels = ( pydanticFormSchema: PydanticFormSchema, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - labelData?: Record, + labelData?: Record, ) => { const fieldValues: Record = {}; diff --git a/frontend/packages/pydantic-forms/src/core/hooks/useApiProvider.tsx b/frontend/packages/pydantic-forms/src/core/hooks/useApiProvider.tsx index 126b687..c6496e8 100644 --- a/frontend/packages/pydantic-forms/src/core/hooks/useApiProvider.tsx +++ b/frontend/packages/pydantic-forms/src/core/hooks/useApiProvider.tsx @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ - /** * Pydantic Forms * @@ -22,12 +20,7 @@ import type { PydanticFormMetaData, } from '@/types'; -const ignoreApiErrors = async ( - req: Promise, - // ignoreCodes: number[], - // eslint-disable-next-line @typescript-eslint/no-explicit-any -): Promise => { - // TODO: What to use these for: ignoreCodes +const ignoreApiErrors = async (req: Promise): Promise => { try { return await req; } catch (error) { diff --git a/frontend/packages/pydantic-forms/src/core/hooks/useCustomDataProvider.tsx b/frontend/packages/pydantic-forms/src/core/hooks/useCustomDataProvider.tsx index b10782c..7c45d12 100644 --- a/frontend/packages/pydantic-forms/src/core/hooks/useCustomDataProvider.tsx +++ b/frontend/packages/pydantic-forms/src/core/hooks/useCustomDataProvider.tsx @@ -1,12 +1,15 @@ import useSWR from 'swr'; -import { PydanticFormCustomDataProvider, PydanticFormLabels } from '@/types'; +import { + PydanticFormCustomDataProvider, + PydanticFormLabelProviderResponse, +} from '@/types'; export const useCustomDataProvider = ( customDataProviderCacheKey: number, customDataProvider?: PydanticFormCustomDataProvider, ) => { - return useSWR( + return useSWR( // cache key [`pydanticFormsDataProvider-${customDataProviderCacheKey}`], diff --git a/frontend/packages/pydantic-forms/src/core/hooks/useLabelProvider.tsx b/frontend/packages/pydantic-forms/src/core/hooks/useLabelProvider.tsx index 70b67ae..f7e9de9 100644 --- a/frontend/packages/pydantic-forms/src/core/hooks/useLabelProvider.tsx +++ b/frontend/packages/pydantic-forms/src/core/hooks/useLabelProvider.tsx @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ - /** * Pydantic Forms * @@ -16,7 +14,10 @@ */ import useSWR, { SWRConfiguration } from 'swr'; -import { PydanticFormLabelProvider } from '@/types'; +import { + PydanticFormLabelProvider, + PydanticFormLabelProviderResponse, +} from '@/types'; export function useLabelProvider( labelProvider?: PydanticFormLabelProvider, @@ -25,7 +26,7 @@ export function useLabelProvider( cacheKey?: number, swrConfig?: SWRConfiguration, ) { - return useSWR | undefined>( + return useSWR( // cache key [labelProvider, formKey, id, swrConfig, cacheKey], diff --git a/frontend/packages/pydantic-forms/src/core/hooks/usePydanticFormParser.tsx b/frontend/packages/pydantic-forms/src/core/hooks/usePydanticFormParser.tsx index 8fc0e6e..c398280 100644 --- a/frontend/packages/pydantic-forms/src/core/hooks/usePydanticFormParser.tsx +++ b/frontend/packages/pydantic-forms/src/core/hooks/usePydanticFormParser.tsx @@ -54,11 +54,12 @@ const parseProperties = ( const parsedProperty: PydanticFormField = { id, - title: translateLabel( - propertyId, - propertySchema.title, - formLabels, - ), + title: + translateLabel( + propertyId, + propertySchema.title, + formLabels, + ) || propertyId, description: translateLabel( `${propertyId}_info`, propertySchema.description, diff --git a/frontend/packages/pydantic-forms/src/types.ts b/frontend/packages/pydantic-forms/src/types.ts index da2973e..27e5c83 100644 --- a/frontend/packages/pydantic-forms/src/types.ts +++ b/frontend/packages/pydantic-forms/src/types.ts @@ -83,7 +83,7 @@ export enum PydanticFormState { export interface PydanticFormField { id: string; - title?: string; + title: string; description?: string; type: PydanticFormFieldType; format: PydanticFormFieldFormat; @@ -249,6 +249,15 @@ export type PydanticFormZodValidationFn = ( rhf?: ReturnType, ) => z.ZodTypeAny; +export type RowRenderer = React.JSXElementConstructor<{ + title: string; + description?: string; + required?: boolean; + isInvalid?: boolean; + error?: string; + children: React.ReactNode; +}>; + export interface PydanticFormZodValidationPresets { [type: string]: PydanticFormZodValidationFn; } @@ -286,6 +295,7 @@ export interface PydanticFormsContextConfig { formRenderer?: FormRenderer; footerRenderer?: React.JSXElementConstructor; + rowRenderer?: RowRenderer; // Extend field definitions fieldDetailProvider?: PydanticFormFieldDetailProvider; @@ -308,11 +318,9 @@ interface PydanticFormComponent { export type PydanticFormComponents = PydanticFormComponent[]; -export type PydanticFormCustomDataProvider = () => Promise; - -export interface PydanticFormLabels { - [key: string]: string[] | number[] | string | number | null; -} +export type PydanticFormCustomDataProvider = () => Promise< + PydanticFormLabelProviderResponse['data'] +>; export type PydanticFormLabelProvider = ({ formKey, @@ -320,8 +328,7 @@ export type PydanticFormLabelProvider = ({ }: { formKey: string; id?: string | null; - // eslint-disable-next-line @typescript-eslint/no-explicit-any -}) => Promise>; +}) => Promise; // will return column export type PydanticFormLayoutColumnProvider = (fieldId: string) => number; @@ -360,6 +367,11 @@ export type PydanticFormCustomValidationRuleFn = ( rhf?: ReturnType, ) => Zod.ZodTypeAny | undefined; +export interface PydanticFormLabelProviderResponse { + labels: Record; + data: Record; +} + export interface PydanticFormApiResponse { detail?: string; status: number;