@bsol-oss/react-datatable5 13.0.1-beta.2 → 13.0.1-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +70 -23
- package/dist/index.mjs +70 -23
- package/dist/types/components/Form/components/fields/FilePicker.d.ts +1 -1
- package/dist/types/components/Form/components/viewers/EnumViewer.d.ts +1 -1
- package/dist/types/components/Form/utils/useFormI18n.d.ts +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3714,7 +3714,7 @@ const TextWithCopy = ({ text, globalFilter, highlightedText, }) => {
|
|
|
3714
3714
|
const displayText = highlightedText !== undefined
|
|
3715
3715
|
? highlightedText
|
|
3716
3716
|
: highlightText$1(textValue, globalFilter);
|
|
3717
|
-
return (jsxRuntime.jsxs(react.HStack, { gap: 2, alignItems: "center", children: [jsxRuntime.jsx(react.Text, { as: "span", children: displayText }), jsxRuntime.jsx(react.Clipboard.Root, { value: textValue, children: jsxRuntime.jsx(react.Clipboard.Trigger, { asChild: true, children: jsxRuntime.jsx(react.IconButton, { size: "
|
|
3717
|
+
return (jsxRuntime.jsxs(react.HStack, { gap: 2, alignItems: "center", children: [jsxRuntime.jsx(react.Text, { as: "span", children: displayText }), jsxRuntime.jsx(react.Clipboard.Root, { value: textValue, children: jsxRuntime.jsx(react.Clipboard.Trigger, { asChild: true, children: jsxRuntime.jsx(react.IconButton, { size: "2xs", variant: "ghost", "aria-label": "Copy", fontSize: "1em", children: jsxRuntime.jsx(react.Clipboard.Indicator, { copied: jsxRuntime.jsx(lu.LuCheck, {}), children: jsxRuntime.jsx(lu.LuCopy, {}) }) }) }) })] }));
|
|
3718
3718
|
};
|
|
3719
3719
|
|
|
3720
3720
|
// Helper function to highlight matching text
|
|
@@ -4146,6 +4146,22 @@ const convertAjvErrorsToFieldErrors = (errors, schema) => {
|
|
|
4146
4146
|
// Get the schema node for this field to check for custom error messages
|
|
4147
4147
|
const fieldSchema = getSchemaNodeForField(schema, fieldName);
|
|
4148
4148
|
const customMessage = fieldSchema?.errorMessages?.[error.keyword];
|
|
4149
|
+
// Debug log when error message is missing
|
|
4150
|
+
if (!customMessage) {
|
|
4151
|
+
console.debug(`[Form Validation] Missing error message for field '${fieldName}' with keyword '${error.keyword}'. Add errorMessages.${error.keyword} to schema for field '${fieldName}'`, {
|
|
4152
|
+
fieldName,
|
|
4153
|
+
keyword: error.keyword,
|
|
4154
|
+
instancePath: error.instancePath,
|
|
4155
|
+
schemaPath: error.schemaPath,
|
|
4156
|
+
params: error.params,
|
|
4157
|
+
fieldSchema: fieldSchema
|
|
4158
|
+
? {
|
|
4159
|
+
type: fieldSchema.type,
|
|
4160
|
+
errorMessages: fieldSchema.errorMessages,
|
|
4161
|
+
}
|
|
4162
|
+
: undefined,
|
|
4163
|
+
});
|
|
4164
|
+
}
|
|
4149
4165
|
// Provide helpful fallback message if no custom message is provided
|
|
4150
4166
|
const fallbackMessage = customMessage ||
|
|
4151
4167
|
`Missing error message for ${error.keyword}. Add errorMessages.${error.keyword} to schema for field '${fieldName}'`;
|
|
@@ -4388,7 +4404,7 @@ function removeIndex(str) {
|
|
|
4388
4404
|
*
|
|
4389
4405
|
* @param column - The column name
|
|
4390
4406
|
* @param prefix - The prefix for the field (usually empty string or parent path)
|
|
4391
|
-
* @param schema -
|
|
4407
|
+
* @param schema - Required schema object with title property
|
|
4392
4408
|
* @returns Object with label helper functions
|
|
4393
4409
|
*
|
|
4394
4410
|
* @example
|
|
@@ -4421,9 +4437,21 @@ const useFormI18n = (column, prefix = '', schema) => {
|
|
|
4421
4437
|
* Uses schema.title if available, otherwise: translate.t(removeIndex(`${colLabel}.field_label`))
|
|
4422
4438
|
*/
|
|
4423
4439
|
label: (options) => {
|
|
4424
|
-
if (schema
|
|
4440
|
+
if (schema.title) {
|
|
4425
4441
|
return schema.title;
|
|
4426
4442
|
}
|
|
4443
|
+
// Debug log when field title is missing
|
|
4444
|
+
console.debug(`[Form Field Label] Missing title for field '${colLabel}'. Add title property to schema for field '${colLabel}'.`, {
|
|
4445
|
+
fieldName: column,
|
|
4446
|
+
colLabel,
|
|
4447
|
+
prefix,
|
|
4448
|
+
schema: {
|
|
4449
|
+
type: schema.type,
|
|
4450
|
+
errorMessages: schema.errorMessages
|
|
4451
|
+
? Object.keys(schema.errorMessages)
|
|
4452
|
+
: undefined,
|
|
4453
|
+
},
|
|
4454
|
+
});
|
|
4427
4455
|
return translate.t(removeIndex(`${colLabel}.field_label`), options);
|
|
4428
4456
|
},
|
|
4429
4457
|
/**
|
|
@@ -4700,7 +4728,7 @@ dayjs.extend(timezone);
|
|
|
4700
4728
|
const DateRangePicker = ({ column, schema, prefix, }) => {
|
|
4701
4729
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
4702
4730
|
const { timezone, insideDialog } = useSchemaContext();
|
|
4703
|
-
const formI18n = useFormI18n(column, prefix);
|
|
4731
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4704
4732
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
|
|
4705
4733
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4706
4734
|
const colLabel = formI18n.colLabel;
|
|
@@ -5345,7 +5373,7 @@ const MediaLibraryBrowser = ({ onFetchFiles, filterImageOnly = false, labels, en
|
|
|
5345
5373
|
}) })) }))] }));
|
|
5346
5374
|
};
|
|
5347
5375
|
|
|
5348
|
-
function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly = false, onFetchFiles, onUploadFile, enableUpload = false, labels,
|
|
5376
|
+
function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly = false, onFetchFiles, onUploadFile, enableUpload = false, labels, }) {
|
|
5349
5377
|
const [selectedFile, setSelectedFile] = React.useState(undefined);
|
|
5350
5378
|
const [activeTab, setActiveTab] = React.useState('browse');
|
|
5351
5379
|
const [uploadingFiles, setUploadingFiles] = React.useState(new Set());
|
|
@@ -5429,7 +5457,7 @@ function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly =
|
|
|
5429
5457
|
const FilePicker = ({ column, schema, prefix }) => {
|
|
5430
5458
|
const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
|
|
5431
5459
|
const { filePickerLabels } = useSchemaContext();
|
|
5432
|
-
const formI18n = useFormI18n(column, prefix);
|
|
5460
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5433
5461
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', type, } = schema;
|
|
5434
5462
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5435
5463
|
const isSingleSelect = type === 'string';
|
|
@@ -5505,7 +5533,7 @@ const FilePicker = ({ column, schema, prefix }) => {
|
|
|
5505
5533
|
const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
5506
5534
|
const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
|
|
5507
5535
|
const { filePickerLabels } = useSchemaContext();
|
|
5508
|
-
const formI18n = useFormI18n(column, prefix);
|
|
5536
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5509
5537
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', filePicker, type, } = schema;
|
|
5510
5538
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5511
5539
|
const isSingleSelect = type === 'string';
|
|
@@ -5600,9 +5628,7 @@ const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
|
5600
5628
|
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
5601
5629
|
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [jsxRuntime.jsx(react.VStack, { align: "stretch", gap: 2, children: jsxRuntime.jsx(react.Button, { variant: "outline", onClick: () => setDialogOpen(true), borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: filePickerLabels?.browseLibrary ??
|
|
5602
5630
|
formI18n.t('browse_library') ??
|
|
5603
|
-
'Browse from Library' }) }), jsxRuntime.jsx(MediaBrowserDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ??
|
|
5604
|
-
filePickerLabels?.dialogTitle ??
|
|
5605
|
-
'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, onUploadFile: onUploadFile, enableUpload: enableUpload, labels: filePickerLabels, colLabel: colLabel }), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: currentFileIds.map((fileId, index) => {
|
|
5631
|
+
'Browse from Library' }) }), jsxRuntime.jsx(MediaBrowserDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ?? formI18n.label() ?? 'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, onUploadFile: onUploadFile, enableUpload: enableUpload, labels: filePickerLabels, colLabel: colLabel }), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: currentFileIds.map((fileId, index) => {
|
|
5606
5632
|
const file = fileMap.get(fileId);
|
|
5607
5633
|
const isImage = file
|
|
5608
5634
|
? /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name)
|
|
@@ -5626,10 +5652,10 @@ const defaultRenderDisplay = (item) => {
|
|
|
5626
5652
|
const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
5627
5653
|
const { watch, getValues, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
5628
5654
|
const { idMap, setIdMap, idPickerLabels, insideDialog } = useSchemaContext();
|
|
5629
|
-
const { renderDisplay, loadInitialValues
|
|
5655
|
+
const { renderDisplay, loadInitialValues, foreign_key, variant } = schema;
|
|
5630
5656
|
// loadInitialValues must be provided in schema for id-picker fields
|
|
5631
5657
|
// It's used to load the record of the id so the display is human-readable
|
|
5632
|
-
if (variant === 'id-picker' && !
|
|
5658
|
+
if (variant === 'id-picker' && !loadInitialValues) {
|
|
5633
5659
|
throw new Error(`loadInitialValues is required in schema for IdPicker field '${column}'. Please provide loadInitialValues function in the schema to load records for human-readable display.`);
|
|
5634
5660
|
}
|
|
5635
5661
|
const { table, column: column_ref, customQueryFn, } = foreign_key;
|
|
@@ -5676,19 +5702,27 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
|
5676
5702
|
const missingIdsKey = React.useMemo(() => {
|
|
5677
5703
|
return JSON.stringify([...missingIds].sort());
|
|
5678
5704
|
}, [missingIds]);
|
|
5705
|
+
// Include idMap state in query key to force refetch when idMap is reset (e.g., on remount from another page)
|
|
5706
|
+
// This ensures the query runs even if React Query has cached data for the same missing IDs
|
|
5707
|
+
const idMapStateKey = React.useMemo(() => {
|
|
5708
|
+
// Create a key based on whether the required IDs are in idMap
|
|
5709
|
+
const hasRequiredIds = currentValue.every((id) => idMap[id]);
|
|
5710
|
+
return hasRequiredIds ? 'complete' : 'incomplete';
|
|
5711
|
+
}, [currentValue, idMap]);
|
|
5679
5712
|
// Query to fetch initial values that are missing from idMap
|
|
5680
5713
|
// This query runs automatically when missingIds.length > 0 and updates idMap
|
|
5681
5714
|
const initialValuesQuery = reactQuery.useQuery({
|
|
5682
|
-
queryKey: [`idpicker-initial`, column, missingIdsKey],
|
|
5715
|
+
queryKey: [`idpicker-initial`, column, missingIdsKey, idMapStateKey],
|
|
5683
5716
|
queryFn: async () => {
|
|
5684
5717
|
if (missingIds.length === 0) {
|
|
5685
5718
|
return { data: [], count: 0 };
|
|
5686
5719
|
}
|
|
5687
5720
|
// Use schema's loadInitialValues (required for id-picker)
|
|
5688
|
-
if (!
|
|
5689
|
-
|
|
5721
|
+
if (!loadInitialValues) {
|
|
5722
|
+
console.warn(`loadInitialValues is required in schema for IdPicker field '${column}'. Returning empty idMap.`);
|
|
5723
|
+
return { data: [], count: 0 };
|
|
5690
5724
|
}
|
|
5691
|
-
const result = await
|
|
5725
|
+
const result = await loadInitialValues({
|
|
5692
5726
|
ids: missingIds,
|
|
5693
5727
|
foreign_key: foreign_key,
|
|
5694
5728
|
setIdMap,
|
|
@@ -5696,7 +5730,9 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
|
5696
5730
|
return result.data;
|
|
5697
5731
|
},
|
|
5698
5732
|
enabled: missingIds.length > 0, // Only fetch if there are missing IDs
|
|
5699
|
-
staleTime:
|
|
5733
|
+
staleTime: 0, // Always consider data stale to refetch on remount
|
|
5734
|
+
refetchOnMount: true, // Always refetch when component remounts (e.g., from another page)
|
|
5735
|
+
refetchOnWindowFocus: false, // Don't refetch on window focus
|
|
5700
5736
|
});
|
|
5701
5737
|
const { isLoading: isLoadingInitialValues, isFetching: isFetchingInitialValues, } = initialValuesQuery;
|
|
5702
5738
|
// Query for search results (async loading)
|
|
@@ -5841,7 +5877,7 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
|
5841
5877
|
idPickerLabels,
|
|
5842
5878
|
insideDialog: insideDialog ?? false,
|
|
5843
5879
|
renderDisplay,
|
|
5844
|
-
loadInitialValues:
|
|
5880
|
+
loadInitialValues: loadInitialValues, // Required for id-picker, checked above
|
|
5845
5881
|
column_ref,
|
|
5846
5882
|
errors,
|
|
5847
5883
|
setValue,
|
|
@@ -7767,15 +7803,15 @@ const DateViewer = ({ column, schema, prefix }) => {
|
|
|
7767
7803
|
|
|
7768
7804
|
const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
7769
7805
|
const { watch, formState: { errors }, } = reactHookForm.useFormContext();
|
|
7770
|
-
const formI18n = useFormI18n(column, prefix);
|
|
7806
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7771
7807
|
const { required } = schema;
|
|
7772
7808
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7773
|
-
const { gridColumn =
|
|
7809
|
+
const { gridColumn = 'span 12', gridRow = 'span 1', renderDisplay } = schema;
|
|
7774
7810
|
const colLabel = formI18n.colLabel;
|
|
7775
7811
|
const watchEnum = watch(colLabel);
|
|
7776
7812
|
const watchEnums = (watch(colLabel) ?? []);
|
|
7777
|
-
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems:
|
|
7778
|
-
gridRow, children: [isMultiple && (jsxRuntime.jsx(react.Flex, { flexFlow:
|
|
7813
|
+
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
7814
|
+
gridRow, children: [isMultiple && (jsxRuntime.jsx(react.Flex, { flexFlow: 'wrap', gap: 1, children: watchEnums.map((enumValue) => {
|
|
7779
7815
|
const item = enumValue;
|
|
7780
7816
|
if (item === undefined) {
|
|
7781
7817
|
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: "undefined" });
|
|
@@ -7783,7 +7819,7 @@ const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
|
7783
7819
|
return (jsxRuntime.jsx(Tag, { size: "lg", children: !!renderDisplay === true
|
|
7784
7820
|
? renderDisplay(item)
|
|
7785
7821
|
: formI18n.t(item) }, item));
|
|
7786
|
-
}) })), !isMultiple && jsxRuntime.jsx(react.Text, { children: formI18n.t(watchEnum) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color:
|
|
7822
|
+
}) })), !isMultiple && jsxRuntime.jsx(react.Text, { children: formI18n.t(watchEnum) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
7787
7823
|
};
|
|
7788
7824
|
|
|
7789
7825
|
const FileViewer = ({ column, schema, prefix }) => {
|
|
@@ -8196,6 +8232,17 @@ const FormBody = () => {
|
|
|
8196
8232
|
|
|
8197
8233
|
const FormTitle = () => {
|
|
8198
8234
|
const { schema } = useSchemaContext();
|
|
8235
|
+
// Debug log when form title is missing
|
|
8236
|
+
if (!schema.title) {
|
|
8237
|
+
console.debug('[Form Title] Missing title in root schema. Add title property to schema.', {
|
|
8238
|
+
schema: {
|
|
8239
|
+
type: schema.type,
|
|
8240
|
+
properties: schema.properties
|
|
8241
|
+
? Object.keys(schema.properties)
|
|
8242
|
+
: undefined,
|
|
8243
|
+
},
|
|
8244
|
+
});
|
|
8245
|
+
}
|
|
8199
8246
|
return jsxRuntime.jsx(react.Heading, { children: schema.title ?? 'Form' });
|
|
8200
8247
|
};
|
|
8201
8248
|
|
package/dist/index.mjs
CHANGED
|
@@ -3694,7 +3694,7 @@ const TextWithCopy = ({ text, globalFilter, highlightedText, }) => {
|
|
|
3694
3694
|
const displayText = highlightedText !== undefined
|
|
3695
3695
|
? highlightedText
|
|
3696
3696
|
: highlightText$1(textValue, globalFilter);
|
|
3697
|
-
return (jsxs(HStack, { gap: 2, alignItems: "center", children: [jsx(Text, { as: "span", children: displayText }), jsx(Clipboard.Root, { value: textValue, children: jsx(Clipboard.Trigger, { asChild: true, children: jsx(IconButton, { size: "
|
|
3697
|
+
return (jsxs(HStack, { gap: 2, alignItems: "center", children: [jsx(Text, { as: "span", children: displayText }), jsx(Clipboard.Root, { value: textValue, children: jsx(Clipboard.Trigger, { asChild: true, children: jsx(IconButton, { size: "2xs", variant: "ghost", "aria-label": "Copy", fontSize: "1em", children: jsx(Clipboard.Indicator, { copied: jsx(LuCheck, {}), children: jsx(LuCopy, {}) }) }) }) })] }));
|
|
3698
3698
|
};
|
|
3699
3699
|
|
|
3700
3700
|
// Helper function to highlight matching text
|
|
@@ -4126,6 +4126,22 @@ const convertAjvErrorsToFieldErrors = (errors, schema) => {
|
|
|
4126
4126
|
// Get the schema node for this field to check for custom error messages
|
|
4127
4127
|
const fieldSchema = getSchemaNodeForField(schema, fieldName);
|
|
4128
4128
|
const customMessage = fieldSchema?.errorMessages?.[error.keyword];
|
|
4129
|
+
// Debug log when error message is missing
|
|
4130
|
+
if (!customMessage) {
|
|
4131
|
+
console.debug(`[Form Validation] Missing error message for field '${fieldName}' with keyword '${error.keyword}'. Add errorMessages.${error.keyword} to schema for field '${fieldName}'`, {
|
|
4132
|
+
fieldName,
|
|
4133
|
+
keyword: error.keyword,
|
|
4134
|
+
instancePath: error.instancePath,
|
|
4135
|
+
schemaPath: error.schemaPath,
|
|
4136
|
+
params: error.params,
|
|
4137
|
+
fieldSchema: fieldSchema
|
|
4138
|
+
? {
|
|
4139
|
+
type: fieldSchema.type,
|
|
4140
|
+
errorMessages: fieldSchema.errorMessages,
|
|
4141
|
+
}
|
|
4142
|
+
: undefined,
|
|
4143
|
+
});
|
|
4144
|
+
}
|
|
4129
4145
|
// Provide helpful fallback message if no custom message is provided
|
|
4130
4146
|
const fallbackMessage = customMessage ||
|
|
4131
4147
|
`Missing error message for ${error.keyword}. Add errorMessages.${error.keyword} to schema for field '${fieldName}'`;
|
|
@@ -4368,7 +4384,7 @@ function removeIndex(str) {
|
|
|
4368
4384
|
*
|
|
4369
4385
|
* @param column - The column name
|
|
4370
4386
|
* @param prefix - The prefix for the field (usually empty string or parent path)
|
|
4371
|
-
* @param schema -
|
|
4387
|
+
* @param schema - Required schema object with title property
|
|
4372
4388
|
* @returns Object with label helper functions
|
|
4373
4389
|
*
|
|
4374
4390
|
* @example
|
|
@@ -4401,9 +4417,21 @@ const useFormI18n = (column, prefix = '', schema) => {
|
|
|
4401
4417
|
* Uses schema.title if available, otherwise: translate.t(removeIndex(`${colLabel}.field_label`))
|
|
4402
4418
|
*/
|
|
4403
4419
|
label: (options) => {
|
|
4404
|
-
if (schema
|
|
4420
|
+
if (schema.title) {
|
|
4405
4421
|
return schema.title;
|
|
4406
4422
|
}
|
|
4423
|
+
// Debug log when field title is missing
|
|
4424
|
+
console.debug(`[Form Field Label] Missing title for field '${colLabel}'. Add title property to schema for field '${colLabel}'.`, {
|
|
4425
|
+
fieldName: column,
|
|
4426
|
+
colLabel,
|
|
4427
|
+
prefix,
|
|
4428
|
+
schema: {
|
|
4429
|
+
type: schema.type,
|
|
4430
|
+
errorMessages: schema.errorMessages
|
|
4431
|
+
? Object.keys(schema.errorMessages)
|
|
4432
|
+
: undefined,
|
|
4433
|
+
},
|
|
4434
|
+
});
|
|
4407
4435
|
return translate.t(removeIndex(`${colLabel}.field_label`), options);
|
|
4408
4436
|
},
|
|
4409
4437
|
/**
|
|
@@ -4680,7 +4708,7 @@ dayjs.extend(timezone);
|
|
|
4680
4708
|
const DateRangePicker = ({ column, schema, prefix, }) => {
|
|
4681
4709
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
4682
4710
|
const { timezone, insideDialog } = useSchemaContext();
|
|
4683
|
-
const formI18n = useFormI18n(column, prefix);
|
|
4711
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4684
4712
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
|
|
4685
4713
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4686
4714
|
const colLabel = formI18n.colLabel;
|
|
@@ -5325,7 +5353,7 @@ const MediaLibraryBrowser = ({ onFetchFiles, filterImageOnly = false, labels, en
|
|
|
5325
5353
|
}) })) }))] }));
|
|
5326
5354
|
};
|
|
5327
5355
|
|
|
5328
|
-
function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly = false, onFetchFiles, onUploadFile, enableUpload = false, labels,
|
|
5356
|
+
function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly = false, onFetchFiles, onUploadFile, enableUpload = false, labels, }) {
|
|
5329
5357
|
const [selectedFile, setSelectedFile] = useState(undefined);
|
|
5330
5358
|
const [activeTab, setActiveTab] = useState('browse');
|
|
5331
5359
|
const [uploadingFiles, setUploadingFiles] = useState(new Set());
|
|
@@ -5409,7 +5437,7 @@ function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly =
|
|
|
5409
5437
|
const FilePicker = ({ column, schema, prefix }) => {
|
|
5410
5438
|
const { setValue, formState: { errors }, watch, } = useFormContext();
|
|
5411
5439
|
const { filePickerLabels } = useSchemaContext();
|
|
5412
|
-
const formI18n = useFormI18n(column, prefix);
|
|
5440
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5413
5441
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', type, } = schema;
|
|
5414
5442
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5415
5443
|
const isSingleSelect = type === 'string';
|
|
@@ -5485,7 +5513,7 @@ const FilePicker = ({ column, schema, prefix }) => {
|
|
|
5485
5513
|
const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
5486
5514
|
const { setValue, formState: { errors }, watch, } = useFormContext();
|
|
5487
5515
|
const { filePickerLabels } = useSchemaContext();
|
|
5488
|
-
const formI18n = useFormI18n(column, prefix);
|
|
5516
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5489
5517
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', filePicker, type, } = schema;
|
|
5490
5518
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5491
5519
|
const isSingleSelect = type === 'string';
|
|
@@ -5580,9 +5608,7 @@ const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
|
5580
5608
|
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
5581
5609
|
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [jsx(VStack, { align: "stretch", gap: 2, children: jsx(Button$1, { variant: "outline", onClick: () => setDialogOpen(true), borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: filePickerLabels?.browseLibrary ??
|
|
5582
5610
|
formI18n.t('browse_library') ??
|
|
5583
|
-
'Browse from Library' }) }), jsx(MediaBrowserDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ??
|
|
5584
|
-
filePickerLabels?.dialogTitle ??
|
|
5585
|
-
'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, onUploadFile: onUploadFile, enableUpload: enableUpload, labels: filePickerLabels, colLabel: colLabel }), jsx(Flex, { flexFlow: 'column', gap: 1, children: currentFileIds.map((fileId, index) => {
|
|
5611
|
+
'Browse from Library' }) }), jsx(MediaBrowserDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ?? formI18n.label() ?? 'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, onUploadFile: onUploadFile, enableUpload: enableUpload, labels: filePickerLabels, colLabel: colLabel }), jsx(Flex, { flexFlow: 'column', gap: 1, children: currentFileIds.map((fileId, index) => {
|
|
5586
5612
|
const file = fileMap.get(fileId);
|
|
5587
5613
|
const isImage = file
|
|
5588
5614
|
? /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name)
|
|
@@ -5606,10 +5632,10 @@ const defaultRenderDisplay = (item) => {
|
|
|
5606
5632
|
const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
5607
5633
|
const { watch, getValues, formState: { errors }, setValue, } = useFormContext();
|
|
5608
5634
|
const { idMap, setIdMap, idPickerLabels, insideDialog } = useSchemaContext();
|
|
5609
|
-
const { renderDisplay, loadInitialValues
|
|
5635
|
+
const { renderDisplay, loadInitialValues, foreign_key, variant } = schema;
|
|
5610
5636
|
// loadInitialValues must be provided in schema for id-picker fields
|
|
5611
5637
|
// It's used to load the record of the id so the display is human-readable
|
|
5612
|
-
if (variant === 'id-picker' && !
|
|
5638
|
+
if (variant === 'id-picker' && !loadInitialValues) {
|
|
5613
5639
|
throw new Error(`loadInitialValues is required in schema for IdPicker field '${column}'. Please provide loadInitialValues function in the schema to load records for human-readable display.`);
|
|
5614
5640
|
}
|
|
5615
5641
|
const { table, column: column_ref, customQueryFn, } = foreign_key;
|
|
@@ -5656,19 +5682,27 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
|
5656
5682
|
const missingIdsKey = useMemo(() => {
|
|
5657
5683
|
return JSON.stringify([...missingIds].sort());
|
|
5658
5684
|
}, [missingIds]);
|
|
5685
|
+
// Include idMap state in query key to force refetch when idMap is reset (e.g., on remount from another page)
|
|
5686
|
+
// This ensures the query runs even if React Query has cached data for the same missing IDs
|
|
5687
|
+
const idMapStateKey = useMemo(() => {
|
|
5688
|
+
// Create a key based on whether the required IDs are in idMap
|
|
5689
|
+
const hasRequiredIds = currentValue.every((id) => idMap[id]);
|
|
5690
|
+
return hasRequiredIds ? 'complete' : 'incomplete';
|
|
5691
|
+
}, [currentValue, idMap]);
|
|
5659
5692
|
// Query to fetch initial values that are missing from idMap
|
|
5660
5693
|
// This query runs automatically when missingIds.length > 0 and updates idMap
|
|
5661
5694
|
const initialValuesQuery = useQuery({
|
|
5662
|
-
queryKey: [`idpicker-initial`, column, missingIdsKey],
|
|
5695
|
+
queryKey: [`idpicker-initial`, column, missingIdsKey, idMapStateKey],
|
|
5663
5696
|
queryFn: async () => {
|
|
5664
5697
|
if (missingIds.length === 0) {
|
|
5665
5698
|
return { data: [], count: 0 };
|
|
5666
5699
|
}
|
|
5667
5700
|
// Use schema's loadInitialValues (required for id-picker)
|
|
5668
|
-
if (!
|
|
5669
|
-
|
|
5701
|
+
if (!loadInitialValues) {
|
|
5702
|
+
console.warn(`loadInitialValues is required in schema for IdPicker field '${column}'. Returning empty idMap.`);
|
|
5703
|
+
return { data: [], count: 0 };
|
|
5670
5704
|
}
|
|
5671
|
-
const result = await
|
|
5705
|
+
const result = await loadInitialValues({
|
|
5672
5706
|
ids: missingIds,
|
|
5673
5707
|
foreign_key: foreign_key,
|
|
5674
5708
|
setIdMap,
|
|
@@ -5676,7 +5710,9 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
|
5676
5710
|
return result.data;
|
|
5677
5711
|
},
|
|
5678
5712
|
enabled: missingIds.length > 0, // Only fetch if there are missing IDs
|
|
5679
|
-
staleTime:
|
|
5713
|
+
staleTime: 0, // Always consider data stale to refetch on remount
|
|
5714
|
+
refetchOnMount: true, // Always refetch when component remounts (e.g., from another page)
|
|
5715
|
+
refetchOnWindowFocus: false, // Don't refetch on window focus
|
|
5680
5716
|
});
|
|
5681
5717
|
const { isLoading: isLoadingInitialValues, isFetching: isFetchingInitialValues, } = initialValuesQuery;
|
|
5682
5718
|
// Query for search results (async loading)
|
|
@@ -5821,7 +5857,7 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
|
5821
5857
|
idPickerLabels,
|
|
5822
5858
|
insideDialog: insideDialog ?? false,
|
|
5823
5859
|
renderDisplay,
|
|
5824
|
-
loadInitialValues:
|
|
5860
|
+
loadInitialValues: loadInitialValues, // Required for id-picker, checked above
|
|
5825
5861
|
column_ref,
|
|
5826
5862
|
errors,
|
|
5827
5863
|
setValue,
|
|
@@ -7747,15 +7783,15 @@ const DateViewer = ({ column, schema, prefix }) => {
|
|
|
7747
7783
|
|
|
7748
7784
|
const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
7749
7785
|
const { watch, formState: { errors }, } = useFormContext();
|
|
7750
|
-
const formI18n = useFormI18n(column, prefix);
|
|
7786
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7751
7787
|
const { required } = schema;
|
|
7752
7788
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7753
|
-
const { gridColumn =
|
|
7789
|
+
const { gridColumn = 'span 12', gridRow = 'span 1', renderDisplay } = schema;
|
|
7754
7790
|
const colLabel = formI18n.colLabel;
|
|
7755
7791
|
const watchEnum = watch(colLabel);
|
|
7756
7792
|
const watchEnums = (watch(colLabel) ?? []);
|
|
7757
|
-
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems:
|
|
7758
|
-
gridRow, children: [isMultiple && (jsx(Flex, { flexFlow:
|
|
7793
|
+
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
7794
|
+
gridRow, children: [isMultiple && (jsx(Flex, { flexFlow: 'wrap', gap: 1, children: watchEnums.map((enumValue) => {
|
|
7759
7795
|
const item = enumValue;
|
|
7760
7796
|
if (item === undefined) {
|
|
7761
7797
|
return jsx(Fragment, { children: "undefined" });
|
|
@@ -7763,7 +7799,7 @@ const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
|
7763
7799
|
return (jsx(Tag, { size: "lg", children: !!renderDisplay === true
|
|
7764
7800
|
? renderDisplay(item)
|
|
7765
7801
|
: formI18n.t(item) }, item));
|
|
7766
|
-
}) })), !isMultiple && jsx(Text, { children: formI18n.t(watchEnum) }), errors[`${column}`] && (jsx(Text, { color:
|
|
7802
|
+
}) })), !isMultiple && jsx(Text, { children: formI18n.t(watchEnum) }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
7767
7803
|
};
|
|
7768
7804
|
|
|
7769
7805
|
const FileViewer = ({ column, schema, prefix }) => {
|
|
@@ -8176,6 +8212,17 @@ const FormBody = () => {
|
|
|
8176
8212
|
|
|
8177
8213
|
const FormTitle = () => {
|
|
8178
8214
|
const { schema } = useSchemaContext();
|
|
8215
|
+
// Debug log when form title is missing
|
|
8216
|
+
if (!schema.title) {
|
|
8217
|
+
console.debug('[Form Title] Missing title in root schema. Add title property to schema.', {
|
|
8218
|
+
schema: {
|
|
8219
|
+
type: schema.type,
|
|
8220
|
+
properties: schema.properties
|
|
8221
|
+
? Object.keys(schema.properties)
|
|
8222
|
+
: undefined,
|
|
8223
|
+
},
|
|
8224
|
+
});
|
|
8225
|
+
}
|
|
8179
8226
|
return jsx(Heading, { children: schema.title ?? 'Form' });
|
|
8180
8227
|
};
|
|
8181
8228
|
|
|
@@ -12,6 +12,6 @@ interface MediaBrowserDialogProps {
|
|
|
12
12
|
labels?: FilePickerLabels;
|
|
13
13
|
colLabel: string;
|
|
14
14
|
}
|
|
15
|
-
export declare function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly, onFetchFiles, onUploadFile, enableUpload, labels,
|
|
15
|
+
export declare function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly, onFetchFiles, onUploadFile, enableUpload, labels, }: MediaBrowserDialogProps): import("react/jsx-runtime").JSX.Element | null;
|
|
16
16
|
export declare const FilePicker: ({ column, schema, prefix }: InputDefaultProps) => import("react/jsx-runtime").JSX.Element;
|
|
17
17
|
export {};
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @param column - The column name
|
|
7
7
|
* @param prefix - The prefix for the field (usually empty string or parent path)
|
|
8
|
-
* @param schema -
|
|
8
|
+
* @param schema - Required schema object with title property
|
|
9
9
|
* @returns Object with label helper functions
|
|
10
10
|
*
|
|
11
11
|
* @example
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* const colLabel = formI18n.colLabel;
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
|
-
export declare const useFormI18n: (column: string, prefix
|
|
28
|
+
export declare const useFormI18n: (column: string, prefix: string | undefined, schema: {
|
|
29
29
|
title?: string;
|
|
30
30
|
}) => {
|
|
31
31
|
/**
|