@bsol-oss/react-datatable5 12.0.0-beta.73 → 12.0.0-beta.75
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 +133 -124
- package/dist/index.js +651 -306
- package/dist/index.mjs +653 -309
- package/dist/types/components/Form/SchemaFormContext.d.ts +5 -2
- package/dist/types/components/Form/components/core/FormRoot.d.ts +2 -1
- package/dist/types/components/Form/components/fields/BooleanPicker.d.ts +1 -1
- package/dist/types/components/Form/components/fields/ColumnRenderer.d.ts +3 -2
- package/dist/types/components/Form/components/fields/DateTimePicker.d.ts +1 -1
- package/dist/types/components/Form/components/fields/FilePicker.d.ts +1 -1
- package/dist/types/components/Form/components/fields/NumberInputField.d.ts +1 -1
- package/dist/types/components/Form/components/fields/ObjectInput.d.ts +1 -1
- package/dist/types/components/Form/components/fields/RecordInput.d.ts +1 -1
- package/dist/types/components/Form/components/fields/StringInputField.d.ts +1 -1
- package/dist/types/components/Form/components/fields/TextAreaInput.d.ts +1 -1
- package/dist/types/components/Form/components/fields/TimePicker.d.ts +1 -1
- package/dist/types/components/Form/components/types/CustomJSONSchema7.d.ts +4 -0
- package/dist/types/components/Form/components/viewers/NumberViewer.d.ts +1 -1
- package/dist/types/components/Form/useForm.d.ts +4 -2
- package/dist/types/components/Form/utils/ajvResolver.d.ts +13 -0
- package/dist/types/components/Form/utils/buildErrorMessages.d.ts +5 -1
- package/dist/types/components/Form/utils/getFieldError.d.ts +6 -0
- package/dist/types/components/Form/utils/useFormI18n.d.ts +1 -1
- package/dist/types/components/Form/utils/validateData.d.ts +2 -2
- package/dist/types/components/ui/field.d.ts +3 -3
- package/package.json +1 -1
- package/dist/types/components/Controls/DensityFeature.d.ts +0 -23
- package/dist/types/components/Controls/DensityToggleButton.d.ts +0 -6
- package/dist/types/components/Controls/EditFilterButton.d.ts +0 -9
- package/dist/types/components/Controls/EditOrderButton.d.ts +0 -7
- package/dist/types/components/Controls/EditSortingButton.d.ts +0 -7
- package/dist/types/components/Controls/EditViewButton.d.ts +0 -7
- package/dist/types/components/Controls/FilterDialog.d.ts +0 -5
- package/dist/types/components/Controls/PageSizeControl.d.ts +0 -4
- package/dist/types/components/Controls/Pagination.d.ts +0 -1
- package/dist/types/components/Controls/ResetFilteringButton.d.ts +0 -4
- package/dist/types/components/Controls/ResetSelectionButton.d.ts +0 -4
- package/dist/types/components/Controls/ResetSortingButton.d.ts +0 -4
- package/dist/types/components/Controls/RowCountText.d.ts +0 -1
- package/dist/types/components/Controls/SelectAllRowsToggle.d.ts +0 -8
- package/dist/types/components/Controls/TablePagination.d.ts +0 -1
- package/dist/types/components/Controls/ViewDialog.d.ts +0 -5
- package/dist/types/components/DataTable/CardHeader.d.ts +0 -13
- package/dist/types/components/DataTable/DataDisplay.d.ts +0 -6
- package/dist/types/components/DataTable/ReloadButton.d.ts +0 -5
- package/dist/types/components/DataTable/Table.d.ts +0 -10
- package/dist/types/components/DataTable/TableBody.d.ts +0 -21
- package/dist/types/components/DataTable/TableCardContainer.d.ts +0 -7
- package/dist/types/components/DataTable/TableCards.d.ts +0 -11
- package/dist/types/components/DataTable/TableComponent.d.ts +0 -6
- package/dist/types/components/DataTable/TableControls.d.ts +0 -21
- package/dist/types/components/DataTable/TableFilter.d.ts +0 -1
- package/dist/types/components/DataTable/TableFilterTags.d.ts +0 -1
- package/dist/types/components/DataTable/TableFilters.d.ts +0 -1
- package/dist/types/components/DataTable/TableFooter.d.ts +0 -9
- package/dist/types/components/DataTable/TableHeader.d.ts +0 -13
- package/dist/types/components/DataTable/TableLoadingComponent.d.ts +0 -5
- package/dist/types/components/DataTable/TableOrderer.d.ts +0 -1
- package/dist/types/components/DataTable/TableSelector.d.ts +0 -1
- package/dist/types/components/DataTable/TableSorter.d.ts +0 -1
- package/dist/types/components/DataTable/TableViewer.d.ts +0 -1
- package/dist/types/components/DataTable/TextCell.d.ts +0 -10
- package/dist/types/components/DataTable/components/EmptyState.d.ts +0 -5
- package/dist/types/components/DataTable/components/ErrorAlert.d.ts +0 -4
- package/dist/types/components/DataTable/components/RecordDisplay.d.ts +0 -9
- package/dist/types/components/DataTable/components/TextCell.d.ts +0 -10
- package/dist/types/components/Filter/DateRangeFilter.d.ts +0 -9
- package/dist/types/components/Filter/FilterOptions.d.ts +0 -4
- package/dist/types/components/Form/Form.d.ts +0 -36
- package/dist/types/components/Form/components/ArrayRenderer.d.ts +0 -7
- package/dist/types/components/Form/components/BooleanPicker.d.ts +0 -7
- package/dist/types/components/Form/components/ColumnRenderer.d.ts +0 -7
- package/dist/types/components/Form/components/DatePicker.d.ts +0 -7
- package/dist/types/components/Form/components/EnumPicker.d.ts +0 -8
- package/dist/types/components/Form/components/FilePicker.d.ts +0 -5
- package/dist/types/components/Form/components/IdPicker.d.ts +0 -8
- package/dist/types/components/Form/components/IdViewer.d.ts +0 -5
- package/dist/types/components/Form/components/NumberInputField.d.ts +0 -7
- package/dist/types/components/Form/components/ObjectInput.d.ts +0 -7
- package/dist/types/components/Form/components/RecordInput.d.ts +0 -7
- package/dist/types/components/Form/components/SchemaRenderer.d.ts +0 -7
- package/dist/types/components/Form/components/StringInputField.d.ts +0 -20
- package/dist/types/components/Form/components/TagPicker.d.ts +0 -30
- package/dist/types/components/Form/utils/translateWrapper.d.ts +0 -6
- package/dist/types/components/Form/utils/validation.d.ts +0 -104
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, Tag as Tag$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, CheckboxCard as CheckboxCard$1, Image, EmptyState as EmptyState$2, VStack, Alert, Card, Group, InputElement, Tooltip as Tooltip$1, Icon, List, Table as Table$1, Checkbox as Checkbox$1, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1,
|
|
2
|
+
import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, Tag as Tag$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, CheckboxCard as CheckboxCard$1, Image, EmptyState as EmptyState$2, VStack, Alert, Card, Group, InputElement, Tooltip as Tooltip$1, Icon, List, Table as Table$1, Checkbox as Checkbox$1, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, Field as Field$1, Popover, NumberInput, Show, RadioCard, CheckboxGroup, Center, Heading } from '@chakra-ui/react';
|
|
3
3
|
import { AiOutlineColumnWidth } from 'react-icons/ai';
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import React__default, { createContext, useContext, useState, useEffect, useRef, forwardRef } from 'react';
|
|
6
|
-
import { LuX, LuCheck, LuChevronRight
|
|
6
|
+
import { LuX, LuCheck, LuChevronRight } from 'react-icons/lu';
|
|
7
7
|
import { MdOutlineSort, MdFilterAlt, MdSearch, MdOutlineViewColumn, MdFilterListAlt, MdPushPin, MdCancel, MdClear, MdOutlineChecklist, MdDateRange } from 'react-icons/md';
|
|
8
8
|
import { FaUpDown, FaGripLinesVertical, FaTrash } from 'react-icons/fa6';
|
|
9
9
|
import { BiDownArrow, BiUpArrow, BiError } from 'react-icons/bi';
|
|
@@ -30,7 +30,6 @@ import axios from 'axios';
|
|
|
30
30
|
import { FormProvider, useFormContext, useForm as useForm$1 } from 'react-hook-form';
|
|
31
31
|
import Ajv from 'ajv';
|
|
32
32
|
import addFormats from 'ajv-formats';
|
|
33
|
-
import addErrors from 'ajv-errors';
|
|
34
33
|
import dayjs from 'dayjs';
|
|
35
34
|
import utc from 'dayjs/plugin/utc';
|
|
36
35
|
import timezone from 'dayjs/plugin/timezone';
|
|
@@ -3644,16 +3643,6 @@ const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
|
|
|
3644
3643
|
})] }));
|
|
3645
3644
|
};
|
|
3646
3645
|
|
|
3647
|
-
const AccordionItemTrigger = React.forwardRef(function AccordionItemTrigger(props, ref) {
|
|
3648
|
-
const { children, indicatorPlacement = "end", ...rest } = props;
|
|
3649
|
-
return (jsxs(Accordion.ItemTrigger, { ...rest, ref: ref, children: [indicatorPlacement === "start" && (jsx(Accordion.ItemIndicator, { rotate: { base: "-90deg", _open: "0deg" }, children: jsx(LuChevronDown, {}) })), jsx(HStack, { gap: "4", flex: "1", textAlign: "start", width: "full", children: children }), indicatorPlacement === "end" && (jsx(Accordion.ItemIndicator, { children: jsx(LuChevronDown, {}) }))] }));
|
|
3650
|
-
});
|
|
3651
|
-
const AccordionItemContent = React.forwardRef(function AccordionItemContent(props, ref) {
|
|
3652
|
-
return (jsx(Accordion.ItemContent, { children: jsx(Accordion.ItemBody, { ...props, ref: ref }) }));
|
|
3653
|
-
});
|
|
3654
|
-
const AccordionRoot = Accordion.Root;
|
|
3655
|
-
const AccordionItem = Accordion.Item;
|
|
3656
|
-
|
|
3657
3646
|
//@ts-expect-error TODO: find appropriate type
|
|
3658
3647
|
const SchemaFormContext = createContext({
|
|
3659
3648
|
schema: {},
|
|
@@ -3671,6 +3660,9 @@ const SchemaFormContext = createContext({
|
|
|
3671
3660
|
showResetButton: true,
|
|
3672
3661
|
showTitle: true,
|
|
3673
3662
|
},
|
|
3663
|
+
requireConfirmation: false,
|
|
3664
|
+
onFormSubmit: async () => { },
|
|
3665
|
+
ajvResolver: async () => ({ values: {}, errors: {} }),
|
|
3674
3666
|
});
|
|
3675
3667
|
|
|
3676
3668
|
const useSchemaContext = () => {
|
|
@@ -3687,7 +3679,6 @@ const validateData = (data, schema) => {
|
|
|
3687
3679
|
allErrors: true,
|
|
3688
3680
|
});
|
|
3689
3681
|
addFormats(ajv);
|
|
3690
|
-
addErrors(ajv);
|
|
3691
3682
|
const validate = ajv.compile(schema);
|
|
3692
3683
|
const validationResult = validate(data);
|
|
3693
3684
|
const errors = validate.errors;
|
|
@@ -3699,6 +3690,185 @@ const validateData = (data, schema) => {
|
|
|
3699
3690
|
};
|
|
3700
3691
|
};
|
|
3701
3692
|
|
|
3693
|
+
/**
|
|
3694
|
+
* Gets the schema node for a field by following the path from root schema
|
|
3695
|
+
*/
|
|
3696
|
+
const getSchemaNodeForField = (schema, fieldPath) => {
|
|
3697
|
+
if (!fieldPath || fieldPath === '') {
|
|
3698
|
+
return schema;
|
|
3699
|
+
}
|
|
3700
|
+
const pathParts = fieldPath.split('.');
|
|
3701
|
+
let currentSchema = schema;
|
|
3702
|
+
for (const part of pathParts) {
|
|
3703
|
+
if (currentSchema &&
|
|
3704
|
+
currentSchema.properties &&
|
|
3705
|
+
currentSchema.properties[part] &&
|
|
3706
|
+
typeof currentSchema.properties[part] === 'object' &&
|
|
3707
|
+
currentSchema.properties[part] !== null) {
|
|
3708
|
+
currentSchema = currentSchema.properties[part];
|
|
3709
|
+
}
|
|
3710
|
+
else {
|
|
3711
|
+
return undefined;
|
|
3712
|
+
}
|
|
3713
|
+
}
|
|
3714
|
+
return currentSchema;
|
|
3715
|
+
};
|
|
3716
|
+
/**
|
|
3717
|
+
* Converts AJV error objects to react-hook-form field errors format
|
|
3718
|
+
*/
|
|
3719
|
+
const convertAjvErrorsToFieldErrors = (errors, schema) => {
|
|
3720
|
+
if (!errors || errors.length === 0) {
|
|
3721
|
+
return {};
|
|
3722
|
+
}
|
|
3723
|
+
const fieldErrors = {};
|
|
3724
|
+
errors.forEach((error) => {
|
|
3725
|
+
let fieldName = '';
|
|
3726
|
+
// Special handling for required keyword: map to the specific missing property
|
|
3727
|
+
if (error.keyword === 'required') {
|
|
3728
|
+
const basePath = (error.instancePath || '')
|
|
3729
|
+
.replace(/^\//, '')
|
|
3730
|
+
.replace(/\//g, '.');
|
|
3731
|
+
const missingProperty = (error.params &&
|
|
3732
|
+
error.params.missingProperty);
|
|
3733
|
+
if (missingProperty) {
|
|
3734
|
+
fieldName = basePath
|
|
3735
|
+
? `${basePath}.${missingProperty}`
|
|
3736
|
+
: missingProperty;
|
|
3737
|
+
}
|
|
3738
|
+
else {
|
|
3739
|
+
// Fallback to schemaPath conversion if missingProperty is unavailable
|
|
3740
|
+
fieldName = (error.schemaPath || '')
|
|
3741
|
+
.replace(/^#\//, '#.')
|
|
3742
|
+
.replace(/\//g, '.');
|
|
3743
|
+
}
|
|
3744
|
+
}
|
|
3745
|
+
else {
|
|
3746
|
+
const fieldPath = error.instancePath || error.schemaPath;
|
|
3747
|
+
if (fieldPath) {
|
|
3748
|
+
fieldName = fieldPath.replace(/^\//, '').replace(/\//g, '.');
|
|
3749
|
+
}
|
|
3750
|
+
}
|
|
3751
|
+
if (fieldName) {
|
|
3752
|
+
// Get the schema node for this field to check for custom error messages
|
|
3753
|
+
const fieldSchema = getSchemaNodeForField(schema, fieldName);
|
|
3754
|
+
const customMessage = fieldSchema?.errorMessages?.[error.keyword];
|
|
3755
|
+
// Provide helpful fallback message if no custom message is provided
|
|
3756
|
+
const fallbackMessage = customMessage ||
|
|
3757
|
+
`Missing error message for ${error.keyword}. Add errorMessages.${error.keyword} to schema for field '${fieldName}'`;
|
|
3758
|
+
if (error.keyword === 'required') {
|
|
3759
|
+
// Required errors override any existing non-required errors for this field
|
|
3760
|
+
fieldErrors[fieldName] = {
|
|
3761
|
+
type: 'required',
|
|
3762
|
+
keyword: error.keyword,
|
|
3763
|
+
params: error.params,
|
|
3764
|
+
message: fallbackMessage,
|
|
3765
|
+
};
|
|
3766
|
+
}
|
|
3767
|
+
else {
|
|
3768
|
+
const existing = fieldErrors[fieldName];
|
|
3769
|
+
if (existing) {
|
|
3770
|
+
// Do not override required errors
|
|
3771
|
+
if (existing.type === 'required') {
|
|
3772
|
+
return;
|
|
3773
|
+
}
|
|
3774
|
+
// Combine messages if multiple errors for same field
|
|
3775
|
+
existing.message = existing.message
|
|
3776
|
+
? `${existing.message}; ${fallbackMessage}`
|
|
3777
|
+
: fallbackMessage;
|
|
3778
|
+
}
|
|
3779
|
+
else {
|
|
3780
|
+
fieldErrors[fieldName] = {
|
|
3781
|
+
type: error.keyword,
|
|
3782
|
+
keyword: error.keyword,
|
|
3783
|
+
params: error.params,
|
|
3784
|
+
message: fallbackMessage,
|
|
3785
|
+
};
|
|
3786
|
+
}
|
|
3787
|
+
}
|
|
3788
|
+
}
|
|
3789
|
+
});
|
|
3790
|
+
return fieldErrors;
|
|
3791
|
+
};
|
|
3792
|
+
/**
|
|
3793
|
+
* AJV resolver for react-hook-form
|
|
3794
|
+
* Integrates AJV validation with react-hook-form's validation system
|
|
3795
|
+
*/
|
|
3796
|
+
/**
|
|
3797
|
+
* Strips null, undefined, and empty string values from an object
|
|
3798
|
+
*/
|
|
3799
|
+
const stripEmptyValues = (obj) => {
|
|
3800
|
+
if (obj === null || obj === undefined) {
|
|
3801
|
+
return undefined;
|
|
3802
|
+
}
|
|
3803
|
+
if (typeof obj === 'string' && obj.trim() === '') {
|
|
3804
|
+
return undefined;
|
|
3805
|
+
}
|
|
3806
|
+
if (Array.isArray(obj)) {
|
|
3807
|
+
const filtered = obj
|
|
3808
|
+
.map(stripEmptyValues)
|
|
3809
|
+
.filter((item) => item !== undefined);
|
|
3810
|
+
return filtered.length > 0 ? filtered : undefined;
|
|
3811
|
+
}
|
|
3812
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
3813
|
+
const result = {};
|
|
3814
|
+
let hasValues = false;
|
|
3815
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
3816
|
+
const cleanedValue = stripEmptyValues(value);
|
|
3817
|
+
if (cleanedValue !== undefined) {
|
|
3818
|
+
result[key] = cleanedValue;
|
|
3819
|
+
hasValues = true;
|
|
3820
|
+
}
|
|
3821
|
+
}
|
|
3822
|
+
return hasValues ? result : undefined;
|
|
3823
|
+
}
|
|
3824
|
+
return obj;
|
|
3825
|
+
};
|
|
3826
|
+
const ajvResolver = (schema) => {
|
|
3827
|
+
return async (values) => {
|
|
3828
|
+
try {
|
|
3829
|
+
// Strip empty values before validation
|
|
3830
|
+
const cleanedValues = stripEmptyValues(values);
|
|
3831
|
+
// Use empty object for validation if all values were stripped
|
|
3832
|
+
const valuesToValidate = cleanedValues === undefined ? {} : cleanedValues;
|
|
3833
|
+
const { isValid, errors } = validateData(valuesToValidate, schema);
|
|
3834
|
+
console.debug('AJV Validation Result:', {
|
|
3835
|
+
isValid,
|
|
3836
|
+
errors,
|
|
3837
|
+
cleanedValues,
|
|
3838
|
+
valuesToValidate,
|
|
3839
|
+
});
|
|
3840
|
+
if (isValid) {
|
|
3841
|
+
return {
|
|
3842
|
+
values: (cleanedValues || {}),
|
|
3843
|
+
errors: {},
|
|
3844
|
+
};
|
|
3845
|
+
}
|
|
3846
|
+
const fieldErrors = convertAjvErrorsToFieldErrors(errors, schema);
|
|
3847
|
+
console.debug('AJV Validation Failed:', {
|
|
3848
|
+
errors,
|
|
3849
|
+
fieldErrors,
|
|
3850
|
+
cleanedValues,
|
|
3851
|
+
valuesToValidate,
|
|
3852
|
+
});
|
|
3853
|
+
return {
|
|
3854
|
+
values: {},
|
|
3855
|
+
errors: fieldErrors,
|
|
3856
|
+
};
|
|
3857
|
+
}
|
|
3858
|
+
catch (error) {
|
|
3859
|
+
return {
|
|
3860
|
+
values: {},
|
|
3861
|
+
errors: {
|
|
3862
|
+
root: {
|
|
3863
|
+
type: 'validation',
|
|
3864
|
+
message: error instanceof Error ? error.message : 'Validation failed',
|
|
3865
|
+
},
|
|
3866
|
+
},
|
|
3867
|
+
};
|
|
3868
|
+
}
|
|
3869
|
+
};
|
|
3870
|
+
};
|
|
3871
|
+
|
|
3702
3872
|
const idPickerSanityCheck = (column, foreign_key) => {
|
|
3703
3873
|
if (!!foreign_key == false) {
|
|
3704
3874
|
throw new Error(`The key foreign_key does not exist in properties of column ${column} when using id-picker.`);
|
|
@@ -3718,13 +3888,61 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
3718
3888
|
showSubmitButton: true,
|
|
3719
3889
|
showResetButton: true,
|
|
3720
3890
|
showTitle: true,
|
|
3721
|
-
}, dateTimePickerLabels, idPickerLabels, enumPickerLabels, }) => {
|
|
3891
|
+
}, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, }) => {
|
|
3722
3892
|
const [isSuccess, setIsSuccess] = useState(false);
|
|
3723
3893
|
const [isError, setIsError] = useState(false);
|
|
3724
3894
|
const [isSubmiting, setIsSubmiting] = useState(false);
|
|
3725
3895
|
const [isConfirming, setIsConfirming] = useState(false);
|
|
3726
3896
|
const [validatedData, setValidatedData] = useState();
|
|
3727
3897
|
const [error, setError] = useState();
|
|
3898
|
+
const onBeforeSubmit = () => {
|
|
3899
|
+
setIsSubmiting(true);
|
|
3900
|
+
};
|
|
3901
|
+
const onAfterSubmit = () => {
|
|
3902
|
+
setIsSubmiting(false);
|
|
3903
|
+
};
|
|
3904
|
+
const onSubmitError = (error) => {
|
|
3905
|
+
setIsError(true);
|
|
3906
|
+
setError(error);
|
|
3907
|
+
};
|
|
3908
|
+
const onSubmitSuccess = () => {
|
|
3909
|
+
setIsSuccess(true);
|
|
3910
|
+
};
|
|
3911
|
+
const defaultOnSubmit = async (promise) => {
|
|
3912
|
+
try {
|
|
3913
|
+
console.log('onBeforeSubmit');
|
|
3914
|
+
onBeforeSubmit();
|
|
3915
|
+
await promise;
|
|
3916
|
+
console.log('onSubmitSuccess');
|
|
3917
|
+
onSubmitSuccess();
|
|
3918
|
+
}
|
|
3919
|
+
catch (error) {
|
|
3920
|
+
console.log('onSubmitError', error);
|
|
3921
|
+
onSubmitError(error);
|
|
3922
|
+
}
|
|
3923
|
+
finally {
|
|
3924
|
+
onAfterSubmit();
|
|
3925
|
+
}
|
|
3926
|
+
};
|
|
3927
|
+
const defaultSubmitPromise = (data) => {
|
|
3928
|
+
const options = {
|
|
3929
|
+
method: 'POST',
|
|
3930
|
+
url: `${serverUrl}`,
|
|
3931
|
+
data: clearEmptyString(data),
|
|
3932
|
+
...requestOptions,
|
|
3933
|
+
};
|
|
3934
|
+
return axios.request(options);
|
|
3935
|
+
};
|
|
3936
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3937
|
+
const onFormSubmit = async (data) => {
|
|
3938
|
+
// AJV validation is now handled by react-hook-form resolver
|
|
3939
|
+
// This function will only be called if validation passes
|
|
3940
|
+
if (onSubmit === undefined) {
|
|
3941
|
+
await defaultOnSubmit(Promise.resolve(defaultSubmitPromise(data)));
|
|
3942
|
+
return;
|
|
3943
|
+
}
|
|
3944
|
+
await defaultOnSubmit(Promise.resolve(onSubmit(data)));
|
|
3945
|
+
};
|
|
3728
3946
|
return (jsx(SchemaFormContext.Provider, { value: {
|
|
3729
3947
|
schema,
|
|
3730
3948
|
serverUrl,
|
|
@@ -3754,9 +3972,12 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
3754
3972
|
customErrorRenderer,
|
|
3755
3973
|
customSuccessRenderer,
|
|
3756
3974
|
displayConfig,
|
|
3975
|
+
requireConfirmation,
|
|
3976
|
+
onFormSubmit,
|
|
3757
3977
|
dateTimePickerLabels,
|
|
3758
3978
|
idPickerLabels,
|
|
3759
3979
|
enumPickerLabels,
|
|
3980
|
+
ajvResolver: ajvResolver(schema),
|
|
3760
3981
|
}, children: jsx(FormProvider, { ...form, children: children }) }));
|
|
3761
3982
|
};
|
|
3762
3983
|
|
|
@@ -3802,20 +4023,22 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
|
|
|
3802
4023
|
|
|
3803
4024
|
const Field = React.forwardRef(function Field(props, ref) {
|
|
3804
4025
|
const { label, children, helperText, errorText, optionalText, ...rest } = props;
|
|
3805
|
-
return (jsxs(Field$1.Root, { ref: ref, ...rest, children: [label && (jsxs(Field$1.Label, { children: [label, jsx(Field$1.RequiredIndicator, { fallback: optionalText })] })), children, helperText && (jsx(Field$1.HelperText, { children: helperText })), errorText && (
|
|
4026
|
+
return (jsxs(Field$1.Root, { ref: ref, ...rest, children: [label && (jsxs(Field$1.Label, { children: [label, jsx(Field$1.RequiredIndicator, { color: rest.invalid && rest.required ? 'red.500' : undefined, fallback: optionalText })] })), children, helperText && (jsx(Field$1.HelperText, { children: helperText })), !!errorText && (jsxs(Field$1.ErrorText, { children: [rest.required && rest.invalid && (jsx("span", { style: { color: 'var(--chakra-colors-red-500)' }, children: "* " })), errorText] }))] }));
|
|
3806
4027
|
});
|
|
3807
4028
|
|
|
3808
4029
|
const BooleanPicker = ({ schema, column, prefix }) => {
|
|
3809
4030
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
3810
4031
|
const { translate } = useSchemaContext();
|
|
3811
|
-
const { required, gridColumn =
|
|
4032
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
3812
4033
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
3813
4034
|
const colLabel = `${prefix}${column}`;
|
|
3814
4035
|
const value = watch(colLabel);
|
|
3815
|
-
return (
|
|
3816
|
-
gridRow,
|
|
3817
|
-
|
|
3818
|
-
|
|
4036
|
+
return (jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4037
|
+
gridRow, errorText: errors[`${colLabel}`]
|
|
4038
|
+
? translate.t(removeIndex(`${colLabel}.field_required`))
|
|
4039
|
+
: undefined, invalid: !!errors[colLabel], children: jsx(CheckboxCard, { checked: value, variant: 'surface', onChange: () => {
|
|
4040
|
+
setValue(colLabel, !value);
|
|
4041
|
+
} }) }));
|
|
3819
4042
|
};
|
|
3820
4043
|
|
|
3821
4044
|
const CustomInput = ({ column, schema, prefix }) => {
|
|
@@ -4048,83 +4271,83 @@ const DatePicker = ({ column, schema, prefix }) => {
|
|
|
4048
4271
|
console.error(e);
|
|
4049
4272
|
}
|
|
4050
4273
|
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
4051
|
-
return (
|
|
4052
|
-
gridRow, children:
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4274
|
+
return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4275
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
4276
|
+
setOpen(true);
|
|
4277
|
+
}, justifyContent: 'start', children: [jsx(MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ''] }) }), jsx(PopoverContent, { children: jsxs(PopoverBody, { children: [jsx(PopoverTitle, {}), jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
|
|
4278
|
+
setValue(colLabel, dayjs(date).format(dateFormat));
|
|
4279
|
+
setOpen(false);
|
|
4280
|
+
}, labels: {
|
|
4281
|
+
monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
|
|
4282
|
+
formI18n.translate.t(`common.month_1`, {
|
|
4283
|
+
defaultValue: 'January',
|
|
4284
|
+
}),
|
|
4285
|
+
formI18n.translate.t(`common.month_2`, {
|
|
4286
|
+
defaultValue: 'February',
|
|
4287
|
+
}),
|
|
4288
|
+
formI18n.translate.t(`common.month_3`, {
|
|
4289
|
+
defaultValue: 'March',
|
|
4290
|
+
}),
|
|
4291
|
+
formI18n.translate.t(`common.month_4`, {
|
|
4292
|
+
defaultValue: 'April',
|
|
4293
|
+
}),
|
|
4294
|
+
formI18n.translate.t(`common.month_5`, {
|
|
4295
|
+
defaultValue: 'May',
|
|
4296
|
+
}),
|
|
4297
|
+
formI18n.translate.t(`common.month_6`, {
|
|
4298
|
+
defaultValue: 'June',
|
|
4299
|
+
}),
|
|
4300
|
+
formI18n.translate.t(`common.month_7`, {
|
|
4301
|
+
defaultValue: 'July',
|
|
4302
|
+
}),
|
|
4303
|
+
formI18n.translate.t(`common.month_8`, {
|
|
4304
|
+
defaultValue: 'August',
|
|
4305
|
+
}),
|
|
4306
|
+
formI18n.translate.t(`common.month_9`, {
|
|
4307
|
+
defaultValue: 'September',
|
|
4308
|
+
}),
|
|
4309
|
+
formI18n.translate.t(`common.month_10`, {
|
|
4310
|
+
defaultValue: 'October',
|
|
4311
|
+
}),
|
|
4312
|
+
formI18n.translate.t(`common.month_11`, {
|
|
4313
|
+
defaultValue: 'November',
|
|
4314
|
+
}),
|
|
4315
|
+
formI18n.translate.t(`common.month_12`, {
|
|
4316
|
+
defaultValue: 'December',
|
|
4317
|
+
}),
|
|
4318
|
+
],
|
|
4319
|
+
weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
|
|
4320
|
+
formI18n.translate.t(`common.weekday_1`, {
|
|
4321
|
+
defaultValue: 'Sun',
|
|
4322
|
+
}),
|
|
4323
|
+
formI18n.translate.t(`common.weekday_2`, {
|
|
4324
|
+
defaultValue: 'Mon',
|
|
4325
|
+
}),
|
|
4326
|
+
formI18n.translate.t(`common.weekday_3`, {
|
|
4327
|
+
defaultValue: 'Tue',
|
|
4328
|
+
}),
|
|
4329
|
+
formI18n.translate.t(`common.weekday_4`, {
|
|
4330
|
+
defaultValue: 'Wed',
|
|
4331
|
+
}),
|
|
4332
|
+
formI18n.translate.t(`common.weekday_5`, {
|
|
4333
|
+
defaultValue: 'Thu',
|
|
4334
|
+
}),
|
|
4335
|
+
formI18n.translate.t(`common.weekday_6`, {
|
|
4336
|
+
defaultValue: 'Fri',
|
|
4337
|
+
}),
|
|
4338
|
+
formI18n.translate.t(`common.weekday_7`, {
|
|
4339
|
+
defaultValue: 'Sat',
|
|
4340
|
+
}),
|
|
4341
|
+
],
|
|
4342
|
+
backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
|
|
4343
|
+
formI18n.translate.t(`common.back_button`, {
|
|
4344
|
+
defaultValue: 'Back',
|
|
4345
|
+
}),
|
|
4346
|
+
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
|
|
4347
|
+
formI18n.translate.t(`common.forward_button`, {
|
|
4348
|
+
defaultValue: 'Forward',
|
|
4349
|
+
}),
|
|
4350
|
+
} })] }) })] }) }));
|
|
4128
4351
|
};
|
|
4129
4352
|
|
|
4130
4353
|
function filterArray(array, searchTerm) {
|
|
@@ -4159,7 +4382,9 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
|
|
|
4159
4382
|
};
|
|
4160
4383
|
if (variant === 'radio') {
|
|
4161
4384
|
return (jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4162
|
-
gridRow,
|
|
4385
|
+
gridRow, errorText: errors[`${colLabel}`]
|
|
4386
|
+
? translate.t(removeIndex(`${colLabel}.field_required`))
|
|
4387
|
+
: undefined, invalid: !!errors[colLabel], children: jsx(RadioGroup$1.Root, { defaultValue: "1", children: jsx(HStack, { gap: "6", children: filterArray(dataList, searchText ?? '').map((item) => {
|
|
4163
4388
|
return (jsxs(RadioGroup$1.Item, { onClick: () => {
|
|
4164
4389
|
if (!isMultiple) {
|
|
4165
4390
|
setOpenSearchResult(false);
|
|
@@ -4174,7 +4399,9 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
|
|
|
4174
4399
|
}) }) }) }));
|
|
4175
4400
|
}
|
|
4176
4401
|
return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4177
|
-
gridRow,
|
|
4402
|
+
gridRow, errorText: errors[`${colLabel}`]
|
|
4403
|
+
? translate.t(removeIndex(`${colLabel}.field_required`))
|
|
4404
|
+
: undefined, invalid: !!errors[colLabel], children: [isMultiple && (jsxs(Flex, { flexFlow: 'wrap', gap: 1, children: [watchEnums.map((enumValue) => {
|
|
4178
4405
|
const item = enumValue;
|
|
4179
4406
|
if (!!item === false) {
|
|
4180
4407
|
return jsx(Fragment, {});
|
|
@@ -4229,7 +4456,7 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
|
|
|
4229
4456
|
? renderDisplay(item)
|
|
4230
4457
|
: translate.t(removeIndex(`${colLabel}.${item}`)) }, `${colLabel}-${item}`));
|
|
4231
4458
|
}) }), isDirty && (jsx(Fragment, { children: dataList.length <= 0 && (jsx(Fragment, { children: enumPickerLabels?.emptySearchResult ??
|
|
4232
|
-
translate.t(removeIndex(`${colLabel}.empty_search_result`)) })) }))] })] }) })] })
|
|
4459
|
+
translate.t(removeIndex(`${colLabel}.empty_search_result`)) })) }))] })] }) })] })] }));
|
|
4233
4460
|
};
|
|
4234
4461
|
|
|
4235
4462
|
function isEnteringWindow(_ref) {
|
|
@@ -4587,20 +4814,22 @@ const FileDropzone = ({ children = undefined, gridProps = {}, onDrop = () => { }
|
|
|
4587
4814
|
const FilePicker = ({ column, schema, prefix }) => {
|
|
4588
4815
|
const { setValue, formState: { errors }, watch, } = useFormContext();
|
|
4589
4816
|
const { translate } = useSchemaContext();
|
|
4590
|
-
const { required, gridColumn =
|
|
4817
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', } = schema;
|
|
4591
4818
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4592
4819
|
const currentFiles = (watch(column) ?? []);
|
|
4593
4820
|
const colLabel = `${prefix}${column}`;
|
|
4594
|
-
return (jsxs(Field, { label: `${translate.t(`${colLabel}.field_label`)}`, required: isRequired, gridColumn: gridColumn ??
|
|
4821
|
+
return (jsxs(Field, { label: `${translate.t(`${colLabel}.field_label`)}`, required: isRequired, gridColumn: gridColumn ?? 'span 4', gridRow: gridRow ?? 'span 1', display: 'grid', gridTemplateRows: 'auto 1fr auto', alignItems: 'stretch', errorText: errors[`${colLabel}`]
|
|
4822
|
+
? translate.t(removeIndex(`${colLabel}.field_required`))
|
|
4823
|
+
: undefined, invalid: !!errors[colLabel], children: [jsx(FileDropzone, { onDrop: ({ files }) => {
|
|
4595
4824
|
const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => cur.name === name));
|
|
4596
4825
|
setValue(colLabel, [...currentFiles, ...newFiles]);
|
|
4597
|
-
}, placeholder: translate.t(removeIndex(`${colLabel}.fileDropzone`)) }), jsx(Flex, { flexFlow:
|
|
4598
|
-
return (jsx(Card.Root, { variant:
|
|
4826
|
+
}, placeholder: translate.t(removeIndex(`${colLabel}.fileDropzone`)) }), jsx(Flex, { flexFlow: 'column', gap: 1, children: currentFiles.map((file) => {
|
|
4827
|
+
return (jsx(Card.Root, { variant: 'subtle', children: jsxs(Card.Body, { gap: "2", cursor: 'pointer', onClick: () => {
|
|
4599
4828
|
setValue(column, currentFiles.filter(({ name }) => {
|
|
4600
4829
|
return name !== file.name;
|
|
4601
4830
|
}));
|
|
4602
|
-
}, display:
|
|
4603
|
-
}) })
|
|
4831
|
+
}, display: 'flex', flexFlow: 'row', alignItems: 'center', padding: '2', children: [file.type.startsWith('image/') && (jsx(Image, { src: URL.createObjectURL(file), alt: file.name, boxSize: "50px", objectFit: "cover", borderRadius: "md", marginRight: "2" })), jsx(Box, { children: file.name }), jsx(TiDeleteOutline, {})] }) }, file.name));
|
|
4832
|
+
}) })] }));
|
|
4604
4833
|
};
|
|
4605
4834
|
|
|
4606
4835
|
const ToggleTip = React.forwardRef(function ToggleTip(props, ref) {
|
|
@@ -4789,7 +5018,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4789
5018
|
return record[display_column];
|
|
4790
5019
|
};
|
|
4791
5020
|
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4792
|
-
gridRow, children: [isMultiple && (jsxs(Flex, { flexFlow: 'wrap', gap: 1, children: [watchIds.map((id) => {
|
|
5021
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [isMultiple && (jsxs(Flex, { flexFlow: 'wrap', gap: 1, children: [watchIds.map((id) => {
|
|
4793
5022
|
const item = idMap[id];
|
|
4794
5023
|
if (item === undefined) {
|
|
4795
5024
|
return (jsx(Text, { children: idPickerLabels?.undefined ?? formI18n.t('undefined') }, id));
|
|
@@ -4840,7 +5069,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4840
5069
|
? idPickerLabels?.emptySearchResult ??
|
|
4841
5070
|
formI18n.t('empty_search_result')
|
|
4842
5071
|
: idPickerLabels?.initialResults ??
|
|
4843
|
-
formI18n.t('initial_results') })) }), jsx(PaginationRoot, { justifySelf: 'center', count: count, pageSize: limit, defaultPage: 1, page: page + 1, onPageChange: (e) => setPage(e.page - 1), children: jsxs(HStack, { gap: "4", children: [jsx(PaginationPrevTrigger, {}), count > 0 && jsx(PaginationPageText, {}), jsx(PaginationNextTrigger, {})] }) })] }))] }) })] })
|
|
5072
|
+
formI18n.t('initial_results') })) }), jsx(PaginationRoot, { justifySelf: 'center', count: count, pageSize: limit, defaultPage: 1, page: page + 1, onPageChange: (e) => setPage(e.page - 1), children: jsxs(HStack, { gap: "4", children: [jsx(PaginationPrevTrigger, {}), count > 0 && jsx(PaginationPageText, {}), jsx(PaginationNextTrigger, {})] }) })] }))] }) })] })] }));
|
|
4844
5073
|
};
|
|
4845
5074
|
|
|
4846
5075
|
const NumberInputRoot = React.forwardRef(function NumberInput$1(props, ref) {
|
|
@@ -4851,20 +5080,84 @@ const NumberInputField$1 = NumberInput.Input;
|
|
|
4851
5080
|
NumberInput.Scrubber;
|
|
4852
5081
|
NumberInput.Label;
|
|
4853
5082
|
|
|
5083
|
+
/**
|
|
5084
|
+
* Gets the error message for a specific field from react-hook-form errors
|
|
5085
|
+
* Prioritizes required errors (#.required) over field-specific validation errors
|
|
5086
|
+
*/
|
|
5087
|
+
const getFieldError = (errors, fieldName) => {
|
|
5088
|
+
// Check for form-level required errors first (highest priority)
|
|
5089
|
+
const requiredError = errors['#.required'];
|
|
5090
|
+
if (requiredError) {
|
|
5091
|
+
const requiredErrorMessage = extractErrorMessage(requiredError);
|
|
5092
|
+
if (requiredErrorMessage) {
|
|
5093
|
+
return requiredErrorMessage;
|
|
5094
|
+
}
|
|
5095
|
+
}
|
|
5096
|
+
// If no required errors, return field-specific error
|
|
5097
|
+
const fieldError = errors[fieldName];
|
|
5098
|
+
if (fieldError) {
|
|
5099
|
+
const fieldErrorMessage = extractErrorMessage(fieldError);
|
|
5100
|
+
if (fieldErrorMessage) {
|
|
5101
|
+
return fieldErrorMessage;
|
|
5102
|
+
}
|
|
5103
|
+
}
|
|
5104
|
+
return undefined;
|
|
5105
|
+
};
|
|
5106
|
+
/**
|
|
5107
|
+
* Helper function to extract error message from various error formats
|
|
5108
|
+
* Only returns message if explicitly provided, no fallback text
|
|
5109
|
+
*/
|
|
5110
|
+
const extractErrorMessage = (error) => {
|
|
5111
|
+
if (!error) {
|
|
5112
|
+
return undefined;
|
|
5113
|
+
}
|
|
5114
|
+
// If it's a simple string error
|
|
5115
|
+
if (typeof error === 'string') {
|
|
5116
|
+
return error;
|
|
5117
|
+
}
|
|
5118
|
+
// If it's an error object with a message property
|
|
5119
|
+
if (error && typeof error === 'object' && 'message' in error) {
|
|
5120
|
+
return error.message;
|
|
5121
|
+
}
|
|
5122
|
+
// If it's an array of errors, get the first one
|
|
5123
|
+
if (Array.isArray(error) && error.length > 0) {
|
|
5124
|
+
const firstError = error[0];
|
|
5125
|
+
if (typeof firstError === 'string') {
|
|
5126
|
+
return firstError;
|
|
5127
|
+
}
|
|
5128
|
+
if (firstError &&
|
|
5129
|
+
typeof firstError === 'object' &&
|
|
5130
|
+
'message' in firstError) {
|
|
5131
|
+
return firstError.message;
|
|
5132
|
+
}
|
|
5133
|
+
}
|
|
5134
|
+
// No fallback - return undefined if no message provided
|
|
5135
|
+
return undefined;
|
|
5136
|
+
};
|
|
5137
|
+
|
|
4854
5138
|
const NumberInputField = ({ schema, column, prefix, }) => {
|
|
4855
5139
|
const { setValue, formState: { errors }, watch, } = useFormContext();
|
|
4856
5140
|
const { translate } = useSchemaContext();
|
|
4857
|
-
const { required, gridColumn =
|
|
5141
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', numberStorageType = 'number', } = schema;
|
|
4858
5142
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4859
5143
|
const colLabel = `${prefix}${column}`;
|
|
4860
5144
|
const value = watch(`${colLabel}`);
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
5145
|
+
const fieldError = getFieldError(errors, colLabel);
|
|
5146
|
+
return (jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, errorText: fieldError
|
|
5147
|
+
? fieldError.includes('required')
|
|
5148
|
+
? translate.t(removeIndex(`${colLabel}.field_required`))
|
|
5149
|
+
: fieldError
|
|
5150
|
+
: undefined, invalid: !!fieldError, children: jsx(NumberInputRoot, { value: value, onValueChange: (details) => {
|
|
5151
|
+
// Store as string or number based on configuration, default to number
|
|
5152
|
+
const value = numberStorageType === 'string'
|
|
5153
|
+
? details.value
|
|
5154
|
+
: details.valueAsNumber;
|
|
5155
|
+
setValue(`${colLabel}`, value);
|
|
5156
|
+
}, min: schema.minimum, max: schema.maximum, step: schema.multipleOf || 0.01, allowOverflow: false, clampValueOnBlur: false, inputMode: "decimal", formatOptions: schema.formatOptions, children: jsx(NumberInputField$1, { required: isRequired }) }) }));
|
|
4864
5157
|
};
|
|
4865
5158
|
|
|
4866
5159
|
const ObjectInput = ({ schema, column, prefix }) => {
|
|
4867
|
-
const { properties, gridColumn =
|
|
5160
|
+
const { properties, gridColumn = 'span 12', gridRow = 'span 1', required, showLabel = true, } = schema;
|
|
4868
5161
|
const { translate } = useSchemaContext();
|
|
4869
5162
|
const colLabel = `${prefix}${column}`;
|
|
4870
5163
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
@@ -4872,29 +5165,32 @@ const ObjectInput = ({ schema, column, prefix }) => {
|
|
|
4872
5165
|
if (properties === undefined) {
|
|
4873
5166
|
throw new Error(`properties is undefined when using ObjectInput`);
|
|
4874
5167
|
}
|
|
4875
|
-
return (jsxs(Box, { gridRow, gridColumn, children: [showLabel && (jsxs(Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsx("span", { children: "*" })] })), jsx(Grid, { bgColor: { base:
|
|
4876
|
-
base:
|
|
4877
|
-
_dark:
|
|
4878
|
-
}, gap: "4", padding:
|
|
5168
|
+
return (jsxs(Box, { gridRow, gridColumn, children: [showLabel && (jsxs(Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsx("span", { children: "*" })] })), jsx(Grid, { bgColor: { base: 'colorPalette.100', _dark: 'colorPalette.900' }, p: 2, borderRadius: 4, borderWidth: 1, borderColor: {
|
|
5169
|
+
base: 'colorPalette.200',
|
|
5170
|
+
_dark: 'colorPalette.800',
|
|
5171
|
+
}, gap: "4", padding: '4', gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: Object.keys(properties ?? {}).map((key) => {
|
|
4879
5172
|
return (
|
|
4880
5173
|
// @ts-expect-error find suitable types
|
|
4881
5174
|
jsx(ColumnRenderer, { column: `${key}`,
|
|
4882
5175
|
prefix: `${prefix}${column}.`,
|
|
4883
|
-
properties
|
|
4884
|
-
|
|
5176
|
+
properties,
|
|
5177
|
+
parentRequired: required }, `form-${colLabel}-${key}`));
|
|
5178
|
+
}) }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
4885
5179
|
};
|
|
4886
5180
|
|
|
4887
5181
|
const RecordInput$1 = ({ column, schema, prefix }) => {
|
|
4888
5182
|
const { formState: { errors }, setValue, getValues, } = useFormContext();
|
|
4889
5183
|
const { translate } = useSchemaContext();
|
|
4890
|
-
const { required, gridColumn =
|
|
5184
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
4891
5185
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4892
5186
|
const entries = Object.entries(getValues(column) ?? {});
|
|
4893
5187
|
const [showNewEntries, setShowNewEntries] = useState(false);
|
|
4894
5188
|
const [newKey, setNewKey] = useState();
|
|
4895
5189
|
const [newValue, setNewValue] = useState();
|
|
4896
|
-
return (jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems:
|
|
4897
|
-
|
|
5190
|
+
return (jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems: 'stretch', gridColumn, gridRow, errorText: errors[`${column}`]
|
|
5191
|
+
? translate.t(`${column}.field_required`)
|
|
5192
|
+
: undefined, invalid: !!errors[column], children: [entries.map(([key, value]) => {
|
|
5193
|
+
return (jsxs(Grid, { templateColumns: '1fr 1fr auto', gap: 1, children: [jsx(Input, { value: key, onChange: (e) => {
|
|
4898
5194
|
const filtered = entries.filter(([target]) => {
|
|
4899
5195
|
return target !== key;
|
|
4900
5196
|
});
|
|
@@ -4904,17 +5200,17 @@ const RecordInput$1 = ({ column, schema, prefix }) => {
|
|
|
4904
5200
|
...getValues(column),
|
|
4905
5201
|
[key]: e.target.value,
|
|
4906
5202
|
});
|
|
4907
|
-
}, autoComplete: "off" }), jsx(IconButton, { variant:
|
|
5203
|
+
}, autoComplete: "off" }), jsx(IconButton, { variant: 'ghost', onClick: () => {
|
|
4908
5204
|
const filtered = entries.filter(([target]) => {
|
|
4909
5205
|
return target !== key;
|
|
4910
5206
|
});
|
|
4911
5207
|
setValue(column, Object.fromEntries([...filtered]));
|
|
4912
5208
|
}, children: jsx(CgClose, {}) })] }));
|
|
4913
|
-
}), jsx(Show, { when: showNewEntries, children: jsxs(Card.Root, { children: [jsx(Card.Body, { gap: "2", children: jsxs(Grid, { templateColumns:
|
|
5209
|
+
}), jsx(Show, { when: showNewEntries, children: jsxs(Card.Root, { children: [jsx(Card.Body, { gap: "2", children: jsxs(Grid, { templateColumns: '1fr 1fr auto', gap: 1, children: [jsx(Input, { value: newKey, onChange: (e) => {
|
|
4914
5210
|
setNewKey(e.target.value);
|
|
4915
5211
|
}, autoComplete: "off" }), jsx(Input, { value: newValue, onChange: (e) => {
|
|
4916
5212
|
setNewValue(e.target.value);
|
|
4917
|
-
}, autoComplete: "off" })] }) }), jsxs(Card.Footer, { justifyContent: "flex-end", children: [jsx(IconButton, { variant:
|
|
5213
|
+
}, autoComplete: "off" })] }) }), jsxs(Card.Footer, { justifyContent: "flex-end", children: [jsx(IconButton, { variant: 'subtle', onClick: () => {
|
|
4918
5214
|
setShowNewEntries(false);
|
|
4919
5215
|
setNewKey(undefined);
|
|
4920
5216
|
setNewValue(undefined);
|
|
@@ -4933,16 +5229,17 @@ const RecordInput$1 = ({ column, schema, prefix }) => {
|
|
|
4933
5229
|
setShowNewEntries(true);
|
|
4934
5230
|
setNewKey(undefined);
|
|
4935
5231
|
setNewValue(undefined);
|
|
4936
|
-
}, children: translate.t(`${column}.addNew`) })
|
|
5232
|
+
}, children: translate.t(`${column}.addNew`) })] }));
|
|
4937
5233
|
};
|
|
4938
5234
|
|
|
4939
5235
|
const StringInputField = ({ column, schema, prefix, }) => {
|
|
4940
5236
|
const { register, formState: { errors }, } = useFormContext();
|
|
4941
5237
|
const { translate } = useSchemaContext();
|
|
4942
|
-
const { required, gridColumn =
|
|
5238
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
4943
5239
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4944
5240
|
const colLabel = `${prefix}${column}`;
|
|
4945
|
-
|
|
5241
|
+
const fieldError = getFieldError(errors, colLabel);
|
|
5242
|
+
return (jsx(Fragment, { children: jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, errorText: fieldError, invalid: !!fieldError, children: jsx(Input, { ...register(`${colLabel}`, { required: isRequired }), autoComplete: "off" }) }) }));
|
|
4946
5243
|
};
|
|
4947
5244
|
|
|
4948
5245
|
const RadioCardItem = React.forwardRef(function RadioCardItem(props, ref) {
|
|
@@ -5128,13 +5425,18 @@ Textarea.displayName = "Textarea";
|
|
|
5128
5425
|
const TextAreaInput = ({ column, schema, prefix, }) => {
|
|
5129
5426
|
const { register, formState: { errors }, } = useFormContext();
|
|
5130
5427
|
const { translate } = useSchemaContext();
|
|
5131
|
-
const { required, gridColumn =
|
|
5428
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
5132
5429
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5133
5430
|
const colLabel = `${prefix}${column}`;
|
|
5134
5431
|
const form = useFormContext();
|
|
5135
5432
|
const { setValue, watch } = form;
|
|
5433
|
+
const fieldError = getFieldError(errors, colLabel);
|
|
5136
5434
|
const watchValue = watch(colLabel);
|
|
5137
|
-
return (jsx(Fragment, { children:
|
|
5435
|
+
return (jsx(Fragment, { children: jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn ?? 'span 4', gridRow: gridRow ?? 'span 1', display: "grid", errorText: fieldError
|
|
5436
|
+
? fieldError.includes('required')
|
|
5437
|
+
? translate.t(removeIndex(`${colLabel}.field_required`))
|
|
5438
|
+
: fieldError
|
|
5439
|
+
: undefined, invalid: !!fieldError, children: jsx(Textarea, { value: watchValue, onChange: (value) => setValue(colLabel, value) }) }) }));
|
|
5138
5440
|
};
|
|
5139
5441
|
|
|
5140
5442
|
function TimePicker$1({ hour, setHour, minute, setMinute, meridiem, setMeridiem, meridiemLabel = {
|
|
@@ -5265,25 +5567,25 @@ dayjs.extend(timezone);
|
|
|
5265
5567
|
const TimePicker = ({ column, schema, prefix }) => {
|
|
5266
5568
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
5267
5569
|
const { translate, timezone } = useSchemaContext();
|
|
5268
|
-
const { required, gridColumn =
|
|
5570
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', timeFormat = 'HH:mm:ssZ', displayTimeFormat = 'hh:mm A', } = schema;
|
|
5269
5571
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5270
5572
|
const colLabel = `${prefix}${column}`;
|
|
5271
5573
|
const [open, setOpen] = useState(false);
|
|
5272
5574
|
const value = watch(colLabel);
|
|
5273
5575
|
const displayedTime = dayjs(`1970-01-01T${value}`).tz(timezone).isValid()
|
|
5274
5576
|
? dayjs(`1970-01-01T${value}`).tz(timezone).format(displayTimeFormat)
|
|
5275
|
-
:
|
|
5577
|
+
: '';
|
|
5276
5578
|
// Parse the initial time parts from the time string (HH:mm:ssZ)
|
|
5277
5579
|
const parseTime = (time) => {
|
|
5278
5580
|
if (!time)
|
|
5279
|
-
return { hour: 12, minute: 0, meridiem:
|
|
5581
|
+
return { hour: 12, minute: 0, meridiem: 'am' };
|
|
5280
5582
|
const parsed = dayjs(`1970-01-01T${time}`).tz(timezone);
|
|
5281
5583
|
if (!parsed.isValid()) {
|
|
5282
|
-
return { hour: 12, minute: 0, meridiem:
|
|
5584
|
+
return { hour: 12, minute: 0, meridiem: 'am' };
|
|
5283
5585
|
}
|
|
5284
5586
|
let hour = parsed.hour();
|
|
5285
5587
|
const minute = parsed.minute();
|
|
5286
|
-
const meridiem = hour >= 12 ?
|
|
5588
|
+
const meridiem = hour >= 12 ? 'pm' : 'am';
|
|
5287
5589
|
if (hour === 0)
|
|
5288
5590
|
hour = 12;
|
|
5289
5591
|
else if (hour > 12)
|
|
@@ -5304,10 +5606,15 @@ const TimePicker = ({ column, schema, prefix }) => {
|
|
|
5304
5606
|
if (hour === null || minute === null || meridiem === null)
|
|
5305
5607
|
return null;
|
|
5306
5608
|
let newHour = hour;
|
|
5307
|
-
if (meridiem ===
|
|
5609
|
+
if (meridiem === 'pm' && hour !== 12) {
|
|
5308
5610
|
newHour = hour + 12;
|
|
5309
5611
|
}
|
|
5310
|
-
return dayjs()
|
|
5612
|
+
return dayjs()
|
|
5613
|
+
.tz(timezone)
|
|
5614
|
+
.hour(newHour)
|
|
5615
|
+
.minute(minute)
|
|
5616
|
+
.second(0)
|
|
5617
|
+
.format(timeFormat);
|
|
5311
5618
|
};
|
|
5312
5619
|
// Handle changes to time parts
|
|
5313
5620
|
const handleTimeChange = ({ hour: newHour, minute: newMinute, meridiem: newMeridiem, }) => {
|
|
@@ -5317,13 +5624,15 @@ const TimePicker = ({ column, schema, prefix }) => {
|
|
|
5317
5624
|
const timeString = getTimeString(newHour, newMinute, newMeridiem);
|
|
5318
5625
|
setValue(colLabel, timeString, { shouldValidate: true, shouldDirty: true });
|
|
5319
5626
|
};
|
|
5320
|
-
return (
|
|
5321
|
-
gridRow,
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5627
|
+
return (jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
|
|
5628
|
+
gridRow, errorText: errors[`${colLabel}`]
|
|
5629
|
+
? translate.t(removeIndex(`${colLabel}.field_required`))
|
|
5630
|
+
: undefined, invalid: !!errors[colLabel], children: jsxs(Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(Popover.Trigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
5631
|
+
setOpen(true);
|
|
5632
|
+
}, justifyContent: 'start', children: [jsx(IoMdClock, {}), !!value ? `${displayedTime}` : ''] }) }), jsx(Popover.Positioner, { children: jsx(Popover.Content, { children: jsx(Popover.Body, { children: jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, meridiemLabel: {
|
|
5633
|
+
am: translate.t(`common.am`, { defaultValue: 'AM' }),
|
|
5634
|
+
pm: translate.t(`common.pm`, { defaultValue: 'PM' }),
|
|
5635
|
+
} }) }) }) })] }) }));
|
|
5327
5636
|
};
|
|
5328
5637
|
|
|
5329
5638
|
function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond, onChange = (_newValue) => { }, }) {
|
|
@@ -5529,9 +5838,9 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
5529
5838
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
5530
5839
|
const { timezone, dateTimePickerLabels } = useSchemaContext();
|
|
5531
5840
|
const formI18n = useFormI18n(column, prefix);
|
|
5532
|
-
const { required, gridColumn =
|
|
5841
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD HH:mm:ss',
|
|
5533
5842
|
// with timezone
|
|
5534
|
-
dateFormat =
|
|
5843
|
+
dateFormat = 'YYYY-MM-DD[T]HH:mm:ssZ', } = schema;
|
|
5535
5844
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5536
5845
|
const colLabel = formI18n.colLabel;
|
|
5537
5846
|
const [open, setOpen] = useState(false);
|
|
@@ -5562,44 +5871,82 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
5562
5871
|
console.error(e);
|
|
5563
5872
|
}
|
|
5564
5873
|
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
5565
|
-
return (
|
|
5566
|
-
gridRow, children:
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
defaultValue:
|
|
5874
|
+
return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
5875
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
5876
|
+
setOpen(true);
|
|
5877
|
+
}, justifyContent: 'start', children: [jsx(MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ''] }) }), jsx(PopoverContent, { minW: '450px', children: jsxs(PopoverBody, { children: [jsx(PopoverTitle, {}), jsx(DateTimePicker$1, { value: selectedDate, onChange: (date) => {
|
|
5878
|
+
setValue(colLabel, dayjs(date).tz(timezone).format(dateFormat));
|
|
5879
|
+
}, timezone: timezone, labels: {
|
|
5880
|
+
monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
|
|
5881
|
+
formI18n.translate.t(`common.month_1`, {
|
|
5882
|
+
defaultValue: 'January',
|
|
5883
|
+
}),
|
|
5884
|
+
formI18n.translate.t(`common.month_2`, {
|
|
5885
|
+
defaultValue: 'February',
|
|
5886
|
+
}),
|
|
5887
|
+
formI18n.translate.t(`common.month_3`, {
|
|
5888
|
+
defaultValue: 'March',
|
|
5889
|
+
}),
|
|
5890
|
+
formI18n.translate.t(`common.month_4`, {
|
|
5891
|
+
defaultValue: 'April',
|
|
5892
|
+
}),
|
|
5893
|
+
formI18n.translate.t(`common.month_5`, {
|
|
5894
|
+
defaultValue: 'May',
|
|
5895
|
+
}),
|
|
5896
|
+
formI18n.translate.t(`common.month_6`, {
|
|
5897
|
+
defaultValue: 'June',
|
|
5898
|
+
}),
|
|
5899
|
+
formI18n.translate.t(`common.month_7`, {
|
|
5900
|
+
defaultValue: 'July',
|
|
5901
|
+
}),
|
|
5902
|
+
formI18n.translate.t(`common.month_8`, {
|
|
5903
|
+
defaultValue: 'August',
|
|
5904
|
+
}),
|
|
5905
|
+
formI18n.translate.t(`common.month_9`, {
|
|
5906
|
+
defaultValue: 'September',
|
|
5598
5907
|
}),
|
|
5599
|
-
|
|
5600
|
-
defaultValue:
|
|
5908
|
+
formI18n.translate.t(`common.month_10`, {
|
|
5909
|
+
defaultValue: 'October',
|
|
5601
5910
|
}),
|
|
5602
|
-
|
|
5911
|
+
formI18n.translate.t(`common.month_11`, {
|
|
5912
|
+
defaultValue: 'November',
|
|
5913
|
+
}),
|
|
5914
|
+
formI18n.translate.t(`common.month_12`, {
|
|
5915
|
+
defaultValue: 'December',
|
|
5916
|
+
}),
|
|
5917
|
+
],
|
|
5918
|
+
weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
|
|
5919
|
+
formI18n.translate.t(`common.weekday_1`, {
|
|
5920
|
+
defaultValue: 'Sun',
|
|
5921
|
+
}),
|
|
5922
|
+
formI18n.translate.t(`common.weekday_2`, {
|
|
5923
|
+
defaultValue: 'Mon',
|
|
5924
|
+
}),
|
|
5925
|
+
formI18n.translate.t(`common.weekday_3`, {
|
|
5926
|
+
defaultValue: 'Tue',
|
|
5927
|
+
}),
|
|
5928
|
+
formI18n.translate.t(`common.weekday_4`, {
|
|
5929
|
+
defaultValue: 'Wed',
|
|
5930
|
+
}),
|
|
5931
|
+
formI18n.translate.t(`common.weekday_5`, {
|
|
5932
|
+
defaultValue: 'Thu',
|
|
5933
|
+
}),
|
|
5934
|
+
formI18n.translate.t(`common.weekday_6`, {
|
|
5935
|
+
defaultValue: 'Fri',
|
|
5936
|
+
}),
|
|
5937
|
+
formI18n.translate.t(`common.weekday_7`, {
|
|
5938
|
+
defaultValue: 'Sat',
|
|
5939
|
+
}),
|
|
5940
|
+
],
|
|
5941
|
+
backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
|
|
5942
|
+
formI18n.translate.t(`common.back_button`, {
|
|
5943
|
+
defaultValue: 'Back',
|
|
5944
|
+
}),
|
|
5945
|
+
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
|
|
5946
|
+
formI18n.translate.t(`common.forward_button`, {
|
|
5947
|
+
defaultValue: 'Forward',
|
|
5948
|
+
}),
|
|
5949
|
+
} })] }) })] }) }));
|
|
5603
5950
|
};
|
|
5604
5951
|
|
|
5605
5952
|
const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
@@ -5673,13 +6020,18 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
5673
6020
|
return jsx(Text, { children: "missing type" });
|
|
5674
6021
|
};
|
|
5675
6022
|
|
|
5676
|
-
const ColumnRenderer = ({ column, properties, prefix, }) => {
|
|
6023
|
+
const ColumnRenderer = ({ column, properties, prefix, parentRequired, }) => {
|
|
5677
6024
|
const colSchema = properties[column];
|
|
5678
6025
|
const colLabel = `${prefix}${column}`;
|
|
5679
6026
|
if (colSchema === undefined) {
|
|
5680
6027
|
throw new Error(`${colLabel} does not exist when using ColumnRenderer`);
|
|
5681
6028
|
}
|
|
5682
|
-
|
|
6029
|
+
// Merge parent's required array with the schema's required array
|
|
6030
|
+
const schemaWithRequired = {
|
|
6031
|
+
...colSchema,
|
|
6032
|
+
required: parentRequired || colSchema.required,
|
|
6033
|
+
};
|
|
6034
|
+
return jsx(SchemaRenderer, { schema: schemaWithRequired, prefix, column });
|
|
5683
6035
|
};
|
|
5684
6036
|
|
|
5685
6037
|
const ArrayViewer = ({ schema, column, prefix }) => {
|
|
@@ -5802,11 +6154,29 @@ const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5802
6154
|
const NumberViewer = ({ schema, column, prefix, }) => {
|
|
5803
6155
|
const { watch, formState: { errors }, } = useFormContext();
|
|
5804
6156
|
const { translate } = useSchemaContext();
|
|
5805
|
-
const { required, gridColumn =
|
|
6157
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
5806
6158
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5807
6159
|
const colLabel = `${prefix}${column}`;
|
|
5808
6160
|
const value = watch(colLabel);
|
|
5809
|
-
|
|
6161
|
+
// Format the value for display if formatOptions are provided
|
|
6162
|
+
const formatValue = (val) => {
|
|
6163
|
+
if (val === undefined || val === null || val === '')
|
|
6164
|
+
return '';
|
|
6165
|
+
const numValue = typeof val === 'string' ? parseFloat(val) : val;
|
|
6166
|
+
if (isNaN(numValue))
|
|
6167
|
+
return String(val);
|
|
6168
|
+
// Use formatOptions if available, otherwise display as-is
|
|
6169
|
+
if (schema.formatOptions) {
|
|
6170
|
+
try {
|
|
6171
|
+
return new Intl.NumberFormat(undefined, schema.formatOptions).format(numValue);
|
|
6172
|
+
}
|
|
6173
|
+
catch {
|
|
6174
|
+
return String(val);
|
|
6175
|
+
}
|
|
6176
|
+
}
|
|
6177
|
+
return String(val);
|
|
6178
|
+
};
|
|
6179
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, children: [jsx(Text, { children: formatValue(value) }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
5810
6180
|
};
|
|
5811
6181
|
|
|
5812
6182
|
const ObjectViewer = ({ schema, column, prefix }) => {
|
|
@@ -6098,113 +6468,43 @@ const ColumnViewer = ({ column, properties, prefix, }) => {
|
|
|
6098
6468
|
};
|
|
6099
6469
|
|
|
6100
6470
|
const SubmitButton = () => {
|
|
6101
|
-
const { translate, setValidatedData, setIsError, setIsConfirming, setError, schema, } = useSchemaContext();
|
|
6471
|
+
const { translate, setValidatedData, setIsError, setIsConfirming, setError, schema, requireConfirmation, onFormSubmit, } = useSchemaContext();
|
|
6102
6472
|
const methods = useFormContext();
|
|
6103
6473
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6104
6474
|
const onValid = (data) => {
|
|
6105
|
-
const { isValid, errors } = validateData(data, schema);
|
|
6106
|
-
if (!isValid) {
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6475
|
+
// const { isValid, errors } = validateData(data, schema);
|
|
6476
|
+
// if (!isValid) {
|
|
6477
|
+
// setError({
|
|
6478
|
+
// type: 'validation',
|
|
6479
|
+
// errors,
|
|
6480
|
+
// });
|
|
6481
|
+
// setIsError(true);
|
|
6482
|
+
// return;
|
|
6483
|
+
// }
|
|
6484
|
+
// If validation passes, check if confirmation is required
|
|
6485
|
+
if (requireConfirmation) {
|
|
6486
|
+
// Show confirmation (existing behavior)
|
|
6487
|
+
setValidatedData(data);
|
|
6488
|
+
setIsError(false);
|
|
6489
|
+
setIsConfirming(true);
|
|
6490
|
+
}
|
|
6491
|
+
else {
|
|
6492
|
+
// Skip confirmation and submit directly
|
|
6493
|
+
setValidatedData(data);
|
|
6494
|
+
setIsError(false);
|
|
6495
|
+
onFormSubmit(data);
|
|
6113
6496
|
}
|
|
6114
|
-
// If validation passes, proceed to confirmation
|
|
6115
|
-
setValidatedData(data);
|
|
6116
|
-
setIsError(false);
|
|
6117
|
-
setIsConfirming(true);
|
|
6118
6497
|
};
|
|
6119
6498
|
return (jsx(Button$1, { onClick: () => {
|
|
6120
6499
|
methods.handleSubmit(onValid)();
|
|
6121
|
-
}, formNoValidate: true, children: translate.t(
|
|
6500
|
+
}, formNoValidate: true, children: translate.t('submit') }));
|
|
6122
6501
|
};
|
|
6123
6502
|
|
|
6124
6503
|
const FormBody = () => {
|
|
6125
|
-
const { schema,
|
|
6504
|
+
const { schema, order, ignore, include, translate, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, onFormSubmit, } = useSchemaContext();
|
|
6126
6505
|
const { showSubmitButton, showResetButton } = displayConfig;
|
|
6127
6506
|
const methods = useFormContext();
|
|
6128
6507
|
const { properties } = schema;
|
|
6129
|
-
const onBeforeSubmit = () => {
|
|
6130
|
-
setIsSubmiting(true);
|
|
6131
|
-
};
|
|
6132
|
-
const onAfterSubmit = () => {
|
|
6133
|
-
setIsSubmiting(false);
|
|
6134
|
-
};
|
|
6135
|
-
const onSubmitError = (error) => {
|
|
6136
|
-
setIsError(true);
|
|
6137
|
-
setError(error);
|
|
6138
|
-
};
|
|
6139
|
-
const onSubmitSuccess = () => {
|
|
6140
|
-
setIsSuccess(true);
|
|
6141
|
-
};
|
|
6142
|
-
const validateFormData = (data) => {
|
|
6143
|
-
try {
|
|
6144
|
-
const { isValid, errors } = validateData(data, schema);
|
|
6145
|
-
return {
|
|
6146
|
-
isValid,
|
|
6147
|
-
errors,
|
|
6148
|
-
};
|
|
6149
|
-
}
|
|
6150
|
-
catch (error) {
|
|
6151
|
-
return {
|
|
6152
|
-
isValid: false,
|
|
6153
|
-
errors: [
|
|
6154
|
-
{
|
|
6155
|
-
field: "validation",
|
|
6156
|
-
message: error instanceof Error ? error.message : "Unknown error",
|
|
6157
|
-
},
|
|
6158
|
-
],
|
|
6159
|
-
};
|
|
6160
|
-
}
|
|
6161
|
-
};
|
|
6162
|
-
const defaultOnSubmit = async (promise) => {
|
|
6163
|
-
try {
|
|
6164
|
-
onBeforeSubmit();
|
|
6165
|
-
await promise;
|
|
6166
|
-
onSubmitSuccess();
|
|
6167
|
-
}
|
|
6168
|
-
catch (error) {
|
|
6169
|
-
onSubmitError(error);
|
|
6170
|
-
}
|
|
6171
|
-
finally {
|
|
6172
|
-
onAfterSubmit();
|
|
6173
|
-
}
|
|
6174
|
-
};
|
|
6175
|
-
const defaultSubmitPromise = (data) => {
|
|
6176
|
-
const options = {
|
|
6177
|
-
method: "POST",
|
|
6178
|
-
url: `${requestUrl}`,
|
|
6179
|
-
data: clearEmptyString(data),
|
|
6180
|
-
...requestOptions,
|
|
6181
|
-
};
|
|
6182
|
-
return axios.request(options);
|
|
6183
|
-
};
|
|
6184
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6185
|
-
const onFormSubmit = async (data) => {
|
|
6186
|
-
// Validate data using AJV before submission
|
|
6187
|
-
const validationResult = validateFormData(data);
|
|
6188
|
-
if (!validationResult.isValid) {
|
|
6189
|
-
// Set validation errors
|
|
6190
|
-
const validationErrorMessage = {
|
|
6191
|
-
type: "validation",
|
|
6192
|
-
errors: validationResult.errors,
|
|
6193
|
-
message: translate.t("validation_error"),
|
|
6194
|
-
};
|
|
6195
|
-
onSubmitError(validationErrorMessage);
|
|
6196
|
-
return;
|
|
6197
|
-
}
|
|
6198
|
-
if (onSubmit === undefined) {
|
|
6199
|
-
await defaultOnSubmit(defaultSubmitPromise(data));
|
|
6200
|
-
return;
|
|
6201
|
-
}
|
|
6202
|
-
await defaultOnSubmit(onSubmit(data));
|
|
6203
|
-
};
|
|
6204
|
-
// Custom error renderer for validation errors with i18n support
|
|
6205
|
-
const renderValidationErrors = (validationErrors) => {
|
|
6206
|
-
return (jsx(Flex, { flexFlow: "column", gap: "2", children: validationErrors.map((err, index) => (jsxs(Alert.Root, { status: "error", display: "flex", alignItems: "center", children: [jsx(Alert.Indicator, {}), jsx(Alert.Content, { children: jsx(Alert.Description, { children: err.message }) })] }, index))) }));
|
|
6207
|
-
};
|
|
6208
6508
|
const renderColumns = ({ order, keys, ignore, include, }) => {
|
|
6209
6509
|
const included = include.length > 0 ? include : keys;
|
|
6210
6510
|
const not_exist = included.filter((columnA) => !order.some((columnB) => columnA === columnB));
|
|
@@ -6231,32 +6531,30 @@ const FormBody = () => {
|
|
|
6231
6531
|
if (customSuccessRenderer) {
|
|
6232
6532
|
return customSuccessRenderer(resetHandler);
|
|
6233
6533
|
}
|
|
6234
|
-
return (jsxs(Flex, { flexFlow:
|
|
6534
|
+
return (jsxs(Flex, { flexFlow: 'column', gap: "2", children: [jsxs(Alert.Root, { status: "success", children: [jsx(Alert.Indicator, {}), jsx(Alert.Content, { children: jsx(Alert.Title, { children: translate.t('submit_success') }) })] }), jsx(Flex, { justifyContent: 'end', children: jsx(Button$1, { onClick: resetHandler, formNoValidate: true, children: translate.t('submit_again') }) })] }));
|
|
6235
6535
|
}
|
|
6236
6536
|
if (isConfirming) {
|
|
6237
|
-
return (jsxs(Flex, { flexFlow:
|
|
6537
|
+
return (jsxs(Flex, { flexFlow: 'column', gap: "2", children: [jsx(Grid, { gap: 4, gridTemplateColumns: 'repeat(12, 1fr)', gridTemplateRows: 'repeat(12, max-content)', autoFlow: 'row', children: ordered.map((column) => {
|
|
6238
6538
|
return (jsx(ColumnViewer
|
|
6239
6539
|
// @ts-expect-error find suitable types
|
|
6240
6540
|
, {
|
|
6241
6541
|
// @ts-expect-error find suitable types
|
|
6242
6542
|
properties: properties, prefix: ``, column }, `form-viewer-${column}`));
|
|
6243
|
-
}) }), jsxs(Flex, { justifyContent:
|
|
6543
|
+
}) }), jsxs(Flex, { justifyContent: 'end', gap: '2', children: [jsx(Button$1, { onClick: () => {
|
|
6244
6544
|
setIsConfirming(false);
|
|
6245
|
-
}, variant:
|
|
6545
|
+
}, variant: 'subtle', children: translate.t('cancel') }), jsx(Button$1, { onClick: () => {
|
|
6246
6546
|
onFormSubmit(validatedData);
|
|
6247
|
-
}, children: translate.t(
|
|
6248
|
-
error?.errors ? (renderValidationErrors(error.errors)) : (jsxs(Alert.Root, { status: "error", children: [jsx(Alert.Indicator, {}), jsxs(Alert.Content, { children: [jsx(Alert.Title, { children: "Error" }), jsx(Alert.Description, { children: jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxs(AccordionItem, { value: "b", children: [jsx(AccordionItemTrigger, { children: `${error}` }), jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) })] })] })) })) }))] }));
|
|
6547
|
+
}, children: translate.t('confirm') })] }), isSubmiting && (jsx(Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsx(Center, { h: "full", children: jsx(Spinner, { color: "teal.500" }) }) })), isError && customErrorRenderer && customErrorRenderer(error)] }));
|
|
6249
6548
|
}
|
|
6250
|
-
return (jsxs(Flex, { flexFlow:
|
|
6549
|
+
return (jsxs(Flex, { flexFlow: 'column', gap: "2", children: [jsx(Grid, { gap: "4", gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: ordered.map((column) => {
|
|
6251
6550
|
return (jsx(ColumnRenderer
|
|
6252
6551
|
// @ts-expect-error find suitable types
|
|
6253
6552
|
, {
|
|
6254
6553
|
// @ts-expect-error find suitable types
|
|
6255
|
-
properties: properties, prefix: ``, column }, `form-input-${column}`));
|
|
6256
|
-
}) }), jsxs(Flex, { justifyContent:
|
|
6554
|
+
properties: properties, prefix: ``, parentRequired: schema.required, column }, `form-input-${column}`));
|
|
6555
|
+
}) }), jsxs(Flex, { justifyContent: 'end', gap: "2", children: [showResetButton && (jsx(Button$1, { onClick: () => {
|
|
6257
6556
|
methods.reset();
|
|
6258
|
-
}, variant:
|
|
6259
|
-
error?.errors ? (renderValidationErrors(error.errors)) : (jsxs(Alert.Root, { status: "error", children: [jsx(Alert.Indicator, {}), jsxs(Alert.Content, { children: [jsx(Alert.Title, { children: "Error" }), jsx(Alert.Description, { children: jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxs(AccordionItem, { value: "b", children: [jsx(AccordionItemTrigger, { children: `${error}` }), jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) })] })] })) })) }))] }));
|
|
6557
|
+
}, variant: 'subtle', children: translate.t('reset') })), showSubmitButton && jsx(SubmitButton, {})] }), isError && customErrorRenderer && customErrorRenderer(error)] }));
|
|
6260
6558
|
};
|
|
6261
6559
|
|
|
6262
6560
|
const FormTitle = () => {
|
|
@@ -6269,12 +6567,15 @@ const DefaultForm = ({ formConfig, }) => {
|
|
|
6269
6567
|
return (jsx(FormRoot, { ...formConfig, children: jsxs(Grid, { gap: "2", children: [showTitle && jsx(FormTitle, {}), jsx(FormBody, {})] }) }));
|
|
6270
6568
|
};
|
|
6271
6569
|
|
|
6272
|
-
const useForm = ({ preLoadedValues, keyPrefix, namespace }) => {
|
|
6570
|
+
const useForm = ({ preLoadedValues, keyPrefix, namespace, schema, }) => {
|
|
6273
6571
|
const form = useForm$1({
|
|
6274
6572
|
values: preLoadedValues,
|
|
6573
|
+
resolver: schema ? ajvResolver(schema) : undefined,
|
|
6574
|
+
mode: 'onBlur',
|
|
6575
|
+
reValidateMode: 'onBlur',
|
|
6275
6576
|
});
|
|
6276
6577
|
const [idMap, setIdMap] = useState({});
|
|
6277
|
-
const translate = useTranslation(namespace ||
|
|
6578
|
+
const translate = useTranslation(namespace || '', { keyPrefix });
|
|
6278
6579
|
return {
|
|
6279
6580
|
form,
|
|
6280
6581
|
idMap,
|
|
@@ -6344,15 +6645,15 @@ const buildErrorMessages = (config) => {
|
|
|
6344
6645
|
}
|
|
6345
6646
|
// Add global fallback error messages
|
|
6346
6647
|
const globalKeys = [
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
|
|
6353
|
-
|
|
6354
|
-
|
|
6355
|
-
|
|
6648
|
+
'minLength',
|
|
6649
|
+
'maxLength',
|
|
6650
|
+
'pattern',
|
|
6651
|
+
'minimum',
|
|
6652
|
+
'maximum',
|
|
6653
|
+
'multipleOf',
|
|
6654
|
+
'format',
|
|
6655
|
+
'type',
|
|
6656
|
+
'enum',
|
|
6356
6657
|
];
|
|
6357
6658
|
globalKeys.forEach((key) => {
|
|
6358
6659
|
if (config[key]) {
|
|
@@ -6361,6 +6662,46 @@ const buildErrorMessages = (config) => {
|
|
|
6361
6662
|
});
|
|
6362
6663
|
return result;
|
|
6363
6664
|
};
|
|
6665
|
+
/**
|
|
6666
|
+
* Converts buildErrorMessages result to ajv-errors compatible format
|
|
6667
|
+
*/
|
|
6668
|
+
const convertToAjvErrorsFormat = (errorMessages) => {
|
|
6669
|
+
const result = {};
|
|
6670
|
+
// Convert required field errors
|
|
6671
|
+
if (errorMessages.required) {
|
|
6672
|
+
result.required = errorMessages.required;
|
|
6673
|
+
}
|
|
6674
|
+
// Convert properties errors to ajv-errors format
|
|
6675
|
+
if (errorMessages.properties) {
|
|
6676
|
+
result.properties = {};
|
|
6677
|
+
Object.keys(errorMessages.properties).forEach((fieldName) => {
|
|
6678
|
+
const fieldErrors = errorMessages.properties[fieldName];
|
|
6679
|
+
result.properties[fieldName] = {};
|
|
6680
|
+
Object.keys(fieldErrors).forEach((keyword) => {
|
|
6681
|
+
result.properties[fieldName][keyword] =
|
|
6682
|
+
fieldErrors[keyword];
|
|
6683
|
+
});
|
|
6684
|
+
});
|
|
6685
|
+
}
|
|
6686
|
+
// Add global fallback errors
|
|
6687
|
+
const globalKeys = [
|
|
6688
|
+
'minLength',
|
|
6689
|
+
'maxLength',
|
|
6690
|
+
'pattern',
|
|
6691
|
+
'minimum',
|
|
6692
|
+
'maximum',
|
|
6693
|
+
'multipleOf',
|
|
6694
|
+
'format',
|
|
6695
|
+
'type',
|
|
6696
|
+
'enum',
|
|
6697
|
+
];
|
|
6698
|
+
globalKeys.forEach((key) => {
|
|
6699
|
+
if (errorMessages[key]) {
|
|
6700
|
+
result[key] = errorMessages[key];
|
|
6701
|
+
}
|
|
6702
|
+
});
|
|
6703
|
+
return result;
|
|
6704
|
+
};
|
|
6364
6705
|
/**
|
|
6365
6706
|
* Helper function to build required field errors
|
|
6366
6707
|
*
|
|
@@ -6403,10 +6744,10 @@ const buildErrorMessages = (config) => {
|
|
|
6403
6744
|
* // Result: { username: "user.username.field_required", email: "user.email.field_required" }
|
|
6404
6745
|
* ```
|
|
6405
6746
|
*/
|
|
6406
|
-
const buildRequiredErrors = (fields, messageOrGenerator, keyPrefix =
|
|
6747
|
+
const buildRequiredErrors = (fields, messageOrGenerator, keyPrefix = '') => {
|
|
6407
6748
|
const result = {};
|
|
6408
6749
|
fields.forEach((field) => {
|
|
6409
|
-
if (typeof messageOrGenerator ===
|
|
6750
|
+
if (typeof messageOrGenerator === 'function') {
|
|
6410
6751
|
const message = messageOrGenerator(field);
|
|
6411
6752
|
result[field] = keyPrefix ? `${keyPrefix}.${message}` : message;
|
|
6412
6753
|
}
|
|
@@ -6477,11 +6818,14 @@ const buildFieldErrors = (config) => {
|
|
|
6477
6818
|
* ```
|
|
6478
6819
|
*/
|
|
6479
6820
|
const createErrorMessage = (required, properties, globalFallbacks) => {
|
|
6480
|
-
|
|
6821
|
+
const config = {
|
|
6481
6822
|
required,
|
|
6482
6823
|
properties,
|
|
6483
|
-
|
|
6484
|
-
|
|
6824
|
+
};
|
|
6825
|
+
if (globalFallbacks) {
|
|
6826
|
+
Object.assign(config, globalFallbacks);
|
|
6827
|
+
}
|
|
6828
|
+
return buildErrorMessages(config);
|
|
6485
6829
|
};
|
|
6486
6830
|
|
|
6487
6831
|
const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) => {
|
|
@@ -6500,4 +6844,4 @@ const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) =
|
|
|
6500
6844
|
}
|
|
6501
6845
|
};
|
|
6502
6846
|
|
|
6503
|
-
export { CardHeader, DataDisplay, DataTable, DataTableServer, DefaultCardTitle, DefaultForm, DefaultTable, DensityToggleButton, EditSortingButton, EmptyState$1 as EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, buildErrorMessages, buildFieldErrors, buildRequiredErrors, createErrorMessage, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
|
|
6847
|
+
export { CardHeader, DataDisplay, DataTable, DataTableServer, DefaultCardTitle, DefaultForm, DefaultTable, DensityToggleButton, EditSortingButton, EmptyState$1 as EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, buildErrorMessages, buildFieldErrors, buildRequiredErrors, convertToAjvErrorsFormat, createErrorMessage, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
|