@bsol-oss/react-datatable5 12.0.0-beta.71 → 12.0.0-beta.73
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/README.md +67 -40
- package/dist/index.d.ts +265 -14
- package/dist/index.js +356 -98
- package/dist/index.mjs +353 -99
- package/dist/types/components/Form/SchemaFormContext.d.ts +10 -5
- package/dist/types/components/Form/components/core/FormBody.d.ts +2 -1
- package/dist/types/components/Form/components/core/FormRoot.d.ts +12 -8
- package/dist/types/components/Form/components/fields/DatePicker.d.ts +1 -1
- package/dist/types/components/Form/components/fields/EnumPicker.d.ts +1 -1
- package/dist/types/components/Form/components/fields/IdPicker.d.ts +1 -1
- package/dist/types/components/Form/components/types/CustomJSONSchema7.d.ts +30 -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, enumPickerLabels, }) => {
|
|
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,11 @@ 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,
|
|
3779
|
+
enumPickerLabels,
|
|
3776
3780
|
}, children: jsxRuntime.jsx(reactHookForm.FormProvider, { ...form, children: children }) }));
|
|
3777
3781
|
};
|
|
3778
3782
|
|
|
@@ -4031,14 +4035,16 @@ dayjs.extend(utc);
|
|
|
4031
4035
|
dayjs.extend(timezone);
|
|
4032
4036
|
const DatePicker = ({ column, schema, prefix }) => {
|
|
4033
4037
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
4034
|
-
const { timezone } = useSchemaContext();
|
|
4038
|
+
const { timezone, dateTimePickerLabels } = useSchemaContext();
|
|
4035
4039
|
const formI18n = useFormI18n(column, prefix);
|
|
4036
|
-
const { required, gridColumn =
|
|
4040
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
|
|
4037
4041
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4038
4042
|
const colLabel = formI18n.colLabel;
|
|
4039
4043
|
const [open, setOpen] = React.useState(false);
|
|
4040
4044
|
const selectedDate = watch(colLabel);
|
|
4041
|
-
const displayDate = dayjs(selectedDate)
|
|
4045
|
+
const displayDate = dayjs(selectedDate)
|
|
4046
|
+
.tz(timezone)
|
|
4047
|
+
.format(displayDateFormat);
|
|
4042
4048
|
React.useEffect(() => {
|
|
4043
4049
|
try {
|
|
4044
4050
|
if (selectedDate) {
|
|
@@ -4062,45 +4068,83 @@ const DatePicker = ({ column, schema, prefix }) => {
|
|
|
4062
4068
|
console.error(e);
|
|
4063
4069
|
}
|
|
4064
4070
|
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
4065
|
-
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems:
|
|
4071
|
+
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4066
4072
|
gridRow, children: [jsxRuntime.jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
4067
4073
|
setOpen(true);
|
|
4068
|
-
}, justifyContent:
|
|
4074
|
+
}, justifyContent: 'start', children: [jsxRuntime.jsx(md.MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ''] }) }), jsxRuntime.jsx(PopoverContent, { children: jsxRuntime.jsxs(PopoverBody, { children: [jsxRuntime.jsx(PopoverTitle, {}), jsxRuntime.jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
|
|
4069
4075
|
setValue(colLabel, dayjs(date).format(dateFormat));
|
|
4070
4076
|
setOpen(false);
|
|
4071
4077
|
}, labels: {
|
|
4072
|
-
monthNamesShort: [
|
|
4073
|
-
formI18n.translate.t(`common.month_1`, {
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
formI18n.translate.t(`common.
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
formI18n.translate.t(`common.
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
formI18n.translate.t(`common.
|
|
4083
|
-
|
|
4084
|
-
|
|
4078
|
+
monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
|
|
4079
|
+
formI18n.translate.t(`common.month_1`, {
|
|
4080
|
+
defaultValue: 'January',
|
|
4081
|
+
}),
|
|
4082
|
+
formI18n.translate.t(`common.month_2`, {
|
|
4083
|
+
defaultValue: 'February',
|
|
4084
|
+
}),
|
|
4085
|
+
formI18n.translate.t(`common.month_3`, {
|
|
4086
|
+
defaultValue: 'March',
|
|
4087
|
+
}),
|
|
4088
|
+
formI18n.translate.t(`common.month_4`, {
|
|
4089
|
+
defaultValue: 'April',
|
|
4090
|
+
}),
|
|
4091
|
+
formI18n.translate.t(`common.month_5`, {
|
|
4092
|
+
defaultValue: 'May',
|
|
4093
|
+
}),
|
|
4094
|
+
formI18n.translate.t(`common.month_6`, {
|
|
4095
|
+
defaultValue: 'June',
|
|
4096
|
+
}),
|
|
4097
|
+
formI18n.translate.t(`common.month_7`, {
|
|
4098
|
+
defaultValue: 'July',
|
|
4099
|
+
}),
|
|
4100
|
+
formI18n.translate.t(`common.month_8`, {
|
|
4101
|
+
defaultValue: 'August',
|
|
4102
|
+
}),
|
|
4103
|
+
formI18n.translate.t(`common.month_9`, {
|
|
4104
|
+
defaultValue: 'September',
|
|
4105
|
+
}),
|
|
4106
|
+
formI18n.translate.t(`common.month_10`, {
|
|
4107
|
+
defaultValue: 'October',
|
|
4108
|
+
}),
|
|
4109
|
+
formI18n.translate.t(`common.month_11`, {
|
|
4110
|
+
defaultValue: 'November',
|
|
4111
|
+
}),
|
|
4112
|
+
formI18n.translate.t(`common.month_12`, {
|
|
4113
|
+
defaultValue: 'December',
|
|
4114
|
+
}),
|
|
4085
4115
|
],
|
|
4086
|
-
weekdayNamesShort: [
|
|
4087
|
-
formI18n.translate.t(`common.weekday_1`, {
|
|
4088
|
-
|
|
4089
|
-
|
|
4116
|
+
weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
|
|
4117
|
+
formI18n.translate.t(`common.weekday_1`, {
|
|
4118
|
+
defaultValue: 'Sun',
|
|
4119
|
+
}),
|
|
4120
|
+
formI18n.translate.t(`common.weekday_2`, {
|
|
4121
|
+
defaultValue: 'Mon',
|
|
4122
|
+
}),
|
|
4123
|
+
formI18n.translate.t(`common.weekday_3`, {
|
|
4124
|
+
defaultValue: 'Tue',
|
|
4125
|
+
}),
|
|
4090
4126
|
formI18n.translate.t(`common.weekday_4`, {
|
|
4091
|
-
defaultValue:
|
|
4127
|
+
defaultValue: 'Wed',
|
|
4128
|
+
}),
|
|
4129
|
+
formI18n.translate.t(`common.weekday_5`, {
|
|
4130
|
+
defaultValue: 'Thu',
|
|
4131
|
+
}),
|
|
4132
|
+
formI18n.translate.t(`common.weekday_6`, {
|
|
4133
|
+
defaultValue: 'Fri',
|
|
4134
|
+
}),
|
|
4135
|
+
formI18n.translate.t(`common.weekday_7`, {
|
|
4136
|
+
defaultValue: 'Sat',
|
|
4092
4137
|
}),
|
|
4093
|
-
formI18n.translate.t(`common.weekday_5`, { defaultValue: "Thu" }),
|
|
4094
|
-
formI18n.translate.t(`common.weekday_6`, { defaultValue: "Fri" }),
|
|
4095
|
-
formI18n.translate.t(`common.weekday_7`, { defaultValue: "Sat" }),
|
|
4096
4138
|
],
|
|
4097
|
-
backButtonLabel:
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4139
|
+
backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
|
|
4140
|
+
formI18n.translate.t(`common.back_button`, {
|
|
4141
|
+
defaultValue: 'Back',
|
|
4142
|
+
}),
|
|
4143
|
+
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
|
|
4144
|
+
formI18n.translate.t(`common.forward_button`, {
|
|
4145
|
+
defaultValue: 'Forward',
|
|
4146
|
+
}),
|
|
4147
|
+
} })] }) })] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
4104
4148
|
};
|
|
4105
4149
|
|
|
4106
4150
|
function filterArray(array, searchTerm) {
|
|
@@ -4115,10 +4159,10 @@ function filterArray(array, searchTerm) {
|
|
|
4115
4159
|
|
|
4116
4160
|
const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLimit = false, }) => {
|
|
4117
4161
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
4118
|
-
const { translate } = useSchemaContext();
|
|
4162
|
+
const { translate, enumPickerLabels } = useSchemaContext();
|
|
4119
4163
|
const { required, variant } = schema;
|
|
4120
4164
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4121
|
-
const { gridColumn =
|
|
4165
|
+
const { gridColumn = 'span 12', gridRow = 'span 1', renderDisplay } = schema;
|
|
4122
4166
|
const [searchText, setSearchText] = React.useState();
|
|
4123
4167
|
const [limit, setLimit] = React.useState(10);
|
|
4124
4168
|
const [openSearchResult, setOpenSearchResult] = React.useState();
|
|
@@ -4133,9 +4177,9 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
|
|
|
4133
4177
|
setSearchText(event.target.value);
|
|
4134
4178
|
setLimit(10);
|
|
4135
4179
|
};
|
|
4136
|
-
if (variant ===
|
|
4137
|
-
return (jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems:
|
|
4138
|
-
gridRow, children: jsxRuntime.jsx(react.RadioGroup.Root, { defaultValue: "1", children: jsxRuntime.jsx(react.HStack, { gap: "6", children: filterArray(dataList, searchText ??
|
|
4180
|
+
if (variant === 'radio') {
|
|
4181
|
+
return (jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4182
|
+
gridRow, children: jsxRuntime.jsx(react.RadioGroup.Root, { defaultValue: "1", children: jsxRuntime.jsx(react.HStack, { gap: "6", children: filterArray(dataList, searchText ?? '').map((item) => {
|
|
4139
4183
|
return (jsxRuntime.jsxs(react.RadioGroup.Item, { onClick: () => {
|
|
4140
4184
|
if (!isMultiple) {
|
|
4141
4185
|
setOpenSearchResult(false);
|
|
@@ -4149,8 +4193,8 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
|
|
|
4149
4193
|
: translate.t(removeIndex(`${colLabel}.${item}`)) })] }, `${colLabel}-${item}`));
|
|
4150
4194
|
}) }) }) }));
|
|
4151
4195
|
}
|
|
4152
|
-
return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems:
|
|
4153
|
-
gridRow, children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow:
|
|
4196
|
+
return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4197
|
+
gridRow, children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow: 'wrap', gap: 1, children: [watchEnums.map((enumValue) => {
|
|
4154
4198
|
const item = enumValue;
|
|
4155
4199
|
if (!!item === false) {
|
|
4156
4200
|
return jsxRuntime.jsx(jsxRuntime.Fragment, {});
|
|
@@ -4160,18 +4204,20 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
|
|
|
4160
4204
|
}, children: !!renderDisplay === true
|
|
4161
4205
|
? renderDisplay(item)
|
|
4162
4206
|
: translate.t(removeIndex(`${colLabel}.${item}`)) }, item));
|
|
4163
|
-
}), jsxRuntime.jsx(Tag, { size: "lg", cursor:
|
|
4207
|
+
}), jsxRuntime.jsx(Tag, { size: "lg", cursor: 'pointer', onClick: () => {
|
|
4164
4208
|
setOpenSearchResult(true);
|
|
4165
|
-
}, children:
|
|
4209
|
+
}, children: enumPickerLabels?.addMore ??
|
|
4210
|
+
translate.t(removeIndex(`${colLabel}.add_more`)) }, `${colLabel}-add-more-tag`)] })), !isMultiple && (jsxRuntime.jsx(Button, { variant: 'outline', onClick: () => {
|
|
4166
4211
|
setOpenSearchResult(true);
|
|
4167
|
-
}, justifyContent:
|
|
4168
|
-
?
|
|
4169
|
-
: translate.t(removeIndex(`${colLabel}.${watchEnum ??
|
|
4212
|
+
}, justifyContent: 'start', children: !!watchEnum === false
|
|
4213
|
+
? ''
|
|
4214
|
+
: translate.t(removeIndex(`${colLabel}.${watchEnum ?? 'null'}`)) })), jsxRuntime.jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: 'bottom-start' }, children: [jsxRuntime.jsx(PopoverTrigger, {}), jsxRuntime.jsx(PopoverContent, { portalled: false, children: jsxRuntime.jsxs(PopoverBody, { display: 'grid', gap: 1, children: [jsxRuntime.jsx(react.Input, { placeholder: enumPickerLabels?.typeToSearch ??
|
|
4215
|
+
translate.t(`${colLabel}.type_to_search`), onChange: (event) => {
|
|
4170
4216
|
onSearchChange(event);
|
|
4171
4217
|
setOpenSearchResult(true);
|
|
4172
|
-
}, autoComplete: "off", ref: ref }), jsxRuntime.jsx(PopoverTitle, {}), showTotalAndLimit && (jsxRuntime.jsx(react.Text, { children: `${translate.t(removeIndex(`${colLabel}.total`))}: ${count}, ${translate.t(removeIndex(`${colLabel}.showing`))} ${limit}` })), jsxRuntime.jsxs(react.Grid, { overflow:
|
|
4218
|
+
}, autoComplete: "off", ref: ref }), jsxRuntime.jsx(PopoverTitle, {}), showTotalAndLimit && (jsxRuntime.jsx(react.Text, { children: `${enumPickerLabels?.total ?? translate.t(removeIndex(`${colLabel}.total`))}: ${count}, ${enumPickerLabels?.showing ?? translate.t(removeIndex(`${colLabel}.showing`))} ${limit}` })), jsxRuntime.jsxs(react.Grid, { overflow: 'auto', maxHeight: '20rem', children: [jsxRuntime.jsx(react.Flex, { flexFlow: 'column wrap', children: dataList
|
|
4173
4219
|
.filter((item) => {
|
|
4174
|
-
const searchTerm = (searchText ||
|
|
4220
|
+
const searchTerm = (searchText || '').toLowerCase();
|
|
4175
4221
|
if (!searchTerm)
|
|
4176
4222
|
return true;
|
|
4177
4223
|
// Check if the original enum value contains the search text
|
|
@@ -4191,7 +4237,7 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
|
|
|
4191
4237
|
const selected = isMultiple
|
|
4192
4238
|
? watchEnums.some((enumValue) => item === enumValue)
|
|
4193
4239
|
: watchEnum == item;
|
|
4194
|
-
return (jsxRuntime.jsx(react.Box, { cursor:
|
|
4240
|
+
return (jsxRuntime.jsx(react.Box, { cursor: 'pointer', onClick: () => {
|
|
4195
4241
|
if (!isMultiple) {
|
|
4196
4242
|
setOpenSearchResult(false);
|
|
4197
4243
|
setValue(colLabel, item);
|
|
@@ -4199,10 +4245,11 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
|
|
|
4199
4245
|
}
|
|
4200
4246
|
const newSet = new Set([...(watchEnums ?? []), item]);
|
|
4201
4247
|
setValue(colLabel, [...newSet]);
|
|
4202
|
-
}, ...(selected ? { color:
|
|
4248
|
+
}, ...(selected ? { color: 'colorPalette.400/50' } : {}), children: !!renderDisplay === true
|
|
4203
4249
|
? renderDisplay(item)
|
|
4204
4250
|
: translate.t(removeIndex(`${colLabel}.${item}`)) }, `${colLabel}-${item}`));
|
|
4205
|
-
}) }), isDirty && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: dataList.length <= 0 && (jsxRuntime.jsx(jsxRuntime.Fragment, { children:
|
|
4251
|
+
}) }), isDirty && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: dataList.length <= 0 && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: enumPickerLabels?.emptySearchResult ??
|
|
4252
|
+
translate.t(removeIndex(`${colLabel}.empty_search_result`)) })) }))] })] }) })] }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
4206
4253
|
};
|
|
4207
4254
|
|
|
4208
4255
|
function isEnteringWindow(_ref) {
|
|
@@ -4615,12 +4662,12 @@ const getTableData = async ({ serverUrl, in_table, searching = "", where = [], l
|
|
|
4615
4662
|
|
|
4616
4663
|
const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
4617
4664
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
4618
|
-
const { serverUrl, idMap, setIdMap, schema: parentSchema, } = useSchemaContext();
|
|
4665
|
+
const { serverUrl, idMap, setIdMap, schema: parentSchema, idPickerLabels, } = useSchemaContext();
|
|
4619
4666
|
const formI18n = useFormI18n(column, prefix);
|
|
4620
|
-
const { required, gridColumn =
|
|
4667
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, foreign_key, } = schema;
|
|
4621
4668
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4622
4669
|
const { table, column: column_ref, display_column, customQueryFn, } = foreign_key;
|
|
4623
|
-
const [searchText, setSearchText] = React.useState(
|
|
4670
|
+
const [searchText, setSearchText] = React.useState('');
|
|
4624
4671
|
const [limit, setLimit] = React.useState(10);
|
|
4625
4672
|
const [openSearchResult, setOpenSearchResult] = React.useState();
|
|
4626
4673
|
const [page, setPage] = React.useState(0);
|
|
@@ -4634,7 +4681,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4634
4681
|
queryFn: async () => {
|
|
4635
4682
|
if (customQueryFn) {
|
|
4636
4683
|
const { data, idMap } = await customQueryFn({
|
|
4637
|
-
searching: searchText ??
|
|
4684
|
+
searching: searchText ?? '',
|
|
4638
4685
|
limit: limit,
|
|
4639
4686
|
offset: page * limit,
|
|
4640
4687
|
});
|
|
@@ -4645,7 +4692,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4645
4692
|
}
|
|
4646
4693
|
const data = await getTableData({
|
|
4647
4694
|
serverUrl,
|
|
4648
|
-
searching: searchText ??
|
|
4695
|
+
searching: searchText ?? '',
|
|
4649
4696
|
in_table: table,
|
|
4650
4697
|
limit: limit,
|
|
4651
4698
|
offset: page * limit,
|
|
@@ -4675,7 +4722,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4675
4722
|
queryFn: async () => {
|
|
4676
4723
|
if (customQueryFn) {
|
|
4677
4724
|
const { data, idMap } = await customQueryFn({
|
|
4678
|
-
searching: watchIds.join(
|
|
4725
|
+
searching: watchIds.join(','),
|
|
4679
4726
|
limit: isMultiple ? watchIds.length : 1,
|
|
4680
4727
|
offset: 0,
|
|
4681
4728
|
});
|
|
@@ -4687,7 +4734,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4687
4734
|
if (!watchId && (!watchIds || watchIds.length === 0)) {
|
|
4688
4735
|
return { data: [] };
|
|
4689
4736
|
}
|
|
4690
|
-
const searchValue = isMultiple ? watchIds.join(
|
|
4737
|
+
const searchValue = isMultiple ? watchIds.join(',') : watchId;
|
|
4691
4738
|
const data = await getTableData({
|
|
4692
4739
|
serverUrl,
|
|
4693
4740
|
searching: searchValue,
|
|
@@ -4724,7 +4771,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4724
4771
|
React.useEffect(() => {
|
|
4725
4772
|
if (openSearchResult) {
|
|
4726
4773
|
// Reset search text when opening the popover
|
|
4727
|
-
setSearchText(
|
|
4774
|
+
setSearchText('');
|
|
4728
4775
|
// Reset page to first page
|
|
4729
4776
|
setPage(0);
|
|
4730
4777
|
// Fetch initial data
|
|
@@ -4750,44 +4797,44 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4750
4797
|
const count = data?.count ?? 0;
|
|
4751
4798
|
const getPickedValue = () => {
|
|
4752
4799
|
if (Object.keys(idMap).length <= 0) {
|
|
4753
|
-
return
|
|
4800
|
+
return '';
|
|
4754
4801
|
}
|
|
4755
4802
|
const record = idMap[watchId];
|
|
4756
4803
|
if (record === undefined) {
|
|
4757
|
-
return
|
|
4804
|
+
return '';
|
|
4758
4805
|
}
|
|
4759
4806
|
if (!!renderDisplay === true) {
|
|
4760
4807
|
return renderDisplay(record);
|
|
4761
4808
|
}
|
|
4762
4809
|
return record[display_column];
|
|
4763
4810
|
};
|
|
4764
|
-
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems:
|
|
4765
|
-
gridRow, children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow:
|
|
4811
|
+
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4812
|
+
gridRow, children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow: 'wrap', gap: 1, children: [watchIds.map((id) => {
|
|
4766
4813
|
const item = idMap[id];
|
|
4767
4814
|
if (item === undefined) {
|
|
4768
|
-
return (jsxRuntime.jsx(react.Text, { children: formI18n.t('undefined') }, id));
|
|
4815
|
+
return (jsxRuntime.jsx(react.Text, { children: idPickerLabels?.undefined ?? formI18n.t('undefined') }, id));
|
|
4769
4816
|
}
|
|
4770
4817
|
return (jsxRuntime.jsx(Tag, { closable: true, onClick: () => {
|
|
4771
4818
|
setValue(colLabel, watchIds.filter((itemId) => itemId !== item[column_ref]));
|
|
4772
4819
|
}, children: !!renderDisplay === true
|
|
4773
4820
|
? renderDisplay(item)
|
|
4774
4821
|
: item[display_column] }, id));
|
|
4775
|
-
}), jsxRuntime.jsx(Tag, { cursor:
|
|
4822
|
+
}), jsxRuntime.jsx(Tag, { cursor: 'pointer', onClick: () => {
|
|
4776
4823
|
setOpenSearchResult(true);
|
|
4777
|
-
}, children: formI18n.t('add_more') })] })), !isMultiple && (jsxRuntime.jsx(Button, { variant:
|
|
4824
|
+
}, children: idPickerLabels?.addMore ?? formI18n.t('add_more') })] })), !isMultiple && (jsxRuntime.jsx(Button, { variant: 'outline', onClick: () => {
|
|
4778
4825
|
setOpenSearchResult(true);
|
|
4779
|
-
}, justifyContent:
|
|
4826
|
+
}, 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
4827
|
? `${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:
|
|
4828
|
+
: '0'] })] })] }), jsxRuntime.jsx(react.Box, { children: jsxRuntime.jsxs("select", { value: limit, onChange: handleLimitChange, style: {
|
|
4829
|
+
padding: '4px 8px',
|
|
4830
|
+
borderRadius: '4px',
|
|
4831
|
+
border: '1px solid #ccc',
|
|
4832
|
+
fontSize: '14px',
|
|
4833
|
+
}, 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
4834
|
const selected = isMultiple
|
|
4788
4835
|
? watchIds.some((id) => item[column_ref] === id)
|
|
4789
4836
|
: watchId === item[column_ref];
|
|
4790
|
-
return (jsxRuntime.jsx(react.Box, { cursor:
|
|
4837
|
+
return (jsxRuntime.jsx(react.Box, { cursor: 'pointer', onClick: () => {
|
|
4791
4838
|
if (!isMultiple) {
|
|
4792
4839
|
setOpenSearchResult(false);
|
|
4793
4840
|
setValue(colLabel, item[column_ref]);
|
|
@@ -4803,15 +4850,17 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4803
4850
|
setValue(colLabel, [...newSet]);
|
|
4804
4851
|
}, opacity: 0.7, _hover: { opacity: 1 }, ...(selected
|
|
4805
4852
|
? {
|
|
4806
|
-
color:
|
|
4807
|
-
fontWeight:
|
|
4853
|
+
color: 'colorPalette.400/50',
|
|
4854
|
+
fontWeight: 'bold',
|
|
4808
4855
|
}
|
|
4809
4856
|
: {}), children: !!renderDisplay === true
|
|
4810
4857
|
? renderDisplay(item)
|
|
4811
4858
|
: item[display_column] }, item[column_ref]));
|
|
4812
4859
|
}) })) : (jsxRuntime.jsx(react.Text, { children: searchText
|
|
4813
|
-
?
|
|
4814
|
-
|
|
4860
|
+
? idPickerLabels?.emptySearchResult ??
|
|
4861
|
+
formI18n.t('empty_search_result')
|
|
4862
|
+
: idPickerLabels?.initialResults ??
|
|
4863
|
+
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
4864
|
};
|
|
4816
4865
|
|
|
4817
4866
|
const NumberInputRoot = React__namespace.forwardRef(function NumberInput(props, ref) {
|
|
@@ -5498,7 +5547,7 @@ dayjs.extend(utc);
|
|
|
5498
5547
|
dayjs.extend(timezone);
|
|
5499
5548
|
const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
5500
5549
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
5501
|
-
const { timezone } = useSchemaContext();
|
|
5550
|
+
const { timezone, dateTimePickerLabels } = useSchemaContext();
|
|
5502
5551
|
const formI18n = useFormI18n(column, prefix);
|
|
5503
5552
|
const { required, gridColumn = "span 12", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD HH:mm:ss",
|
|
5504
5553
|
// with timezone
|
|
@@ -5539,7 +5588,7 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
5539
5588
|
}, 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
5589
|
setValue(colLabel, dayjs(date).tz(timezone).format(dateFormat));
|
|
5541
5590
|
}, timezone: timezone, labels: {
|
|
5542
|
-
monthNamesShort: [
|
|
5591
|
+
monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
|
|
5543
5592
|
formI18n.translate.t(`common.month_1`, { defaultValue: "January" }),
|
|
5544
5593
|
formI18n.translate.t(`common.month_2`, { defaultValue: "February" }),
|
|
5545
5594
|
formI18n.translate.t(`common.month_3`, { defaultValue: "March" }),
|
|
@@ -5553,7 +5602,7 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
5553
5602
|
formI18n.translate.t(`common.month_11`, { defaultValue: "November" }),
|
|
5554
5603
|
formI18n.translate.t(`common.month_12`, { defaultValue: "December" }),
|
|
5555
5604
|
],
|
|
5556
|
-
weekdayNamesShort: [
|
|
5605
|
+
weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
|
|
5557
5606
|
formI18n.translate.t(`common.weekday_1`, { defaultValue: "Sun" }),
|
|
5558
5607
|
formI18n.translate.t(`common.weekday_2`, { defaultValue: "Mon" }),
|
|
5559
5608
|
formI18n.translate.t(`common.weekday_3`, { defaultValue: "Tue" }),
|
|
@@ -5564,10 +5613,10 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
5564
5613
|
formI18n.translate.t(`common.weekday_6`, { defaultValue: "Fri" }),
|
|
5565
5614
|
formI18n.translate.t(`common.weekday_7`, { defaultValue: "Sat" }),
|
|
5566
5615
|
],
|
|
5567
|
-
backButtonLabel: formI18n.translate.t(`common.back_button`, {
|
|
5616
|
+
backButtonLabel: dateTimePickerLabels?.backButtonLabel ?? formI18n.translate.t(`common.back_button`, {
|
|
5568
5617
|
defaultValue: "Back",
|
|
5569
5618
|
}),
|
|
5570
|
-
forwardButtonLabel: formI18n.translate.t(`common.forward_button`, {
|
|
5619
|
+
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ?? formI18n.translate.t(`common.forward_button`, {
|
|
5571
5620
|
defaultValue: "Forward",
|
|
5572
5621
|
}),
|
|
5573
5622
|
} })] }) })] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: formI18n.required() }))] }));
|
|
@@ -6093,7 +6142,7 @@ const SubmitButton = () => {
|
|
|
6093
6142
|
};
|
|
6094
6143
|
|
|
6095
6144
|
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();
|
|
6145
|
+
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
6146
|
const { showSubmitButton, showResetButton } = displayConfig;
|
|
6098
6147
|
const methods = reactHookForm.useFormContext();
|
|
6099
6148
|
const { properties } = schema;
|
|
@@ -6190,15 +6239,19 @@ const FormBody = () => {
|
|
|
6190
6239
|
include,
|
|
6191
6240
|
});
|
|
6192
6241
|
if (isSuccess) {
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6242
|
+
const resetHandler = async () => {
|
|
6243
|
+
setIsError(false);
|
|
6244
|
+
setIsSubmiting(false);
|
|
6245
|
+
setIsSuccess(false);
|
|
6246
|
+
setIsConfirming(false);
|
|
6247
|
+
setValidatedData(undefined);
|
|
6248
|
+
const data = await getUpdatedData();
|
|
6249
|
+
methods.reset(data);
|
|
6250
|
+
};
|
|
6251
|
+
if (customSuccessRenderer) {
|
|
6252
|
+
return customSuccessRenderer(resetHandler);
|
|
6253
|
+
}
|
|
6254
|
+
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
6255
|
}
|
|
6203
6256
|
if (isConfirming) {
|
|
6204
6257
|
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 +6289,12 @@ const DefaultForm = ({ formConfig, }) => {
|
|
|
6236
6289
|
return (jsxRuntime.jsx(FormRoot, { ...formConfig, children: jsxRuntime.jsxs(react.Grid, { gap: "2", children: [showTitle && jsxRuntime.jsx(FormTitle, {}), jsxRuntime.jsx(FormBody, {})] }) }));
|
|
6237
6290
|
};
|
|
6238
6291
|
|
|
6239
|
-
const useForm = ({ preLoadedValues, keyPrefix }) => {
|
|
6292
|
+
const useForm = ({ preLoadedValues, keyPrefix, namespace }) => {
|
|
6240
6293
|
const form = reactHookForm.useForm({
|
|
6241
6294
|
values: preLoadedValues,
|
|
6242
6295
|
});
|
|
6243
6296
|
const [idMap, setIdMap] = React.useState({});
|
|
6244
|
-
const translate = reactI18next.useTranslation("", { keyPrefix });
|
|
6297
|
+
const translate = reactI18next.useTranslation(namespace || "", { keyPrefix });
|
|
6245
6298
|
return {
|
|
6246
6299
|
form,
|
|
6247
6300
|
idMap,
|
|
@@ -6250,6 +6303,207 @@ const useForm = ({ preLoadedValues, keyPrefix }) => {
|
|
|
6250
6303
|
};
|
|
6251
6304
|
};
|
|
6252
6305
|
|
|
6306
|
+
/**
|
|
6307
|
+
* Type definitions for error message configuration
|
|
6308
|
+
*/
|
|
6309
|
+
/**
|
|
6310
|
+
* Schema-level error message builder
|
|
6311
|
+
*
|
|
6312
|
+
* Builds a complete errorMessage object compatible with ajv-errors plugin.
|
|
6313
|
+
* Supports both i18n translation keys and plain string messages.
|
|
6314
|
+
*
|
|
6315
|
+
* @param config - Error message configuration
|
|
6316
|
+
* @returns Complete errorMessage object for JSON Schema
|
|
6317
|
+
*
|
|
6318
|
+
* @example
|
|
6319
|
+
* ```typescript
|
|
6320
|
+
* // Simple required field errors
|
|
6321
|
+
* const errorMessage = buildErrorMessages({
|
|
6322
|
+
* required: {
|
|
6323
|
+
* username: "Username is required",
|
|
6324
|
+
* email: "user.email.field_required" // i18n key
|
|
6325
|
+
* }
|
|
6326
|
+
* });
|
|
6327
|
+
*
|
|
6328
|
+
* // With validation rules
|
|
6329
|
+
* const errorMessage = buildErrorMessages({
|
|
6330
|
+
* required: {
|
|
6331
|
+
* password: "Password is required"
|
|
6332
|
+
* },
|
|
6333
|
+
* properties: {
|
|
6334
|
+
* password: {
|
|
6335
|
+
* minLength: "Password must be at least 8 characters",
|
|
6336
|
+
* pattern: "Password must contain letters and numbers"
|
|
6337
|
+
* },
|
|
6338
|
+
* age: {
|
|
6339
|
+
* minimum: "Must be 18 or older",
|
|
6340
|
+
* maximum: "Must be under 120"
|
|
6341
|
+
* }
|
|
6342
|
+
* }
|
|
6343
|
+
* });
|
|
6344
|
+
*
|
|
6345
|
+
* // With global fallbacks
|
|
6346
|
+
* const errorMessage = buildErrorMessages({
|
|
6347
|
+
* required: {
|
|
6348
|
+
* email: "Email is required"
|
|
6349
|
+
* },
|
|
6350
|
+
* minLength: "This field is too short", // applies to all fields
|
|
6351
|
+
* minimum: "Value is too small"
|
|
6352
|
+
* });
|
|
6353
|
+
* ```
|
|
6354
|
+
*/
|
|
6355
|
+
const buildErrorMessages = (config) => {
|
|
6356
|
+
const result = {};
|
|
6357
|
+
// Add required field errors
|
|
6358
|
+
if (config.required && Object.keys(config.required).length > 0) {
|
|
6359
|
+
result.required = config.required;
|
|
6360
|
+
}
|
|
6361
|
+
// Add field-specific validation errors
|
|
6362
|
+
if (config.properties && Object.keys(config.properties).length > 0) {
|
|
6363
|
+
result.properties = config.properties;
|
|
6364
|
+
}
|
|
6365
|
+
// Add global fallback error messages
|
|
6366
|
+
const globalKeys = [
|
|
6367
|
+
"minLength",
|
|
6368
|
+
"maxLength",
|
|
6369
|
+
"pattern",
|
|
6370
|
+
"minimum",
|
|
6371
|
+
"maximum",
|
|
6372
|
+
"multipleOf",
|
|
6373
|
+
"format",
|
|
6374
|
+
"type",
|
|
6375
|
+
"enum",
|
|
6376
|
+
];
|
|
6377
|
+
globalKeys.forEach((key) => {
|
|
6378
|
+
if (config[key]) {
|
|
6379
|
+
result[key] = config[key];
|
|
6380
|
+
}
|
|
6381
|
+
});
|
|
6382
|
+
return result;
|
|
6383
|
+
};
|
|
6384
|
+
/**
|
|
6385
|
+
* Helper function to build required field errors
|
|
6386
|
+
*
|
|
6387
|
+
* Simplifies creating required field error messages, especially useful
|
|
6388
|
+
* for generating i18n translation keys following a pattern.
|
|
6389
|
+
*
|
|
6390
|
+
* @param fields - Array of required field names
|
|
6391
|
+
* @param messageOrGenerator - Either a string template or function to generate messages
|
|
6392
|
+
* @returns Required field error configuration
|
|
6393
|
+
*
|
|
6394
|
+
* @example
|
|
6395
|
+
* ```typescript
|
|
6396
|
+
* // Plain string messages
|
|
6397
|
+
* const required = buildRequiredErrors(
|
|
6398
|
+
* ["username", "email", "password"],
|
|
6399
|
+
* (field) => `${field} is required`
|
|
6400
|
+
* );
|
|
6401
|
+
* // Result: { username: "username is required", email: "email is required", ... }
|
|
6402
|
+
*
|
|
6403
|
+
* // i18n translation keys
|
|
6404
|
+
* const required = buildRequiredErrors(
|
|
6405
|
+
* ["username", "email"],
|
|
6406
|
+
* (field) => `user.${field}.field_required`
|
|
6407
|
+
* );
|
|
6408
|
+
* // Result: { username: "user.username.field_required", email: "user.email.field_required" }
|
|
6409
|
+
*
|
|
6410
|
+
* // Same message for all fields
|
|
6411
|
+
* const required = buildRequiredErrors(
|
|
6412
|
+
* ["username", "email"],
|
|
6413
|
+
* "This field is required"
|
|
6414
|
+
* );
|
|
6415
|
+
* // Result: { username: "This field is required", email: "This field is required" }
|
|
6416
|
+
*
|
|
6417
|
+
* // With keyPrefix for i18n
|
|
6418
|
+
* const required = buildRequiredErrors(
|
|
6419
|
+
* ["username", "email"],
|
|
6420
|
+
* (field) => `${field}.field_required`,
|
|
6421
|
+
* "user"
|
|
6422
|
+
* );
|
|
6423
|
+
* // Result: { username: "user.username.field_required", email: "user.email.field_required" }
|
|
6424
|
+
* ```
|
|
6425
|
+
*/
|
|
6426
|
+
const buildRequiredErrors = (fields, messageOrGenerator, keyPrefix = "") => {
|
|
6427
|
+
const result = {};
|
|
6428
|
+
fields.forEach((field) => {
|
|
6429
|
+
if (typeof messageOrGenerator === "function") {
|
|
6430
|
+
const message = messageOrGenerator(field);
|
|
6431
|
+
result[field] = keyPrefix ? `${keyPrefix}.${message}` : message;
|
|
6432
|
+
}
|
|
6433
|
+
else {
|
|
6434
|
+
result[field] = messageOrGenerator;
|
|
6435
|
+
}
|
|
6436
|
+
});
|
|
6437
|
+
return result;
|
|
6438
|
+
};
|
|
6439
|
+
/**
|
|
6440
|
+
* Helper function to build field-specific validation errors
|
|
6441
|
+
*
|
|
6442
|
+
* Creates property-specific error messages for multiple fields at once.
|
|
6443
|
+
*
|
|
6444
|
+
* @param config - Maps field names to their validation error configurations
|
|
6445
|
+
* @returns Properties error configuration
|
|
6446
|
+
*
|
|
6447
|
+
* @example
|
|
6448
|
+
* ```typescript
|
|
6449
|
+
* const properties = buildFieldErrors({
|
|
6450
|
+
* username: {
|
|
6451
|
+
* minLength: "Username must be at least 3 characters",
|
|
6452
|
+
* pattern: "Username can only contain letters and numbers"
|
|
6453
|
+
* },
|
|
6454
|
+
* age: {
|
|
6455
|
+
* minimum: "Must be 18 or older",
|
|
6456
|
+
* maximum: "Must be under 120"
|
|
6457
|
+
* },
|
|
6458
|
+
* email: {
|
|
6459
|
+
* format: "Please enter a valid email address"
|
|
6460
|
+
* }
|
|
6461
|
+
* });
|
|
6462
|
+
* ```
|
|
6463
|
+
*/
|
|
6464
|
+
const buildFieldErrors = (config) => {
|
|
6465
|
+
return config;
|
|
6466
|
+
};
|
|
6467
|
+
/**
|
|
6468
|
+
* Helper function to create a complete error message configuration in one call
|
|
6469
|
+
*
|
|
6470
|
+
* Convenient wrapper that combines required and validation errors.
|
|
6471
|
+
*
|
|
6472
|
+
* @param required - Required field error messages
|
|
6473
|
+
* @param properties - Field-specific validation error messages
|
|
6474
|
+
* @param globalFallbacks - Global fallback error messages
|
|
6475
|
+
* @returns Complete error message configuration
|
|
6476
|
+
*
|
|
6477
|
+
* @example
|
|
6478
|
+
* ```typescript
|
|
6479
|
+
* const errorMessage = createErrorMessage(
|
|
6480
|
+
* {
|
|
6481
|
+
* username: "Username is required",
|
|
6482
|
+
* email: "Email is required"
|
|
6483
|
+
* },
|
|
6484
|
+
* {
|
|
6485
|
+
* username: {
|
|
6486
|
+
* minLength: "Username must be at least 3 characters"
|
|
6487
|
+
* },
|
|
6488
|
+
* email: {
|
|
6489
|
+
* format: "Please enter a valid email"
|
|
6490
|
+
* }
|
|
6491
|
+
* },
|
|
6492
|
+
* {
|
|
6493
|
+
* minLength: "This field is too short",
|
|
6494
|
+
* format: "Invalid format"
|
|
6495
|
+
* }
|
|
6496
|
+
* );
|
|
6497
|
+
* ```
|
|
6498
|
+
*/
|
|
6499
|
+
const createErrorMessage = (required, properties, globalFallbacks) => {
|
|
6500
|
+
return buildErrorMessages({
|
|
6501
|
+
required,
|
|
6502
|
+
properties,
|
|
6503
|
+
...globalFallbacks,
|
|
6504
|
+
});
|
|
6505
|
+
};
|
|
6506
|
+
|
|
6253
6507
|
const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) => {
|
|
6254
6508
|
if (!selectable) {
|
|
6255
6509
|
return [...selectedDates];
|
|
@@ -6307,6 +6561,10 @@ exports.TableSorter = TableSorter;
|
|
|
6307
6561
|
exports.TableViewer = TableViewer;
|
|
6308
6562
|
exports.TextCell = TextCell;
|
|
6309
6563
|
exports.ViewDialog = ViewDialog;
|
|
6564
|
+
exports.buildErrorMessages = buildErrorMessages;
|
|
6565
|
+
exports.buildFieldErrors = buildFieldErrors;
|
|
6566
|
+
exports.buildRequiredErrors = buildRequiredErrors;
|
|
6567
|
+
exports.createErrorMessage = createErrorMessage;
|
|
6310
6568
|
exports.getColumns = getColumns;
|
|
6311
6569
|
exports.getMultiDates = getMultiDates;
|
|
6312
6570
|
exports.getRangeDates = getRangeDates;
|