@bsol-oss/react-datatable5 12.0.0-beta.71 → 12.0.0-beta.72
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.d.ts +254 -14
- package/dist/index.js +262 -48
- package/dist/index.mjs +259 -49
- package/dist/types/components/Form/SchemaFormContext.d.ts +9 -5
- package/dist/types/components/Form/components/core/FormBody.d.ts +2 -1
- package/dist/types/components/Form/components/core/FormRoot.d.ts +11 -8
- package/dist/types/components/Form/components/fields/IdPicker.d.ts +1 -1
- package/dist/types/components/Form/components/types/CustomJSONSchema7.d.ts +20 -4
- package/dist/types/components/Form/useForm.d.ts +3 -2
- package/dist/types/components/Form/utils/buildErrorMessages.d.ts +219 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +10 -2
package/dist/index.js
CHANGED
|
@@ -3677,8 +3677,8 @@ const AccordionItem = react.Accordion.Item;
|
|
|
3677
3677
|
//@ts-expect-error TODO: find appropriate type
|
|
3678
3678
|
const SchemaFormContext = React.createContext({
|
|
3679
3679
|
schema: {},
|
|
3680
|
-
serverUrl:
|
|
3681
|
-
requestUrl:
|
|
3680
|
+
serverUrl: '',
|
|
3681
|
+
requestUrl: '',
|
|
3682
3682
|
order: [],
|
|
3683
3683
|
ignore: [],
|
|
3684
3684
|
include: [],
|
|
@@ -3734,11 +3734,11 @@ const idPickerSanityCheck = (column, foreign_key) => {
|
|
|
3734
3734
|
throw new Error(`The key column does not exist in properties of column ${column} when using id-picker.`);
|
|
3735
3735
|
}
|
|
3736
3736
|
};
|
|
3737
|
-
const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, displayConfig = {
|
|
3737
|
+
const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, customSuccessRenderer, displayConfig = {
|
|
3738
3738
|
showSubmitButton: true,
|
|
3739
3739
|
showResetButton: true,
|
|
3740
3740
|
showTitle: true,
|
|
3741
|
-
}, }) => {
|
|
3741
|
+
}, dateTimePickerLabels, idPickerLabels, }) => {
|
|
3742
3742
|
const [isSuccess, setIsSuccess] = React.useState(false);
|
|
3743
3743
|
const [isError, setIsError] = React.useState(false);
|
|
3744
3744
|
const [isSubmiting, setIsSubmiting] = React.useState(false);
|
|
@@ -3772,7 +3772,10 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
3772
3772
|
setError,
|
|
3773
3773
|
getUpdatedData,
|
|
3774
3774
|
customErrorRenderer,
|
|
3775
|
+
customSuccessRenderer,
|
|
3775
3776
|
displayConfig,
|
|
3777
|
+
dateTimePickerLabels,
|
|
3778
|
+
idPickerLabels,
|
|
3776
3779
|
}, children: jsxRuntime.jsx(reactHookForm.FormProvider, { ...form, children: children }) }));
|
|
3777
3780
|
};
|
|
3778
3781
|
|
|
@@ -4615,12 +4618,12 @@ const getTableData = async ({ serverUrl, in_table, searching = "", where = [], l
|
|
|
4615
4618
|
|
|
4616
4619
|
const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
4617
4620
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
4618
|
-
const { serverUrl, idMap, setIdMap, schema: parentSchema, } = useSchemaContext();
|
|
4621
|
+
const { serverUrl, idMap, setIdMap, schema: parentSchema, idPickerLabels, } = useSchemaContext();
|
|
4619
4622
|
const formI18n = useFormI18n(column, prefix);
|
|
4620
|
-
const { required, gridColumn =
|
|
4623
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, foreign_key, } = schema;
|
|
4621
4624
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4622
4625
|
const { table, column: column_ref, display_column, customQueryFn, } = foreign_key;
|
|
4623
|
-
const [searchText, setSearchText] = React.useState(
|
|
4626
|
+
const [searchText, setSearchText] = React.useState('');
|
|
4624
4627
|
const [limit, setLimit] = React.useState(10);
|
|
4625
4628
|
const [openSearchResult, setOpenSearchResult] = React.useState();
|
|
4626
4629
|
const [page, setPage] = React.useState(0);
|
|
@@ -4634,7 +4637,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4634
4637
|
queryFn: async () => {
|
|
4635
4638
|
if (customQueryFn) {
|
|
4636
4639
|
const { data, idMap } = await customQueryFn({
|
|
4637
|
-
searching: searchText ??
|
|
4640
|
+
searching: searchText ?? '',
|
|
4638
4641
|
limit: limit,
|
|
4639
4642
|
offset: page * limit,
|
|
4640
4643
|
});
|
|
@@ -4645,7 +4648,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4645
4648
|
}
|
|
4646
4649
|
const data = await getTableData({
|
|
4647
4650
|
serverUrl,
|
|
4648
|
-
searching: searchText ??
|
|
4651
|
+
searching: searchText ?? '',
|
|
4649
4652
|
in_table: table,
|
|
4650
4653
|
limit: limit,
|
|
4651
4654
|
offset: page * limit,
|
|
@@ -4675,7 +4678,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4675
4678
|
queryFn: async () => {
|
|
4676
4679
|
if (customQueryFn) {
|
|
4677
4680
|
const { data, idMap } = await customQueryFn({
|
|
4678
|
-
searching: watchIds.join(
|
|
4681
|
+
searching: watchIds.join(','),
|
|
4679
4682
|
limit: isMultiple ? watchIds.length : 1,
|
|
4680
4683
|
offset: 0,
|
|
4681
4684
|
});
|
|
@@ -4687,7 +4690,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4687
4690
|
if (!watchId && (!watchIds || watchIds.length === 0)) {
|
|
4688
4691
|
return { data: [] };
|
|
4689
4692
|
}
|
|
4690
|
-
const searchValue = isMultiple ? watchIds.join(
|
|
4693
|
+
const searchValue = isMultiple ? watchIds.join(',') : watchId;
|
|
4691
4694
|
const data = await getTableData({
|
|
4692
4695
|
serverUrl,
|
|
4693
4696
|
searching: searchValue,
|
|
@@ -4724,7 +4727,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4724
4727
|
React.useEffect(() => {
|
|
4725
4728
|
if (openSearchResult) {
|
|
4726
4729
|
// Reset search text when opening the popover
|
|
4727
|
-
setSearchText(
|
|
4730
|
+
setSearchText('');
|
|
4728
4731
|
// Reset page to first page
|
|
4729
4732
|
setPage(0);
|
|
4730
4733
|
// Fetch initial data
|
|
@@ -4750,44 +4753,44 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4750
4753
|
const count = data?.count ?? 0;
|
|
4751
4754
|
const getPickedValue = () => {
|
|
4752
4755
|
if (Object.keys(idMap).length <= 0) {
|
|
4753
|
-
return
|
|
4756
|
+
return '';
|
|
4754
4757
|
}
|
|
4755
4758
|
const record = idMap[watchId];
|
|
4756
4759
|
if (record === undefined) {
|
|
4757
|
-
return
|
|
4760
|
+
return '';
|
|
4758
4761
|
}
|
|
4759
4762
|
if (!!renderDisplay === true) {
|
|
4760
4763
|
return renderDisplay(record);
|
|
4761
4764
|
}
|
|
4762
4765
|
return record[display_column];
|
|
4763
4766
|
};
|
|
4764
|
-
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems:
|
|
4765
|
-
gridRow, children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow:
|
|
4767
|
+
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4768
|
+
gridRow, children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow: 'wrap', gap: 1, children: [watchIds.map((id) => {
|
|
4766
4769
|
const item = idMap[id];
|
|
4767
4770
|
if (item === undefined) {
|
|
4768
|
-
return (jsxRuntime.jsx(react.Text, { children: formI18n.t('undefined') }, id));
|
|
4771
|
+
return (jsxRuntime.jsx(react.Text, { children: idPickerLabels?.undefined ?? formI18n.t('undefined') }, id));
|
|
4769
4772
|
}
|
|
4770
4773
|
return (jsxRuntime.jsx(Tag, { closable: true, onClick: () => {
|
|
4771
4774
|
setValue(colLabel, watchIds.filter((itemId) => itemId !== item[column_ref]));
|
|
4772
4775
|
}, children: !!renderDisplay === true
|
|
4773
4776
|
? renderDisplay(item)
|
|
4774
4777
|
: item[display_column] }, id));
|
|
4775
|
-
}), jsxRuntime.jsx(Tag, { cursor:
|
|
4778
|
+
}), jsxRuntime.jsx(Tag, { cursor: 'pointer', onClick: () => {
|
|
4776
4779
|
setOpenSearchResult(true);
|
|
4777
|
-
}, children: formI18n.t('add_more') })] })), !isMultiple && (jsxRuntime.jsx(Button, { variant:
|
|
4780
|
+
}, children: idPickerLabels?.addMore ?? formI18n.t('add_more') })] })), !isMultiple && (jsxRuntime.jsx(Button, { variant: 'outline', onClick: () => {
|
|
4778
4781
|
setOpenSearchResult(true);
|
|
4779
|
-
}, justifyContent:
|
|
4782
|
+
}, justifyContent: 'start', children: queryDefault.isLoading ? jsxRuntime.jsx(react.Spinner, { size: "sm" }) : getPickedValue() })), jsxRuntime.jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: 'bottom-start', strategy: 'fixed' }, children: [jsxRuntime.jsx(PopoverTrigger, {}), jsxRuntime.jsx(PopoverContent, { portalled: false, children: jsxRuntime.jsxs(PopoverBody, { display: 'grid', gap: 1, children: [jsxRuntime.jsx(react.Input, { placeholder: idPickerLabels?.typeToSearch ?? formI18n.t('type_to_search'), onChange: onSearchChange, autoComplete: "off", ref: ref, value: searchText }), jsxRuntime.jsx(PopoverTitle, {}), openSearchResult && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [(isFetching || isLoading || isPending) && jsxRuntime.jsx(react.Spinner, {}), isError && (jsxRuntime.jsx(react.Icon, { color: 'red.400', children: jsxRuntime.jsx(bi.BiError, {}) })), jsxRuntime.jsxs(react.Flex, { justifyContent: "space-between", alignItems: "center", children: [jsxRuntime.jsxs(react.Flex, { alignItems: "center", gap: "2", children: [jsxRuntime.jsx(InfoTip, { children: `${idPickerLabels?.total ?? formI18n.t('total')} ${count}, ${idPickerLabels?.showing ?? formI18n.t('showing')} ${limit} ${idPickerLabels?.perPage ?? formI18n.t('per_page', { defaultValue: 'per page' })}` }), jsxRuntime.jsxs(react.Text, { fontSize: "sm", fontWeight: "bold", children: [count, jsxRuntime.jsxs(react.Text, { as: "span", fontSize: "xs", ml: "1", color: "gray.500", children: ["/", ' ', count > 0
|
|
4780
4783
|
? `${page * limit + 1}-${Math.min((page + 1) * limit, count)}`
|
|
4781
|
-
:
|
|
4782
|
-
padding:
|
|
4783
|
-
borderRadius:
|
|
4784
|
-
border:
|
|
4785
|
-
fontSize:
|
|
4786
|
-
}, children: [jsxRuntime.jsx("option", { value: "5", children: "5" }), jsxRuntime.jsx("option", { value: "10", children: "10" }), jsxRuntime.jsx("option", { value: "20", children: "20" }), jsxRuntime.jsx("option", { value: "30", children: "30" })] }) })] }), jsxRuntime.jsx(react.Grid, { overflowY:
|
|
4784
|
+
: '0'] })] })] }), jsxRuntime.jsx(react.Box, { children: jsxRuntime.jsxs("select", { value: limit, onChange: handleLimitChange, style: {
|
|
4785
|
+
padding: '4px 8px',
|
|
4786
|
+
borderRadius: '4px',
|
|
4787
|
+
border: '1px solid #ccc',
|
|
4788
|
+
fontSize: '14px',
|
|
4789
|
+
}, children: [jsxRuntime.jsx("option", { value: "5", children: "5" }), jsxRuntime.jsx("option", { value: "10", children: "10" }), jsxRuntime.jsx("option", { value: "20", children: "20" }), jsxRuntime.jsx("option", { value: "30", children: "30" })] }) })] }), jsxRuntime.jsx(react.Grid, { overflowY: 'auto', children: dataList.length > 0 ? (jsxRuntime.jsx(react.Flex, { flexFlow: 'column wrap', gap: 1, children: dataList.map((item) => {
|
|
4787
4790
|
const selected = isMultiple
|
|
4788
4791
|
? watchIds.some((id) => item[column_ref] === id)
|
|
4789
4792
|
: watchId === item[column_ref];
|
|
4790
|
-
return (jsxRuntime.jsx(react.Box, { cursor:
|
|
4793
|
+
return (jsxRuntime.jsx(react.Box, { cursor: 'pointer', onClick: () => {
|
|
4791
4794
|
if (!isMultiple) {
|
|
4792
4795
|
setOpenSearchResult(false);
|
|
4793
4796
|
setValue(colLabel, item[column_ref]);
|
|
@@ -4803,15 +4806,17 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4803
4806
|
setValue(colLabel, [...newSet]);
|
|
4804
4807
|
}, opacity: 0.7, _hover: { opacity: 1 }, ...(selected
|
|
4805
4808
|
? {
|
|
4806
|
-
color:
|
|
4807
|
-
fontWeight:
|
|
4809
|
+
color: 'colorPalette.400/50',
|
|
4810
|
+
fontWeight: 'bold',
|
|
4808
4811
|
}
|
|
4809
4812
|
: {}), children: !!renderDisplay === true
|
|
4810
4813
|
? renderDisplay(item)
|
|
4811
4814
|
: item[display_column] }, item[column_ref]));
|
|
4812
4815
|
}) })) : (jsxRuntime.jsx(react.Text, { children: searchText
|
|
4813
|
-
?
|
|
4814
|
-
|
|
4816
|
+
? idPickerLabels?.emptySearchResult ??
|
|
4817
|
+
formI18n.t('empty_search_result')
|
|
4818
|
+
: idPickerLabels?.initialResults ??
|
|
4819
|
+
formI18n.t('initial_results') })) }), jsxRuntime.jsx(PaginationRoot, { justifySelf: 'center', count: count, pageSize: limit, defaultPage: 1, page: page + 1, onPageChange: (e) => setPage(e.page - 1), children: jsxRuntime.jsxs(react.HStack, { gap: "4", children: [jsxRuntime.jsx(PaginationPrevTrigger, {}), count > 0 && jsxRuntime.jsx(PaginationPageText, {}), jsxRuntime.jsx(PaginationNextTrigger, {})] }) })] }))] }) })] }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
4815
4820
|
};
|
|
4816
4821
|
|
|
4817
4822
|
const NumberInputRoot = React__namespace.forwardRef(function NumberInput(props, ref) {
|
|
@@ -5498,7 +5503,7 @@ dayjs.extend(utc);
|
|
|
5498
5503
|
dayjs.extend(timezone);
|
|
5499
5504
|
const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
5500
5505
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
5501
|
-
const { timezone } = useSchemaContext();
|
|
5506
|
+
const { timezone, dateTimePickerLabels } = useSchemaContext();
|
|
5502
5507
|
const formI18n = useFormI18n(column, prefix);
|
|
5503
5508
|
const { required, gridColumn = "span 12", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD HH:mm:ss",
|
|
5504
5509
|
// with timezone
|
|
@@ -5539,7 +5544,7 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
5539
5544
|
}, justifyContent: "start", children: [jsxRuntime.jsx(md.MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ""] }) }), jsxRuntime.jsx(PopoverContent, { minW: "450px", children: jsxRuntime.jsxs(PopoverBody, { children: [jsxRuntime.jsx(PopoverTitle, {}), jsxRuntime.jsx(DateTimePicker$1, { value: selectedDate, onChange: (date) => {
|
|
5540
5545
|
setValue(colLabel, dayjs(date).tz(timezone).format(dateFormat));
|
|
5541
5546
|
}, timezone: timezone, labels: {
|
|
5542
|
-
monthNamesShort: [
|
|
5547
|
+
monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
|
|
5543
5548
|
formI18n.translate.t(`common.month_1`, { defaultValue: "January" }),
|
|
5544
5549
|
formI18n.translate.t(`common.month_2`, { defaultValue: "February" }),
|
|
5545
5550
|
formI18n.translate.t(`common.month_3`, { defaultValue: "March" }),
|
|
@@ -5553,7 +5558,7 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
5553
5558
|
formI18n.translate.t(`common.month_11`, { defaultValue: "November" }),
|
|
5554
5559
|
formI18n.translate.t(`common.month_12`, { defaultValue: "December" }),
|
|
5555
5560
|
],
|
|
5556
|
-
weekdayNamesShort: [
|
|
5561
|
+
weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
|
|
5557
5562
|
formI18n.translate.t(`common.weekday_1`, { defaultValue: "Sun" }),
|
|
5558
5563
|
formI18n.translate.t(`common.weekday_2`, { defaultValue: "Mon" }),
|
|
5559
5564
|
formI18n.translate.t(`common.weekday_3`, { defaultValue: "Tue" }),
|
|
@@ -5564,10 +5569,10 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
5564
5569
|
formI18n.translate.t(`common.weekday_6`, { defaultValue: "Fri" }),
|
|
5565
5570
|
formI18n.translate.t(`common.weekday_7`, { defaultValue: "Sat" }),
|
|
5566
5571
|
],
|
|
5567
|
-
backButtonLabel: formI18n.translate.t(`common.back_button`, {
|
|
5572
|
+
backButtonLabel: dateTimePickerLabels?.backButtonLabel ?? formI18n.translate.t(`common.back_button`, {
|
|
5568
5573
|
defaultValue: "Back",
|
|
5569
5574
|
}),
|
|
5570
|
-
forwardButtonLabel: formI18n.translate.t(`common.forward_button`, {
|
|
5575
|
+
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ?? formI18n.translate.t(`common.forward_button`, {
|
|
5571
5576
|
defaultValue: "Forward",
|
|
5572
5577
|
}),
|
|
5573
5578
|
} })] }) })] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: formI18n.required() }))] }));
|
|
@@ -6093,7 +6098,7 @@ const SubmitButton = () => {
|
|
|
6093
6098
|
};
|
|
6094
6099
|
|
|
6095
6100
|
const FormBody = () => {
|
|
6096
|
-
const { schema, requestUrl, order, ignore, include, onSubmit, translate, requestOptions, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, setError, getUpdatedData, customErrorRenderer, displayConfig, } = useSchemaContext();
|
|
6101
|
+
const { schema, requestUrl, order, ignore, include, onSubmit, translate, requestOptions, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, setError, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, } = useSchemaContext();
|
|
6097
6102
|
const { showSubmitButton, showResetButton } = displayConfig;
|
|
6098
6103
|
const methods = reactHookForm.useFormContext();
|
|
6099
6104
|
const { properties } = schema;
|
|
@@ -6190,15 +6195,19 @@ const FormBody = () => {
|
|
|
6190
6195
|
include,
|
|
6191
6196
|
});
|
|
6192
6197
|
if (isSuccess) {
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6198
|
+
const resetHandler = async () => {
|
|
6199
|
+
setIsError(false);
|
|
6200
|
+
setIsSubmiting(false);
|
|
6201
|
+
setIsSuccess(false);
|
|
6202
|
+
setIsConfirming(false);
|
|
6203
|
+
setValidatedData(undefined);
|
|
6204
|
+
const data = await getUpdatedData();
|
|
6205
|
+
methods.reset(data);
|
|
6206
|
+
};
|
|
6207
|
+
if (customSuccessRenderer) {
|
|
6208
|
+
return customSuccessRenderer(resetHandler);
|
|
6209
|
+
}
|
|
6210
|
+
return (jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: "2", children: [jsxRuntime.jsxs(react.Alert.Root, { status: "success", children: [jsxRuntime.jsx(react.Alert.Indicator, {}), jsxRuntime.jsx(react.Alert.Content, { children: jsxRuntime.jsx(react.Alert.Title, { children: translate.t("submit_success") }) })] }), jsxRuntime.jsx(react.Flex, { justifyContent: "end", children: jsxRuntime.jsx(react.Button, { onClick: resetHandler, formNoValidate: true, children: translate.t("submit_again") }) })] }));
|
|
6202
6211
|
}
|
|
6203
6212
|
if (isConfirming) {
|
|
6204
6213
|
return (jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: "2", children: [jsxRuntime.jsx(react.Grid, { gap: 4, gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: "repeat(12, max-content)", autoFlow: "row", children: ordered.map((column) => {
|
|
@@ -6236,12 +6245,12 @@ const DefaultForm = ({ formConfig, }) => {
|
|
|
6236
6245
|
return (jsxRuntime.jsx(FormRoot, { ...formConfig, children: jsxRuntime.jsxs(react.Grid, { gap: "2", children: [showTitle && jsxRuntime.jsx(FormTitle, {}), jsxRuntime.jsx(FormBody, {})] }) }));
|
|
6237
6246
|
};
|
|
6238
6247
|
|
|
6239
|
-
const useForm = ({ preLoadedValues, keyPrefix }) => {
|
|
6248
|
+
const useForm = ({ preLoadedValues, keyPrefix, namespace }) => {
|
|
6240
6249
|
const form = reactHookForm.useForm({
|
|
6241
6250
|
values: preLoadedValues,
|
|
6242
6251
|
});
|
|
6243
6252
|
const [idMap, setIdMap] = React.useState({});
|
|
6244
|
-
const translate = reactI18next.useTranslation("", { keyPrefix });
|
|
6253
|
+
const translate = reactI18next.useTranslation(namespace || "", { keyPrefix });
|
|
6245
6254
|
return {
|
|
6246
6255
|
form,
|
|
6247
6256
|
idMap,
|
|
@@ -6250,6 +6259,207 @@ const useForm = ({ preLoadedValues, keyPrefix }) => {
|
|
|
6250
6259
|
};
|
|
6251
6260
|
};
|
|
6252
6261
|
|
|
6262
|
+
/**
|
|
6263
|
+
* Type definitions for error message configuration
|
|
6264
|
+
*/
|
|
6265
|
+
/**
|
|
6266
|
+
* Schema-level error message builder
|
|
6267
|
+
*
|
|
6268
|
+
* Builds a complete errorMessage object compatible with ajv-errors plugin.
|
|
6269
|
+
* Supports both i18n translation keys and plain string messages.
|
|
6270
|
+
*
|
|
6271
|
+
* @param config - Error message configuration
|
|
6272
|
+
* @returns Complete errorMessage object for JSON Schema
|
|
6273
|
+
*
|
|
6274
|
+
* @example
|
|
6275
|
+
* ```typescript
|
|
6276
|
+
* // Simple required field errors
|
|
6277
|
+
* const errorMessage = buildErrorMessages({
|
|
6278
|
+
* required: {
|
|
6279
|
+
* username: "Username is required",
|
|
6280
|
+
* email: "user.email.field_required" // i18n key
|
|
6281
|
+
* }
|
|
6282
|
+
* });
|
|
6283
|
+
*
|
|
6284
|
+
* // With validation rules
|
|
6285
|
+
* const errorMessage = buildErrorMessages({
|
|
6286
|
+
* required: {
|
|
6287
|
+
* password: "Password is required"
|
|
6288
|
+
* },
|
|
6289
|
+
* properties: {
|
|
6290
|
+
* password: {
|
|
6291
|
+
* minLength: "Password must be at least 8 characters",
|
|
6292
|
+
* pattern: "Password must contain letters and numbers"
|
|
6293
|
+
* },
|
|
6294
|
+
* age: {
|
|
6295
|
+
* minimum: "Must be 18 or older",
|
|
6296
|
+
* maximum: "Must be under 120"
|
|
6297
|
+
* }
|
|
6298
|
+
* }
|
|
6299
|
+
* });
|
|
6300
|
+
*
|
|
6301
|
+
* // With global fallbacks
|
|
6302
|
+
* const errorMessage = buildErrorMessages({
|
|
6303
|
+
* required: {
|
|
6304
|
+
* email: "Email is required"
|
|
6305
|
+
* },
|
|
6306
|
+
* minLength: "This field is too short", // applies to all fields
|
|
6307
|
+
* minimum: "Value is too small"
|
|
6308
|
+
* });
|
|
6309
|
+
* ```
|
|
6310
|
+
*/
|
|
6311
|
+
const buildErrorMessages = (config) => {
|
|
6312
|
+
const result = {};
|
|
6313
|
+
// Add required field errors
|
|
6314
|
+
if (config.required && Object.keys(config.required).length > 0) {
|
|
6315
|
+
result.required = config.required;
|
|
6316
|
+
}
|
|
6317
|
+
// Add field-specific validation errors
|
|
6318
|
+
if (config.properties && Object.keys(config.properties).length > 0) {
|
|
6319
|
+
result.properties = config.properties;
|
|
6320
|
+
}
|
|
6321
|
+
// Add global fallback error messages
|
|
6322
|
+
const globalKeys = [
|
|
6323
|
+
"minLength",
|
|
6324
|
+
"maxLength",
|
|
6325
|
+
"pattern",
|
|
6326
|
+
"minimum",
|
|
6327
|
+
"maximum",
|
|
6328
|
+
"multipleOf",
|
|
6329
|
+
"format",
|
|
6330
|
+
"type",
|
|
6331
|
+
"enum",
|
|
6332
|
+
];
|
|
6333
|
+
globalKeys.forEach((key) => {
|
|
6334
|
+
if (config[key]) {
|
|
6335
|
+
result[key] = config[key];
|
|
6336
|
+
}
|
|
6337
|
+
});
|
|
6338
|
+
return result;
|
|
6339
|
+
};
|
|
6340
|
+
/**
|
|
6341
|
+
* Helper function to build required field errors
|
|
6342
|
+
*
|
|
6343
|
+
* Simplifies creating required field error messages, especially useful
|
|
6344
|
+
* for generating i18n translation keys following a pattern.
|
|
6345
|
+
*
|
|
6346
|
+
* @param fields - Array of required field names
|
|
6347
|
+
* @param messageOrGenerator - Either a string template or function to generate messages
|
|
6348
|
+
* @returns Required field error configuration
|
|
6349
|
+
*
|
|
6350
|
+
* @example
|
|
6351
|
+
* ```typescript
|
|
6352
|
+
* // Plain string messages
|
|
6353
|
+
* const required = buildRequiredErrors(
|
|
6354
|
+
* ["username", "email", "password"],
|
|
6355
|
+
* (field) => `${field} is required`
|
|
6356
|
+
* );
|
|
6357
|
+
* // Result: { username: "username is required", email: "email is required", ... }
|
|
6358
|
+
*
|
|
6359
|
+
* // i18n translation keys
|
|
6360
|
+
* const required = buildRequiredErrors(
|
|
6361
|
+
* ["username", "email"],
|
|
6362
|
+
* (field) => `user.${field}.field_required`
|
|
6363
|
+
* );
|
|
6364
|
+
* // Result: { username: "user.username.field_required", email: "user.email.field_required" }
|
|
6365
|
+
*
|
|
6366
|
+
* // Same message for all fields
|
|
6367
|
+
* const required = buildRequiredErrors(
|
|
6368
|
+
* ["username", "email"],
|
|
6369
|
+
* "This field is required"
|
|
6370
|
+
* );
|
|
6371
|
+
* // Result: { username: "This field is required", email: "This field is required" }
|
|
6372
|
+
*
|
|
6373
|
+
* // With keyPrefix for i18n
|
|
6374
|
+
* const required = buildRequiredErrors(
|
|
6375
|
+
* ["username", "email"],
|
|
6376
|
+
* (field) => `${field}.field_required`,
|
|
6377
|
+
* "user"
|
|
6378
|
+
* );
|
|
6379
|
+
* // Result: { username: "user.username.field_required", email: "user.email.field_required" }
|
|
6380
|
+
* ```
|
|
6381
|
+
*/
|
|
6382
|
+
const buildRequiredErrors = (fields, messageOrGenerator, keyPrefix = "") => {
|
|
6383
|
+
const result = {};
|
|
6384
|
+
fields.forEach((field) => {
|
|
6385
|
+
if (typeof messageOrGenerator === "function") {
|
|
6386
|
+
const message = messageOrGenerator(field);
|
|
6387
|
+
result[field] = keyPrefix ? `${keyPrefix}.${message}` : message;
|
|
6388
|
+
}
|
|
6389
|
+
else {
|
|
6390
|
+
result[field] = messageOrGenerator;
|
|
6391
|
+
}
|
|
6392
|
+
});
|
|
6393
|
+
return result;
|
|
6394
|
+
};
|
|
6395
|
+
/**
|
|
6396
|
+
* Helper function to build field-specific validation errors
|
|
6397
|
+
*
|
|
6398
|
+
* Creates property-specific error messages for multiple fields at once.
|
|
6399
|
+
*
|
|
6400
|
+
* @param config - Maps field names to their validation error configurations
|
|
6401
|
+
* @returns Properties error configuration
|
|
6402
|
+
*
|
|
6403
|
+
* @example
|
|
6404
|
+
* ```typescript
|
|
6405
|
+
* const properties = buildFieldErrors({
|
|
6406
|
+
* username: {
|
|
6407
|
+
* minLength: "Username must be at least 3 characters",
|
|
6408
|
+
* pattern: "Username can only contain letters and numbers"
|
|
6409
|
+
* },
|
|
6410
|
+
* age: {
|
|
6411
|
+
* minimum: "Must be 18 or older",
|
|
6412
|
+
* maximum: "Must be under 120"
|
|
6413
|
+
* },
|
|
6414
|
+
* email: {
|
|
6415
|
+
* format: "Please enter a valid email address"
|
|
6416
|
+
* }
|
|
6417
|
+
* });
|
|
6418
|
+
* ```
|
|
6419
|
+
*/
|
|
6420
|
+
const buildFieldErrors = (config) => {
|
|
6421
|
+
return config;
|
|
6422
|
+
};
|
|
6423
|
+
/**
|
|
6424
|
+
* Helper function to create a complete error message configuration in one call
|
|
6425
|
+
*
|
|
6426
|
+
* Convenient wrapper that combines required and validation errors.
|
|
6427
|
+
*
|
|
6428
|
+
* @param required - Required field error messages
|
|
6429
|
+
* @param properties - Field-specific validation error messages
|
|
6430
|
+
* @param globalFallbacks - Global fallback error messages
|
|
6431
|
+
* @returns Complete error message configuration
|
|
6432
|
+
*
|
|
6433
|
+
* @example
|
|
6434
|
+
* ```typescript
|
|
6435
|
+
* const errorMessage = createErrorMessage(
|
|
6436
|
+
* {
|
|
6437
|
+
* username: "Username is required",
|
|
6438
|
+
* email: "Email is required"
|
|
6439
|
+
* },
|
|
6440
|
+
* {
|
|
6441
|
+
* username: {
|
|
6442
|
+
* minLength: "Username must be at least 3 characters"
|
|
6443
|
+
* },
|
|
6444
|
+
* email: {
|
|
6445
|
+
* format: "Please enter a valid email"
|
|
6446
|
+
* }
|
|
6447
|
+
* },
|
|
6448
|
+
* {
|
|
6449
|
+
* minLength: "This field is too short",
|
|
6450
|
+
* format: "Invalid format"
|
|
6451
|
+
* }
|
|
6452
|
+
* );
|
|
6453
|
+
* ```
|
|
6454
|
+
*/
|
|
6455
|
+
const createErrorMessage = (required, properties, globalFallbacks) => {
|
|
6456
|
+
return buildErrorMessages({
|
|
6457
|
+
required,
|
|
6458
|
+
properties,
|
|
6459
|
+
...globalFallbacks,
|
|
6460
|
+
});
|
|
6461
|
+
};
|
|
6462
|
+
|
|
6253
6463
|
const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) => {
|
|
6254
6464
|
if (!selectable) {
|
|
6255
6465
|
return [...selectedDates];
|
|
@@ -6307,6 +6517,10 @@ exports.TableSorter = TableSorter;
|
|
|
6307
6517
|
exports.TableViewer = TableViewer;
|
|
6308
6518
|
exports.TextCell = TextCell;
|
|
6309
6519
|
exports.ViewDialog = ViewDialog;
|
|
6520
|
+
exports.buildErrorMessages = buildErrorMessages;
|
|
6521
|
+
exports.buildFieldErrors = buildFieldErrors;
|
|
6522
|
+
exports.buildRequiredErrors = buildRequiredErrors;
|
|
6523
|
+
exports.createErrorMessage = createErrorMessage;
|
|
6310
6524
|
exports.getColumns = getColumns;
|
|
6311
6525
|
exports.getMultiDates = getMultiDates;
|
|
6312
6526
|
exports.getRangeDates = getRangeDates;
|