@bsol-oss/react-datatable5 12.0.0-beta.74 → 12.0.0-beta.76
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 +159 -126
- package/dist/index.js +820 -279
- package/dist/index.mjs +822 -282
- package/dist/types/components/Form/SchemaFormContext.d.ts +5 -3
- package/dist/types/components/Form/components/core/FormRoot.d.ts +3 -2
- 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/DateRangePicker.d.ts +2 -0
- 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/ObjectInput.d.ts +1 -1
- package/dist/types/components/Form/components/fields/RecordInput.d.ts +1 -1
- package/dist/types/components/Form/components/fields/SchemaRenderer.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 +28 -0
- 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/formatBytes.d.ts +6 -0
- 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.js
CHANGED
|
@@ -31,7 +31,6 @@ var axios = require('axios');
|
|
|
31
31
|
var reactHookForm = require('react-hook-form');
|
|
32
32
|
var Ajv = require('ajv');
|
|
33
33
|
var addFormats = require('ajv-formats');
|
|
34
|
-
var addErrors = require('ajv-errors');
|
|
35
34
|
var dayjs = require('dayjs');
|
|
36
35
|
var utc = require('dayjs/plugin/utc');
|
|
37
36
|
var timezone = require('dayjs/plugin/timezone');
|
|
@@ -3664,16 +3663,6 @@ const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
|
|
|
3664
3663
|
})] }));
|
|
3665
3664
|
};
|
|
3666
3665
|
|
|
3667
|
-
const AccordionItemTrigger = React__namespace.forwardRef(function AccordionItemTrigger(props, ref) {
|
|
3668
|
-
const { children, indicatorPlacement = "end", ...rest } = props;
|
|
3669
|
-
return (jsxRuntime.jsxs(react.Accordion.ItemTrigger, { ...rest, ref: ref, children: [indicatorPlacement === "start" && (jsxRuntime.jsx(react.Accordion.ItemIndicator, { rotate: { base: "-90deg", _open: "0deg" }, children: jsxRuntime.jsx(lu.LuChevronDown, {}) })), jsxRuntime.jsx(react.HStack, { gap: "4", flex: "1", textAlign: "start", width: "full", children: children }), indicatorPlacement === "end" && (jsxRuntime.jsx(react.Accordion.ItemIndicator, { children: jsxRuntime.jsx(lu.LuChevronDown, {}) }))] }));
|
|
3670
|
-
});
|
|
3671
|
-
const AccordionItemContent = React__namespace.forwardRef(function AccordionItemContent(props, ref) {
|
|
3672
|
-
return (jsxRuntime.jsx(react.Accordion.ItemContent, { children: jsxRuntime.jsx(react.Accordion.ItemBody, { ...props, ref: ref }) }));
|
|
3673
|
-
});
|
|
3674
|
-
const AccordionRoot = react.Accordion.Root;
|
|
3675
|
-
const AccordionItem = react.Accordion.Item;
|
|
3676
|
-
|
|
3677
3666
|
//@ts-expect-error TODO: find appropriate type
|
|
3678
3667
|
const SchemaFormContext = React.createContext({
|
|
3679
3668
|
schema: {},
|
|
@@ -3693,19 +3682,23 @@ const SchemaFormContext = React.createContext({
|
|
|
3693
3682
|
},
|
|
3694
3683
|
requireConfirmation: false,
|
|
3695
3684
|
onFormSubmit: async () => { },
|
|
3685
|
+
ajvResolver: async () => ({ values: {}, errors: {} }),
|
|
3696
3686
|
});
|
|
3697
3687
|
|
|
3698
3688
|
const useSchemaContext = () => {
|
|
3699
3689
|
return React.useContext(SchemaFormContext);
|
|
3700
3690
|
};
|
|
3701
3691
|
|
|
3692
|
+
const clearEmptyString = (object) => {
|
|
3693
|
+
return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
|
|
3694
|
+
};
|
|
3695
|
+
|
|
3702
3696
|
const validateData = (data, schema) => {
|
|
3703
3697
|
const ajv = new Ajv({
|
|
3704
3698
|
strict: false,
|
|
3705
3699
|
allErrors: true,
|
|
3706
3700
|
});
|
|
3707
3701
|
addFormats(ajv);
|
|
3708
|
-
addErrors(ajv);
|
|
3709
3702
|
const validate = ajv.compile(schema);
|
|
3710
3703
|
const validationResult = validate(data);
|
|
3711
3704
|
const errors = validate.errors;
|
|
@@ -3717,8 +3710,183 @@ const validateData = (data, schema) => {
|
|
|
3717
3710
|
};
|
|
3718
3711
|
};
|
|
3719
3712
|
|
|
3720
|
-
|
|
3721
|
-
|
|
3713
|
+
/**
|
|
3714
|
+
* Gets the schema node for a field by following the path from root schema
|
|
3715
|
+
*/
|
|
3716
|
+
const getSchemaNodeForField = (schema, fieldPath) => {
|
|
3717
|
+
if (!fieldPath || fieldPath === '') {
|
|
3718
|
+
return schema;
|
|
3719
|
+
}
|
|
3720
|
+
const pathParts = fieldPath.split('.');
|
|
3721
|
+
let currentSchema = schema;
|
|
3722
|
+
for (const part of pathParts) {
|
|
3723
|
+
if (currentSchema &&
|
|
3724
|
+
currentSchema.properties &&
|
|
3725
|
+
currentSchema.properties[part] &&
|
|
3726
|
+
typeof currentSchema.properties[part] === 'object' &&
|
|
3727
|
+
currentSchema.properties[part] !== null) {
|
|
3728
|
+
currentSchema = currentSchema.properties[part];
|
|
3729
|
+
}
|
|
3730
|
+
else {
|
|
3731
|
+
return undefined;
|
|
3732
|
+
}
|
|
3733
|
+
}
|
|
3734
|
+
return currentSchema;
|
|
3735
|
+
};
|
|
3736
|
+
/**
|
|
3737
|
+
* Converts AJV error objects to react-hook-form field errors format
|
|
3738
|
+
*/
|
|
3739
|
+
const convertAjvErrorsToFieldErrors = (errors, schema) => {
|
|
3740
|
+
if (!errors || errors.length === 0) {
|
|
3741
|
+
return {};
|
|
3742
|
+
}
|
|
3743
|
+
const fieldErrors = {};
|
|
3744
|
+
errors.forEach((error) => {
|
|
3745
|
+
let fieldName = '';
|
|
3746
|
+
// Special handling for required keyword: map to the specific missing property
|
|
3747
|
+
if (error.keyword === 'required') {
|
|
3748
|
+
const basePath = (error.instancePath || '')
|
|
3749
|
+
.replace(/^\//, '')
|
|
3750
|
+
.replace(/\//g, '.');
|
|
3751
|
+
const missingProperty = (error.params &&
|
|
3752
|
+
error.params.missingProperty);
|
|
3753
|
+
if (missingProperty) {
|
|
3754
|
+
fieldName = basePath
|
|
3755
|
+
? `${basePath}.${missingProperty}`
|
|
3756
|
+
: missingProperty;
|
|
3757
|
+
}
|
|
3758
|
+
else {
|
|
3759
|
+
// Fallback to schemaPath conversion if missingProperty is unavailable
|
|
3760
|
+
fieldName = (error.schemaPath || '')
|
|
3761
|
+
.replace(/^#\//, '#.')
|
|
3762
|
+
.replace(/\//g, '.');
|
|
3763
|
+
}
|
|
3764
|
+
}
|
|
3765
|
+
else {
|
|
3766
|
+
const fieldPath = error.instancePath || error.schemaPath;
|
|
3767
|
+
if (fieldPath) {
|
|
3768
|
+
fieldName = fieldPath.replace(/^\//, '').replace(/\//g, '.');
|
|
3769
|
+
}
|
|
3770
|
+
}
|
|
3771
|
+
if (fieldName) {
|
|
3772
|
+
// Get the schema node for this field to check for custom error messages
|
|
3773
|
+
const fieldSchema = getSchemaNodeForField(schema, fieldName);
|
|
3774
|
+
const customMessage = fieldSchema?.errorMessages?.[error.keyword];
|
|
3775
|
+
// Provide helpful fallback message if no custom message is provided
|
|
3776
|
+
const fallbackMessage = customMessage ||
|
|
3777
|
+
`Missing error message for ${error.keyword}. Add errorMessages.${error.keyword} to schema for field '${fieldName}'`;
|
|
3778
|
+
if (error.keyword === 'required') {
|
|
3779
|
+
// Required errors override any existing non-required errors for this field
|
|
3780
|
+
fieldErrors[fieldName] = {
|
|
3781
|
+
type: 'required',
|
|
3782
|
+
keyword: error.keyword,
|
|
3783
|
+
params: error.params,
|
|
3784
|
+
message: fallbackMessage,
|
|
3785
|
+
};
|
|
3786
|
+
}
|
|
3787
|
+
else {
|
|
3788
|
+
const existing = fieldErrors[fieldName];
|
|
3789
|
+
if (existing) {
|
|
3790
|
+
// Do not override required errors
|
|
3791
|
+
if (existing.type === 'required') {
|
|
3792
|
+
return;
|
|
3793
|
+
}
|
|
3794
|
+
// Combine messages if multiple errors for same field
|
|
3795
|
+
existing.message = existing.message
|
|
3796
|
+
? `${existing.message}; ${fallbackMessage}`
|
|
3797
|
+
: fallbackMessage;
|
|
3798
|
+
}
|
|
3799
|
+
else {
|
|
3800
|
+
fieldErrors[fieldName] = {
|
|
3801
|
+
type: error.keyword,
|
|
3802
|
+
keyword: error.keyword,
|
|
3803
|
+
params: error.params,
|
|
3804
|
+
message: fallbackMessage,
|
|
3805
|
+
};
|
|
3806
|
+
}
|
|
3807
|
+
}
|
|
3808
|
+
}
|
|
3809
|
+
});
|
|
3810
|
+
return fieldErrors;
|
|
3811
|
+
};
|
|
3812
|
+
/**
|
|
3813
|
+
* AJV resolver for react-hook-form
|
|
3814
|
+
* Integrates AJV validation with react-hook-form's validation system
|
|
3815
|
+
*/
|
|
3816
|
+
/**
|
|
3817
|
+
* Strips null, undefined, and empty string values from an object
|
|
3818
|
+
*/
|
|
3819
|
+
const stripEmptyValues = (obj) => {
|
|
3820
|
+
if (obj === null || obj === undefined) {
|
|
3821
|
+
return undefined;
|
|
3822
|
+
}
|
|
3823
|
+
if (typeof obj === 'string' && obj.trim() === '') {
|
|
3824
|
+
return undefined;
|
|
3825
|
+
}
|
|
3826
|
+
if (Array.isArray(obj)) {
|
|
3827
|
+
const filtered = obj
|
|
3828
|
+
.map(stripEmptyValues)
|
|
3829
|
+
.filter((item) => item !== undefined);
|
|
3830
|
+
return filtered.length > 0 ? filtered : undefined;
|
|
3831
|
+
}
|
|
3832
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
3833
|
+
const result = {};
|
|
3834
|
+
let hasValues = false;
|
|
3835
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
3836
|
+
const cleanedValue = stripEmptyValues(value);
|
|
3837
|
+
if (cleanedValue !== undefined) {
|
|
3838
|
+
result[key] = cleanedValue;
|
|
3839
|
+
hasValues = true;
|
|
3840
|
+
}
|
|
3841
|
+
}
|
|
3842
|
+
return hasValues ? result : undefined;
|
|
3843
|
+
}
|
|
3844
|
+
return obj;
|
|
3845
|
+
};
|
|
3846
|
+
const ajvResolver = (schema) => {
|
|
3847
|
+
return async (values) => {
|
|
3848
|
+
try {
|
|
3849
|
+
// Strip empty values before validation
|
|
3850
|
+
const cleanedValues = stripEmptyValues(values);
|
|
3851
|
+
// Use empty object for validation if all values were stripped
|
|
3852
|
+
const valuesToValidate = cleanedValues === undefined ? {} : cleanedValues;
|
|
3853
|
+
const { isValid, errors } = validateData(valuesToValidate, schema);
|
|
3854
|
+
console.debug('AJV Validation Result:', {
|
|
3855
|
+
isValid,
|
|
3856
|
+
errors,
|
|
3857
|
+
cleanedValues,
|
|
3858
|
+
valuesToValidate,
|
|
3859
|
+
});
|
|
3860
|
+
if (isValid) {
|
|
3861
|
+
return {
|
|
3862
|
+
values: (cleanedValues || {}),
|
|
3863
|
+
errors: {},
|
|
3864
|
+
};
|
|
3865
|
+
}
|
|
3866
|
+
const fieldErrors = convertAjvErrorsToFieldErrors(errors, schema);
|
|
3867
|
+
console.debug('AJV Validation Failed:', {
|
|
3868
|
+
errors,
|
|
3869
|
+
fieldErrors,
|
|
3870
|
+
cleanedValues,
|
|
3871
|
+
valuesToValidate,
|
|
3872
|
+
});
|
|
3873
|
+
return {
|
|
3874
|
+
values: {},
|
|
3875
|
+
errors: fieldErrors,
|
|
3876
|
+
};
|
|
3877
|
+
}
|
|
3878
|
+
catch (error) {
|
|
3879
|
+
return {
|
|
3880
|
+
values: {},
|
|
3881
|
+
errors: {
|
|
3882
|
+
root: {
|
|
3883
|
+
type: 'validation',
|
|
3884
|
+
message: error instanceof Error ? error.message : 'Validation failed',
|
|
3885
|
+
},
|
|
3886
|
+
},
|
|
3887
|
+
};
|
|
3888
|
+
}
|
|
3889
|
+
};
|
|
3722
3890
|
};
|
|
3723
3891
|
|
|
3724
3892
|
const idPickerSanityCheck = (column, foreign_key) => {
|
|
@@ -3740,7 +3908,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
3740
3908
|
showSubmitButton: true,
|
|
3741
3909
|
showResetButton: true,
|
|
3742
3910
|
showTitle: true,
|
|
3743
|
-
}, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, }) => {
|
|
3911
|
+
}, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, }) => {
|
|
3744
3912
|
const [isSuccess, setIsSuccess] = React.useState(false);
|
|
3745
3913
|
const [isError, setIsError] = React.useState(false);
|
|
3746
3914
|
const [isSubmiting, setIsSubmiting] = React.useState(false);
|
|
@@ -3760,33 +3928,16 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
3760
3928
|
const onSubmitSuccess = () => {
|
|
3761
3929
|
setIsSuccess(true);
|
|
3762
3930
|
};
|
|
3763
|
-
const validateFormData = (data) => {
|
|
3764
|
-
try {
|
|
3765
|
-
const { isValid, errors } = validateData(data, schema);
|
|
3766
|
-
return {
|
|
3767
|
-
isValid,
|
|
3768
|
-
errors,
|
|
3769
|
-
};
|
|
3770
|
-
}
|
|
3771
|
-
catch (error) {
|
|
3772
|
-
return {
|
|
3773
|
-
isValid: false,
|
|
3774
|
-
errors: [
|
|
3775
|
-
{
|
|
3776
|
-
field: 'validation',
|
|
3777
|
-
message: error instanceof Error ? error.message : 'Unknown error',
|
|
3778
|
-
},
|
|
3779
|
-
],
|
|
3780
|
-
};
|
|
3781
|
-
}
|
|
3782
|
-
};
|
|
3783
3931
|
const defaultOnSubmit = async (promise) => {
|
|
3784
3932
|
try {
|
|
3933
|
+
console.log('onBeforeSubmit');
|
|
3785
3934
|
onBeforeSubmit();
|
|
3786
3935
|
await promise;
|
|
3936
|
+
console.log('onSubmitSuccess');
|
|
3787
3937
|
onSubmitSuccess();
|
|
3788
3938
|
}
|
|
3789
3939
|
catch (error) {
|
|
3940
|
+
console.log('onSubmitError', error);
|
|
3790
3941
|
onSubmitError(error);
|
|
3791
3942
|
}
|
|
3792
3943
|
finally {
|
|
@@ -3796,7 +3947,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
3796
3947
|
const defaultSubmitPromise = (data) => {
|
|
3797
3948
|
const options = {
|
|
3798
3949
|
method: 'POST',
|
|
3799
|
-
url: `${
|
|
3950
|
+
url: `${serverUrl}`,
|
|
3800
3951
|
data: clearEmptyString(data),
|
|
3801
3952
|
...requestOptions,
|
|
3802
3953
|
};
|
|
@@ -3804,23 +3955,13 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
3804
3955
|
};
|
|
3805
3956
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3806
3957
|
const onFormSubmit = async (data) => {
|
|
3807
|
-
//
|
|
3808
|
-
|
|
3809
|
-
if (!validationResult.isValid) {
|
|
3810
|
-
// Set validation errors
|
|
3811
|
-
const validationErrorMessage = {
|
|
3812
|
-
type: 'validation',
|
|
3813
|
-
errors: validationResult.errors,
|
|
3814
|
-
message: translate.t('validation_error'),
|
|
3815
|
-
};
|
|
3816
|
-
onSubmitError(validationErrorMessage);
|
|
3817
|
-
return;
|
|
3818
|
-
}
|
|
3958
|
+
// AJV validation is now handled by react-hook-form resolver
|
|
3959
|
+
// This function will only be called if validation passes
|
|
3819
3960
|
if (onSubmit === undefined) {
|
|
3820
|
-
await defaultOnSubmit(defaultSubmitPromise(data));
|
|
3961
|
+
await defaultOnSubmit(Promise.resolve(defaultSubmitPromise(data)));
|
|
3821
3962
|
return;
|
|
3822
3963
|
}
|
|
3823
|
-
await defaultOnSubmit(onSubmit(data));
|
|
3964
|
+
await defaultOnSubmit(Promise.resolve(onSubmit(data)));
|
|
3824
3965
|
};
|
|
3825
3966
|
return (jsxRuntime.jsx(SchemaFormContext.Provider, { value: {
|
|
3826
3967
|
schema,
|
|
@@ -3856,6 +3997,8 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
3856
3997
|
dateTimePickerLabels,
|
|
3857
3998
|
idPickerLabels,
|
|
3858
3999
|
enumPickerLabels,
|
|
4000
|
+
filePickerLabels,
|
|
4001
|
+
ajvResolver: ajvResolver(schema),
|
|
3859
4002
|
}, children: jsxRuntime.jsx(reactHookForm.FormProvider, { ...form, children: children }) }));
|
|
3860
4003
|
};
|
|
3861
4004
|
|
|
@@ -3901,20 +4044,22 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
|
|
|
3901
4044
|
|
|
3902
4045
|
const Field = React__namespace.forwardRef(function Field(props, ref) {
|
|
3903
4046
|
const { label, children, helperText, errorText, optionalText, ...rest } = props;
|
|
3904
|
-
return (jsxRuntime.jsxs(react.Field.Root, { ref: ref, ...rest, children: [label && (jsxRuntime.jsxs(react.Field.Label, { children: [label, jsxRuntime.jsx(react.Field.RequiredIndicator, { fallback: optionalText })] })), children, helperText && (jsxRuntime.jsx(react.Field.HelperText, { children: helperText })), errorText && (jsxRuntime.
|
|
4047
|
+
return (jsxRuntime.jsxs(react.Field.Root, { ref: ref, ...rest, children: [label && (jsxRuntime.jsxs(react.Field.Label, { children: [label, jsxRuntime.jsx(react.Field.RequiredIndicator, { color: rest.invalid && rest.required ? 'red.500' : undefined, fallback: optionalText })] })), children, helperText && (jsxRuntime.jsx(react.Field.HelperText, { children: helperText })), !!errorText && (jsxRuntime.jsxs(react.Field.ErrorText, { children: [rest.required && rest.invalid && (jsxRuntime.jsx("span", { style: { color: 'var(--chakra-colors-red-500)' }, children: "* " })), errorText] }))] }));
|
|
3905
4048
|
});
|
|
3906
4049
|
|
|
3907
4050
|
const BooleanPicker = ({ schema, column, prefix }) => {
|
|
3908
4051
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
3909
4052
|
const { translate } = useSchemaContext();
|
|
3910
|
-
const { required, gridColumn =
|
|
4053
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
3911
4054
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
3912
4055
|
const colLabel = `${prefix}${column}`;
|
|
3913
4056
|
const value = watch(colLabel);
|
|
3914
|
-
return (jsxRuntime.
|
|
3915
|
-
gridRow,
|
|
3916
|
-
|
|
3917
|
-
|
|
4057
|
+
return (jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4058
|
+
gridRow, errorText: errors[`${colLabel}`]
|
|
4059
|
+
? translate.t(removeIndex(`${colLabel}.field_required`))
|
|
4060
|
+
: undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsx(CheckboxCard, { checked: value, variant: 'surface', onChange: () => {
|
|
4061
|
+
setValue(colLabel, !value);
|
|
4062
|
+
} }) }));
|
|
3918
4063
|
};
|
|
3919
4064
|
|
|
3920
4065
|
const CustomInput = ({ column, schema, prefix }) => {
|
|
@@ -4147,83 +4292,169 @@ const DatePicker = ({ column, schema, prefix }) => {
|
|
|
4147
4292
|
console.error(e);
|
|
4148
4293
|
}
|
|
4149
4294
|
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
4150
|
-
return (jsxRuntime.
|
|
4151
|
-
gridRow, children:
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4295
|
+
return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4296
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], 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: () => {
|
|
4297
|
+
setOpen(true);
|
|
4298
|
+
}, 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 }) => {
|
|
4299
|
+
setValue(colLabel, dayjs(date).format(dateFormat));
|
|
4300
|
+
setOpen(false);
|
|
4301
|
+
}, labels: {
|
|
4302
|
+
monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
|
|
4303
|
+
formI18n.translate.t(`common.month_1`, {
|
|
4304
|
+
defaultValue: 'January',
|
|
4305
|
+
}),
|
|
4306
|
+
formI18n.translate.t(`common.month_2`, {
|
|
4307
|
+
defaultValue: 'February',
|
|
4308
|
+
}),
|
|
4309
|
+
formI18n.translate.t(`common.month_3`, {
|
|
4310
|
+
defaultValue: 'March',
|
|
4311
|
+
}),
|
|
4312
|
+
formI18n.translate.t(`common.month_4`, {
|
|
4313
|
+
defaultValue: 'April',
|
|
4314
|
+
}),
|
|
4315
|
+
formI18n.translate.t(`common.month_5`, {
|
|
4316
|
+
defaultValue: 'May',
|
|
4317
|
+
}),
|
|
4318
|
+
formI18n.translate.t(`common.month_6`, {
|
|
4319
|
+
defaultValue: 'June',
|
|
4320
|
+
}),
|
|
4321
|
+
formI18n.translate.t(`common.month_7`, {
|
|
4322
|
+
defaultValue: 'July',
|
|
4323
|
+
}),
|
|
4324
|
+
formI18n.translate.t(`common.month_8`, {
|
|
4325
|
+
defaultValue: 'August',
|
|
4326
|
+
}),
|
|
4327
|
+
formI18n.translate.t(`common.month_9`, {
|
|
4328
|
+
defaultValue: 'September',
|
|
4329
|
+
}),
|
|
4330
|
+
formI18n.translate.t(`common.month_10`, {
|
|
4331
|
+
defaultValue: 'October',
|
|
4332
|
+
}),
|
|
4333
|
+
formI18n.translate.t(`common.month_11`, {
|
|
4334
|
+
defaultValue: 'November',
|
|
4335
|
+
}),
|
|
4336
|
+
formI18n.translate.t(`common.month_12`, {
|
|
4337
|
+
defaultValue: 'December',
|
|
4338
|
+
}),
|
|
4339
|
+
],
|
|
4340
|
+
weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
|
|
4341
|
+
formI18n.translate.t(`common.weekday_1`, {
|
|
4342
|
+
defaultValue: 'Sun',
|
|
4343
|
+
}),
|
|
4344
|
+
formI18n.translate.t(`common.weekday_2`, {
|
|
4345
|
+
defaultValue: 'Mon',
|
|
4346
|
+
}),
|
|
4347
|
+
formI18n.translate.t(`common.weekday_3`, {
|
|
4348
|
+
defaultValue: 'Tue',
|
|
4349
|
+
}),
|
|
4350
|
+
formI18n.translate.t(`common.weekday_4`, {
|
|
4351
|
+
defaultValue: 'Wed',
|
|
4352
|
+
}),
|
|
4353
|
+
formI18n.translate.t(`common.weekday_5`, {
|
|
4354
|
+
defaultValue: 'Thu',
|
|
4355
|
+
}),
|
|
4356
|
+
formI18n.translate.t(`common.weekday_6`, {
|
|
4357
|
+
defaultValue: 'Fri',
|
|
4358
|
+
}),
|
|
4359
|
+
formI18n.translate.t(`common.weekday_7`, {
|
|
4360
|
+
defaultValue: 'Sat',
|
|
4361
|
+
}),
|
|
4362
|
+
],
|
|
4363
|
+
backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
|
|
4364
|
+
formI18n.translate.t(`common.back_button`, {
|
|
4365
|
+
defaultValue: 'Back',
|
|
4366
|
+
}),
|
|
4367
|
+
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
|
|
4368
|
+
formI18n.translate.t(`common.forward_button`, {
|
|
4369
|
+
defaultValue: 'Forward',
|
|
4370
|
+
}),
|
|
4371
|
+
} })] }) })] }) }));
|
|
4372
|
+
};
|
|
4373
|
+
|
|
4374
|
+
dayjs.extend(utc);
|
|
4375
|
+
dayjs.extend(timezone);
|
|
4376
|
+
const DateRangePicker = ({ column, schema, prefix, }) => {
|
|
4377
|
+
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
4378
|
+
const { timezone, dateTimePickerLabels } = useSchemaContext();
|
|
4379
|
+
const formI18n = useFormI18n(column, prefix);
|
|
4380
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
|
|
4381
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
4382
|
+
const colLabel = formI18n.colLabel;
|
|
4383
|
+
const [open, setOpen] = React.useState(false);
|
|
4384
|
+
const selectedDateRange = watch(colLabel);
|
|
4385
|
+
// Convert string[] to Date[] for the picker
|
|
4386
|
+
const selectedDates = (selectedDateRange ?? [])
|
|
4387
|
+
.map((dateStr) => {
|
|
4388
|
+
if (!dateStr)
|
|
4389
|
+
return null;
|
|
4390
|
+
const parsed = dayjs(dateStr).tz(timezone);
|
|
4391
|
+
return parsed.isValid() ? parsed.toDate() : null;
|
|
4392
|
+
})
|
|
4393
|
+
.filter((date) => date !== null);
|
|
4394
|
+
// Format display string
|
|
4395
|
+
const getDisplayText = () => {
|
|
4396
|
+
if (!selectedDateRange || selectedDateRange.length === 0) {
|
|
4397
|
+
return '';
|
|
4398
|
+
}
|
|
4399
|
+
if (selectedDateRange.length === 1) {
|
|
4400
|
+
const date = dayjs(selectedDateRange[0]).tz(timezone);
|
|
4401
|
+
return date.isValid() ? date.format(displayDateFormat) : '';
|
|
4402
|
+
}
|
|
4403
|
+
if (selectedDateRange.length === 2) {
|
|
4404
|
+
const startDate = dayjs(selectedDateRange[0]).tz(timezone);
|
|
4405
|
+
const endDate = dayjs(selectedDateRange[1]).tz(timezone);
|
|
4406
|
+
if (startDate.isValid() && endDate.isValid()) {
|
|
4407
|
+
return `${startDate.format(displayDateFormat)} - ${endDate.format(displayDateFormat)}`;
|
|
4408
|
+
}
|
|
4409
|
+
}
|
|
4410
|
+
return '';
|
|
4411
|
+
};
|
|
4412
|
+
React.useEffect(() => {
|
|
4413
|
+
try {
|
|
4414
|
+
if (selectedDateRange && selectedDateRange.length > 0) {
|
|
4415
|
+
// Format dates according to dateFormat from schema
|
|
4416
|
+
const formatted = selectedDateRange
|
|
4417
|
+
.map((dateStr) => {
|
|
4418
|
+
if (!dateStr)
|
|
4419
|
+
return null;
|
|
4420
|
+
const parsed = dayjs(dateStr).tz(timezone);
|
|
4421
|
+
return parsed.isValid() ? parsed.format(dateFormat) : null;
|
|
4422
|
+
})
|
|
4423
|
+
.filter((date) => date !== null);
|
|
4424
|
+
// Update the form value only if different to avoid loops
|
|
4425
|
+
// Compare arrays element by element
|
|
4426
|
+
const needsUpdate = formatted.length !== selectedDateRange.length ||
|
|
4427
|
+
formatted.some((val, idx) => val !== selectedDateRange[idx]);
|
|
4428
|
+
if (needsUpdate && formatted.length > 0) {
|
|
4429
|
+
setValue(colLabel, formatted, {
|
|
4430
|
+
shouldValidate: true,
|
|
4431
|
+
shouldDirty: true,
|
|
4432
|
+
});
|
|
4433
|
+
}
|
|
4434
|
+
}
|
|
4435
|
+
}
|
|
4436
|
+
catch (e) {
|
|
4437
|
+
console.error(e);
|
|
4438
|
+
}
|
|
4439
|
+
}, [selectedDateRange, dateFormat, colLabel, setValue, timezone]);
|
|
4440
|
+
return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4441
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], 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: () => {
|
|
4442
|
+
setOpen(true);
|
|
4443
|
+
}, justifyContent: 'start', children: [jsxRuntime.jsx(md.MdDateRange, {}), getDisplayText()] }) }), jsxRuntime.jsx(PopoverContent, { minW: '600px', children: jsxRuntime.jsxs(PopoverBody, { children: [jsxRuntime.jsx(PopoverTitle, {}), jsxRuntime.jsx(RangeDatePicker, { selected: selectedDates, onDateSelected: ({ selected, selectable, date }) => {
|
|
4444
|
+
const newDates = getRangeDates({
|
|
4445
|
+
selectable,
|
|
4446
|
+
date,
|
|
4447
|
+
selectedDates,
|
|
4448
|
+
}) ?? [];
|
|
4449
|
+
// Convert Date[] to string[]
|
|
4450
|
+
const formattedDates = newDates
|
|
4451
|
+
.map((dateObj) => dayjs(dateObj).tz(timezone).format(dateFormat))
|
|
4452
|
+
.filter((dateStr) => dateStr);
|
|
4453
|
+
setValue(colLabel, formattedDates, {
|
|
4454
|
+
shouldValidate: true,
|
|
4455
|
+
shouldDirty: true,
|
|
4456
|
+
});
|
|
4457
|
+
}, monthsToDisplay: 2 })] }) })] }) }));
|
|
4227
4458
|
};
|
|
4228
4459
|
|
|
4229
4460
|
function filterArray(array, searchTerm) {
|
|
@@ -4258,7 +4489,9 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
|
|
|
4258
4489
|
};
|
|
4259
4490
|
if (variant === 'radio') {
|
|
4260
4491
|
return (jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4261
|
-
gridRow,
|
|
4492
|
+
gridRow, errorText: errors[`${colLabel}`]
|
|
4493
|
+
? translate.t(removeIndex(`${colLabel}.field_required`))
|
|
4494
|
+
: undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsx(react.RadioGroup.Root, { defaultValue: "1", children: jsxRuntime.jsx(react.HStack, { gap: "6", children: filterArray(dataList, searchText ?? '').map((item) => {
|
|
4262
4495
|
return (jsxRuntime.jsxs(react.RadioGroup.Item, { onClick: () => {
|
|
4263
4496
|
if (!isMultiple) {
|
|
4264
4497
|
setOpenSearchResult(false);
|
|
@@ -4273,7 +4506,9 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
|
|
|
4273
4506
|
}) }) }) }));
|
|
4274
4507
|
}
|
|
4275
4508
|
return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4276
|
-
gridRow,
|
|
4509
|
+
gridRow, errorText: errors[`${colLabel}`]
|
|
4510
|
+
? translate.t(removeIndex(`${colLabel}.field_required`))
|
|
4511
|
+
: undefined, invalid: !!errors[colLabel], children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow: 'wrap', gap: 1, children: [watchEnums.map((enumValue) => {
|
|
4277
4512
|
const item = enumValue;
|
|
4278
4513
|
if (!!item === false) {
|
|
4279
4514
|
return jsxRuntime.jsx(jsxRuntime.Fragment, {});
|
|
@@ -4328,7 +4563,7 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
|
|
|
4328
4563
|
? renderDisplay(item)
|
|
4329
4564
|
: translate.t(removeIndex(`${colLabel}.${item}`)) }, `${colLabel}-${item}`));
|
|
4330
4565
|
}) }), isDirty && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: dataList.length <= 0 && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: enumPickerLabels?.emptySearchResult ??
|
|
4331
|
-
translate.t(removeIndex(`${colLabel}.empty_search_result`)) })) }))] })] }) })] })
|
|
4566
|
+
translate.t(removeIndex(`${colLabel}.empty_search_result`)) })) }))] })] }) })] })] }));
|
|
4332
4567
|
};
|
|
4333
4568
|
|
|
4334
4569
|
function isEnteringWindow(_ref) {
|
|
@@ -4683,23 +4918,162 @@ const FileDropzone = ({ children = undefined, gridProps = {}, onDrop = () => { }
|
|
|
4683
4918
|
return (jsxRuntime.jsxs(react.Grid, { ...getColor(isDraggedOver), ref: ref, cursor: "pointer", onClick: handleClick, borderStyle: "dashed", borderColor: "colorPalette.400", alignContent: "center", justifyContent: "center", borderWidth: 1, borderRadius: 4, ...gridProps, children: [children, !!children === false && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(react.Flex, { children: placeholder }), jsxRuntime.jsx(react.Input, { type: "file", multiple: true, style: { display: "none" }, ref: fileInput, onChange: handleChange })] }))] }));
|
|
4684
4919
|
};
|
|
4685
4920
|
|
|
4921
|
+
/**
|
|
4922
|
+
* Format bytes to human-readable string
|
|
4923
|
+
* @param bytes - The number of bytes to format
|
|
4924
|
+
* @returns Formatted string (e.g., "1.5 KB", "2.3 MB")
|
|
4925
|
+
*/
|
|
4926
|
+
function formatBytes(bytes) {
|
|
4927
|
+
if (bytes === 0)
|
|
4928
|
+
return '0 Bytes';
|
|
4929
|
+
const k = 1024;
|
|
4930
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
|
4931
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
4932
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
|
|
4933
|
+
}
|
|
4934
|
+
|
|
4935
|
+
function FilePickerDialog({ open, onClose, onSelect, title, filterImageOnly = false, onFetchFiles, labels, translate, colLabel, }) {
|
|
4936
|
+
const [searchTerm, setSearchTerm] = React.useState('');
|
|
4937
|
+
const [selectedFileId, setSelectedFileId] = React.useState('');
|
|
4938
|
+
const { data: filesData, isLoading, isError, } = reactQuery.useQuery({
|
|
4939
|
+
queryKey: ['file-picker-library', searchTerm],
|
|
4940
|
+
queryFn: async () => {
|
|
4941
|
+
if (!onFetchFiles)
|
|
4942
|
+
return { data: [] };
|
|
4943
|
+
const files = await onFetchFiles(searchTerm.trim() || '');
|
|
4944
|
+
return { data: files };
|
|
4945
|
+
},
|
|
4946
|
+
enabled: open && !!onFetchFiles,
|
|
4947
|
+
});
|
|
4948
|
+
const files = (filesData?.data || []);
|
|
4949
|
+
const filteredFiles = filterImageOnly
|
|
4950
|
+
? files.filter((file) => /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name))
|
|
4951
|
+
: files;
|
|
4952
|
+
const handleSelect = () => {
|
|
4953
|
+
if (selectedFileId) {
|
|
4954
|
+
onSelect(selectedFileId);
|
|
4955
|
+
onClose();
|
|
4956
|
+
setSelectedFileId('');
|
|
4957
|
+
setSearchTerm('');
|
|
4958
|
+
}
|
|
4959
|
+
};
|
|
4960
|
+
const handleClose = () => {
|
|
4961
|
+
onClose();
|
|
4962
|
+
setSelectedFileId('');
|
|
4963
|
+
setSearchTerm('');
|
|
4964
|
+
};
|
|
4965
|
+
if (!onFetchFiles)
|
|
4966
|
+
return null;
|
|
4967
|
+
return (jsxRuntime.jsx(DialogRoot, { open: open, onOpenChange: (e) => !e.open && handleClose(), children: jsxRuntime.jsxs(DialogContent, { maxWidth: "800px", maxHeight: "90vh", children: [jsxRuntime.jsxs(DialogHeader, { children: [jsxRuntime.jsx(DialogTitle, { fontSize: "lg", fontWeight: "bold", children: title }), jsxRuntime.jsx(DialogCloseTrigger, {})] }), jsxRuntime.jsx(DialogBody, { children: jsxRuntime.jsxs(react.VStack, { align: "stretch", gap: 4, children: [jsxRuntime.jsxs(react.Box, { position: "relative", children: [jsxRuntime.jsx(react.Input, { placeholder: labels?.searchPlaceholder ??
|
|
4968
|
+
translate(removeIndex(`${colLabel}.search_placeholder`)) ??
|
|
4969
|
+
'Search files...', value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), bg: "bg.panel", border: "1px solid", borderColor: "border.default", _focus: {
|
|
4970
|
+
borderColor: 'blue.500',
|
|
4971
|
+
boxShadow: '0 0 0 1px var(--chakra-colors-blue-500)',
|
|
4972
|
+
}, pl: 10 }), jsxRuntime.jsx(react.Icon, { as: lu.LuSearch, position: "absolute", left: 3, top: "50%", transform: "translateY(-50%)", color: "fg.muted", boxSize: 4 })] }), isLoading && (jsxRuntime.jsxs(react.Box, { textAlign: "center", py: 8, children: [jsxRuntime.jsx(react.Spinner, { size: "lg", colorPalette: "blue" }), jsxRuntime.jsx(react.Text, { mt: 4, color: "fg.muted", children: labels?.loading ??
|
|
4973
|
+
translate(removeIndex(`${colLabel}.loading`)) ??
|
|
4974
|
+
'Loading files...' })] })), isError && (jsxRuntime.jsx(react.Box, { bg: "red.50", _dark: { bg: 'red.900/20' }, border: "1px solid", borderColor: "red.200", borderRadius: "md", p: 4, children: jsxRuntime.jsx(react.Text, { color: "red.600", _dark: { color: 'red.300' }, children: labels?.loadingFailed ??
|
|
4975
|
+
translate(removeIndex(`${colLabel}.error.loading_failed`)) ??
|
|
4976
|
+
'Failed to load files' }) })), !isLoading && !isError && (jsxRuntime.jsx(react.Box, { maxHeight: "400px", overflowY: "auto", children: filteredFiles.length === 0 ? (jsxRuntime.jsx(react.Box, { textAlign: "center", py: 8, children: jsxRuntime.jsx(react.Text, { color: "fg.muted", children: labels?.noFilesFound ??
|
|
4977
|
+
translate(removeIndex(`${colLabel}.no_files_found`)) ??
|
|
4978
|
+
'No files found' }) })) : (jsxRuntime.jsx(react.VStack, { align: "stretch", gap: 2, children: filteredFiles.map((file) => {
|
|
4979
|
+
const isImage = /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name);
|
|
4980
|
+
const isSelected = selectedFileId === file.id;
|
|
4981
|
+
return (jsxRuntime.jsx(react.Box, { p: 3, border: "2px solid", borderColor: isSelected ? 'blue.500' : 'border.default', borderRadius: "md", bg: isSelected ? 'blue.50' : 'bg.panel', _dark: {
|
|
4982
|
+
bg: isSelected ? 'blue.900/20' : 'bg.panel',
|
|
4983
|
+
}, cursor: "pointer", onClick: () => setSelectedFileId(file.id), _hover: {
|
|
4984
|
+
borderColor: isSelected ? 'blue.600' : 'blue.300',
|
|
4985
|
+
bg: isSelected ? 'blue.100' : 'bg.muted',
|
|
4986
|
+
}, transition: "all 0.2s", children: jsxRuntime.jsxs(react.HStack, { gap: 3, children: [jsxRuntime.jsx(react.Box, { width: "60px", height: "60px", display: "flex", alignItems: "center", justifyContent: "center", bg: "bg.muted", borderRadius: "md", flexShrink: 0, children: isImage && file.url ? (jsxRuntime.jsx(react.Image, { src: file.url, alt: file.name, boxSize: "60px", objectFit: "cover", borderRadius: "md" })) : (jsxRuntime.jsx(react.Icon, { as: lu.LuFile, boxSize: 6, color: "fg.muted" })) }), jsxRuntime.jsxs(react.VStack, { align: "start", flex: 1, gap: 1, children: [jsxRuntime.jsx(react.Text, { fontSize: "sm", fontWeight: "medium", color: "fg.default", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: file.name }), jsxRuntime.jsxs(react.HStack, { gap: 2, children: [file.size && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", children: typeof file.size === 'number'
|
|
4987
|
+
? formatBytes(file.size)
|
|
4988
|
+
: file.size }) })), file.comment && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [file.size && (jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", children: "\u2022" })), jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: file.comment })] }))] })] }), isSelected && (jsxRuntime.jsx(react.Box, { width: "24px", height: "24px", borderRadius: "full", bg: "blue.500", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, children: jsxRuntime.jsx(react.Text, { color: "white", fontSize: "xs", fontWeight: "bold", children: "\u2713" }) }))] }) }, file.id));
|
|
4989
|
+
}) })) }))] }) }), jsxRuntime.jsx(DialogFooter, { children: jsxRuntime.jsxs(react.HStack, { gap: 3, justify: "end", children: [jsxRuntime.jsx(react.Button, { variant: "outline", onClick: handleClose, borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: labels?.cancel ??
|
|
4990
|
+
translate(removeIndex(`${colLabel}.cancel`)) ??
|
|
4991
|
+
'Cancel' }), jsxRuntime.jsx(react.Button, { colorPalette: "blue", onClick: handleSelect, disabled: !selectedFileId, children: labels?.select ??
|
|
4992
|
+
translate(removeIndex(`${colLabel}.select`)) ??
|
|
4993
|
+
'Select' })] }) })] }) }));
|
|
4994
|
+
}
|
|
4686
4995
|
const FilePicker = ({ column, schema, prefix }) => {
|
|
4687
4996
|
const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
|
|
4688
|
-
const {
|
|
4689
|
-
const
|
|
4997
|
+
const { filePickerLabels } = useSchemaContext();
|
|
4998
|
+
const formI18n = useFormI18n(column, prefix);
|
|
4999
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', filePicker, } = schema;
|
|
4690
5000
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4691
|
-
const
|
|
4692
|
-
const
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
5001
|
+
const currentValue = watch(column) ?? [];
|
|
5002
|
+
const currentFiles = Array.isArray(currentValue)
|
|
5003
|
+
? currentValue
|
|
5004
|
+
: [];
|
|
5005
|
+
const colLabel = formI18n.colLabel;
|
|
5006
|
+
const [dialogOpen, setDialogOpen] = React.useState(false);
|
|
5007
|
+
const { onFetchFiles, enableMediaLibrary = false, filterImageOnly = false, } = filePicker || {};
|
|
5008
|
+
const showMediaLibrary = enableMediaLibrary && !!onFetchFiles;
|
|
5009
|
+
const handleMediaLibrarySelect = (fileId) => {
|
|
5010
|
+
const newFiles = [...currentFiles, fileId];
|
|
5011
|
+
setValue(colLabel, newFiles);
|
|
5012
|
+
};
|
|
5013
|
+
const handleRemove = (index) => {
|
|
5014
|
+
const newFiles = currentFiles.filter((_, i) => i !== index);
|
|
5015
|
+
setValue(colLabel, newFiles);
|
|
5016
|
+
};
|
|
5017
|
+
const isFileObject = (value) => {
|
|
5018
|
+
return value instanceof File;
|
|
5019
|
+
};
|
|
5020
|
+
const getFileIdentifier = (file, index) => {
|
|
5021
|
+
if (isFileObject(file)) {
|
|
5022
|
+
return `${file.name}-${file.size}-${index}`;
|
|
5023
|
+
}
|
|
5024
|
+
return file;
|
|
5025
|
+
};
|
|
5026
|
+
const getFileName = (file) => {
|
|
5027
|
+
if (isFileObject(file)) {
|
|
5028
|
+
return file.name;
|
|
5029
|
+
}
|
|
5030
|
+
return typeof file === 'string' ? file : 'Unknown file';
|
|
5031
|
+
};
|
|
5032
|
+
const getFileSize = (file) => {
|
|
5033
|
+
if (isFileObject(file)) {
|
|
5034
|
+
return file.size;
|
|
5035
|
+
}
|
|
5036
|
+
return undefined;
|
|
5037
|
+
};
|
|
5038
|
+
const isImageFile = (file) => {
|
|
5039
|
+
if (isFileObject(file)) {
|
|
5040
|
+
return file.type.startsWith('image/');
|
|
5041
|
+
}
|
|
5042
|
+
if (typeof file === 'string') {
|
|
5043
|
+
return /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file);
|
|
5044
|
+
}
|
|
5045
|
+
return false;
|
|
5046
|
+
};
|
|
5047
|
+
const getImageUrl = (file) => {
|
|
5048
|
+
if (isFileObject(file)) {
|
|
5049
|
+
return URL.createObjectURL(file);
|
|
5050
|
+
}
|
|
5051
|
+
return undefined;
|
|
5052
|
+
};
|
|
5053
|
+
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
5054
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [jsxRuntime.jsxs(react.VStack, { align: "stretch", gap: 2, children: [jsxRuntime.jsx(FileDropzone, { onDrop: ({ files }) => {
|
|
5055
|
+
const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => {
|
|
5056
|
+
if (isFileObject(cur)) {
|
|
5057
|
+
return cur.name === name;
|
|
5058
|
+
}
|
|
5059
|
+
return false;
|
|
5060
|
+
}));
|
|
5061
|
+
setValue(colLabel, [...currentFiles, ...newFiles]);
|
|
5062
|
+
}, placeholder: filePickerLabels?.fileDropzone ?? formI18n.t('fileDropzone') }), showMediaLibrary && (jsxRuntime.jsx(react.Button, { variant: "outline", onClick: () => setDialogOpen(true), borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: filePickerLabels?.browseLibrary ??
|
|
5063
|
+
formI18n.t('browse_library') ??
|
|
5064
|
+
'Browse from Library' }))] }), showMediaLibrary && (jsxRuntime.jsx(FilePickerDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ??
|
|
5065
|
+
formI18n.t('dialog_title') ??
|
|
5066
|
+
'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, labels: filePickerLabels, translate: formI18n.t, colLabel: colLabel })), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: currentFiles.map((file, index) => {
|
|
5067
|
+
const fileIdentifier = getFileIdentifier(file, index);
|
|
5068
|
+
const fileName = getFileName(file);
|
|
5069
|
+
const fileSize = getFileSize(file);
|
|
5070
|
+
const isImage = isImageFile(file);
|
|
5071
|
+
const imageUrl = getImageUrl(file);
|
|
5072
|
+
return (jsxRuntime.jsx(react.Card.Root, { variant: 'subtle', children: jsxRuntime.jsxs(react.Card.Body, { gap: "2", cursor: 'pointer', onClick: () => handleRemove(index), display: 'flex', flexFlow: 'row', alignItems: 'center', padding: '2', border: "2px solid", borderColor: "border.default", borderRadius: "md", _hover: {
|
|
5073
|
+
borderColor: 'blue.300',
|
|
5074
|
+
bg: 'bg.muted',
|
|
5075
|
+
}, transition: "all 0.2s", children: [jsxRuntime.jsx(react.Box, { width: "60px", height: "60px", display: "flex", alignItems: "center", justifyContent: "center", bg: "bg.muted", borderRadius: "md", flexShrink: 0, marginRight: "2", children: isImage && imageUrl ? (jsxRuntime.jsx(react.Image, { src: imageUrl, alt: fileName, boxSize: "60px", objectFit: "cover", borderRadius: "md" })) : (jsxRuntime.jsx(react.Icon, { as: lu.LuFile, boxSize: 6, color: "fg.muted" })) }), jsxRuntime.jsxs(react.VStack, { align: "start", flex: 1, gap: 1, children: [jsxRuntime.jsx(react.Text, { fontSize: "sm", fontWeight: "medium", color: "fg.default", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: fileName }), fileSize !== undefined && (jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", children: formatBytes(fileSize) }))] }), jsxRuntime.jsx(react.Icon, { as: ti.TiDeleteOutline, boxSize: 5, color: "fg.muted" })] }) }, fileIdentifier));
|
|
5076
|
+
}) })] }));
|
|
4703
5077
|
};
|
|
4704
5078
|
|
|
4705
5079
|
const ToggleTip = React__namespace.forwardRef(function ToggleTip(props, ref) {
|
|
@@ -4888,7 +5262,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4888
5262
|
return record[display_column];
|
|
4889
5263
|
};
|
|
4890
5264
|
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4891
|
-
gridRow, children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow: 'wrap', gap: 1, children: [watchIds.map((id) => {
|
|
5265
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow: 'wrap', gap: 1, children: [watchIds.map((id) => {
|
|
4892
5266
|
const item = idMap[id];
|
|
4893
5267
|
if (item === undefined) {
|
|
4894
5268
|
return (jsxRuntime.jsx(react.Text, { children: idPickerLabels?.undefined ?? formI18n.t('undefined') }, id));
|
|
@@ -4939,7 +5313,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4939
5313
|
? idPickerLabels?.emptySearchResult ??
|
|
4940
5314
|
formI18n.t('empty_search_result')
|
|
4941
5315
|
: idPickerLabels?.initialResults ??
|
|
4942
|
-
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, {})] }) })] }))] }) })] })
|
|
5316
|
+
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, {})] }) })] }))] }) })] })] }));
|
|
4943
5317
|
};
|
|
4944
5318
|
|
|
4945
5319
|
const NumberInputRoot = React__namespace.forwardRef(function NumberInput(props, ref) {
|
|
@@ -4950,20 +5324,84 @@ const NumberInputField$1 = react.NumberInput.Input;
|
|
|
4950
5324
|
react.NumberInput.Scrubber;
|
|
4951
5325
|
react.NumberInput.Label;
|
|
4952
5326
|
|
|
5327
|
+
/**
|
|
5328
|
+
* Gets the error message for a specific field from react-hook-form errors
|
|
5329
|
+
* Prioritizes required errors (#.required) over field-specific validation errors
|
|
5330
|
+
*/
|
|
5331
|
+
const getFieldError = (errors, fieldName) => {
|
|
5332
|
+
// Check for form-level required errors first (highest priority)
|
|
5333
|
+
const requiredError = errors['#.required'];
|
|
5334
|
+
if (requiredError) {
|
|
5335
|
+
const requiredErrorMessage = extractErrorMessage(requiredError);
|
|
5336
|
+
if (requiredErrorMessage) {
|
|
5337
|
+
return requiredErrorMessage;
|
|
5338
|
+
}
|
|
5339
|
+
}
|
|
5340
|
+
// If no required errors, return field-specific error
|
|
5341
|
+
const fieldError = errors[fieldName];
|
|
5342
|
+
if (fieldError) {
|
|
5343
|
+
const fieldErrorMessage = extractErrorMessage(fieldError);
|
|
5344
|
+
if (fieldErrorMessage) {
|
|
5345
|
+
return fieldErrorMessage;
|
|
5346
|
+
}
|
|
5347
|
+
}
|
|
5348
|
+
return undefined;
|
|
5349
|
+
};
|
|
5350
|
+
/**
|
|
5351
|
+
* Helper function to extract error message from various error formats
|
|
5352
|
+
* Only returns message if explicitly provided, no fallback text
|
|
5353
|
+
*/
|
|
5354
|
+
const extractErrorMessage = (error) => {
|
|
5355
|
+
if (!error) {
|
|
5356
|
+
return undefined;
|
|
5357
|
+
}
|
|
5358
|
+
// If it's a simple string error
|
|
5359
|
+
if (typeof error === 'string') {
|
|
5360
|
+
return error;
|
|
5361
|
+
}
|
|
5362
|
+
// If it's an error object with a message property
|
|
5363
|
+
if (error && typeof error === 'object' && 'message' in error) {
|
|
5364
|
+
return error.message;
|
|
5365
|
+
}
|
|
5366
|
+
// If it's an array of errors, get the first one
|
|
5367
|
+
if (Array.isArray(error) && error.length > 0) {
|
|
5368
|
+
const firstError = error[0];
|
|
5369
|
+
if (typeof firstError === 'string') {
|
|
5370
|
+
return firstError;
|
|
5371
|
+
}
|
|
5372
|
+
if (firstError &&
|
|
5373
|
+
typeof firstError === 'object' &&
|
|
5374
|
+
'message' in firstError) {
|
|
5375
|
+
return firstError.message;
|
|
5376
|
+
}
|
|
5377
|
+
}
|
|
5378
|
+
// No fallback - return undefined if no message provided
|
|
5379
|
+
return undefined;
|
|
5380
|
+
};
|
|
5381
|
+
|
|
4953
5382
|
const NumberInputField = ({ schema, column, prefix, }) => {
|
|
4954
5383
|
const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
|
|
4955
5384
|
const { translate } = useSchemaContext();
|
|
4956
|
-
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
5385
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', numberStorageType = 'number', } = schema;
|
|
4957
5386
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4958
5387
|
const colLabel = `${prefix}${column}`;
|
|
4959
5388
|
const value = watch(`${colLabel}`);
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
5389
|
+
const fieldError = getFieldError(errors, colLabel);
|
|
5390
|
+
return (jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, errorText: fieldError
|
|
5391
|
+
? fieldError.includes('required')
|
|
5392
|
+
? translate.t(removeIndex(`${colLabel}.field_required`))
|
|
5393
|
+
: fieldError
|
|
5394
|
+
: undefined, invalid: !!fieldError, children: jsxRuntime.jsx(NumberInputRoot, { value: value, onValueChange: (details) => {
|
|
5395
|
+
// Store as string or number based on configuration, default to number
|
|
5396
|
+
const value = numberStorageType === 'string'
|
|
5397
|
+
? details.value
|
|
5398
|
+
: details.valueAsNumber;
|
|
5399
|
+
setValue(`${colLabel}`, value);
|
|
5400
|
+
}, min: schema.minimum, max: schema.maximum, step: schema.multipleOf || 0.01, allowOverflow: false, clampValueOnBlur: false, inputMode: "decimal", formatOptions: schema.formatOptions, children: jsxRuntime.jsx(NumberInputField$1, { required: isRequired }) }) }));
|
|
4963
5401
|
};
|
|
4964
5402
|
|
|
4965
5403
|
const ObjectInput = ({ schema, column, prefix }) => {
|
|
4966
|
-
const { properties, gridColumn =
|
|
5404
|
+
const { properties, gridColumn = 'span 12', gridRow = 'span 1', required, showLabel = true, } = schema;
|
|
4967
5405
|
const { translate } = useSchemaContext();
|
|
4968
5406
|
const colLabel = `${prefix}${column}`;
|
|
4969
5407
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
@@ -4971,29 +5409,32 @@ const ObjectInput = ({ schema, column, prefix }) => {
|
|
|
4971
5409
|
if (properties === undefined) {
|
|
4972
5410
|
throw new Error(`properties is undefined when using ObjectInput`);
|
|
4973
5411
|
}
|
|
4974
|
-
return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [showLabel && (jsxRuntime.jsxs(react.Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsxRuntime.jsx("span", { children: "*" })] })), jsxRuntime.jsx(react.Grid, { bgColor: { base:
|
|
4975
|
-
base:
|
|
4976
|
-
_dark:
|
|
4977
|
-
}, gap: "4", padding:
|
|
5412
|
+
return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [showLabel && (jsxRuntime.jsxs(react.Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsxRuntime.jsx("span", { children: "*" })] })), jsxRuntime.jsx(react.Grid, { bgColor: { base: 'colorPalette.100', _dark: 'colorPalette.900' }, p: 2, borderRadius: 4, borderWidth: 1, borderColor: {
|
|
5413
|
+
base: 'colorPalette.200',
|
|
5414
|
+
_dark: 'colorPalette.800',
|
|
5415
|
+
}, gap: "4", padding: '4', gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: Object.keys(properties ?? {}).map((key) => {
|
|
4978
5416
|
return (
|
|
4979
5417
|
// @ts-expect-error find suitable types
|
|
4980
5418
|
jsxRuntime.jsx(ColumnRenderer, { column: `${key}`,
|
|
4981
5419
|
prefix: `${prefix}${column}.`,
|
|
4982
|
-
properties
|
|
4983
|
-
|
|
5420
|
+
properties,
|
|
5421
|
+
parentRequired: required }, `form-${colLabel}-${key}`));
|
|
5422
|
+
}) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
4984
5423
|
};
|
|
4985
5424
|
|
|
4986
5425
|
const RecordInput$1 = ({ column, schema, prefix }) => {
|
|
4987
5426
|
const { formState: { errors }, setValue, getValues, } = reactHookForm.useFormContext();
|
|
4988
5427
|
const { translate } = useSchemaContext();
|
|
4989
|
-
const { required, gridColumn =
|
|
5428
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
4990
5429
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4991
5430
|
const entries = Object.entries(getValues(column) ?? {});
|
|
4992
5431
|
const [showNewEntries, setShowNewEntries] = React.useState(false);
|
|
4993
5432
|
const [newKey, setNewKey] = React.useState();
|
|
4994
5433
|
const [newValue, setNewValue] = React.useState();
|
|
4995
|
-
return (jsxRuntime.jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems:
|
|
4996
|
-
|
|
5434
|
+
return (jsxRuntime.jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems: 'stretch', gridColumn, gridRow, errorText: errors[`${column}`]
|
|
5435
|
+
? translate.t(`${column}.field_required`)
|
|
5436
|
+
: undefined, invalid: !!errors[column], children: [entries.map(([key, value]) => {
|
|
5437
|
+
return (jsxRuntime.jsxs(react.Grid, { templateColumns: '1fr 1fr auto', gap: 1, children: [jsxRuntime.jsx(react.Input, { value: key, onChange: (e) => {
|
|
4997
5438
|
const filtered = entries.filter(([target]) => {
|
|
4998
5439
|
return target !== key;
|
|
4999
5440
|
});
|
|
@@ -5003,17 +5444,17 @@ const RecordInput$1 = ({ column, schema, prefix }) => {
|
|
|
5003
5444
|
...getValues(column),
|
|
5004
5445
|
[key]: e.target.value,
|
|
5005
5446
|
});
|
|
5006
|
-
}, autoComplete: "off" }), jsxRuntime.jsx(react.IconButton, { variant:
|
|
5447
|
+
}, autoComplete: "off" }), jsxRuntime.jsx(react.IconButton, { variant: 'ghost', onClick: () => {
|
|
5007
5448
|
const filtered = entries.filter(([target]) => {
|
|
5008
5449
|
return target !== key;
|
|
5009
5450
|
});
|
|
5010
5451
|
setValue(column, Object.fromEntries([...filtered]));
|
|
5011
5452
|
}, children: jsxRuntime.jsx(cg.CgClose, {}) })] }));
|
|
5012
|
-
}), jsxRuntime.jsx(react.Show, { when: showNewEntries, children: jsxRuntime.jsxs(react.Card.Root, { children: [jsxRuntime.jsx(react.Card.Body, { gap: "2", children: jsxRuntime.jsxs(react.Grid, { templateColumns:
|
|
5453
|
+
}), jsxRuntime.jsx(react.Show, { when: showNewEntries, children: jsxRuntime.jsxs(react.Card.Root, { children: [jsxRuntime.jsx(react.Card.Body, { gap: "2", children: jsxRuntime.jsxs(react.Grid, { templateColumns: '1fr 1fr auto', gap: 1, children: [jsxRuntime.jsx(react.Input, { value: newKey, onChange: (e) => {
|
|
5013
5454
|
setNewKey(e.target.value);
|
|
5014
5455
|
}, autoComplete: "off" }), jsxRuntime.jsx(react.Input, { value: newValue, onChange: (e) => {
|
|
5015
5456
|
setNewValue(e.target.value);
|
|
5016
|
-
}, autoComplete: "off" })] }) }), jsxRuntime.jsxs(react.Card.Footer, { justifyContent: "flex-end", children: [jsxRuntime.jsx(react.IconButton, { variant:
|
|
5457
|
+
}, autoComplete: "off" })] }) }), jsxRuntime.jsxs(react.Card.Footer, { justifyContent: "flex-end", children: [jsxRuntime.jsx(react.IconButton, { variant: 'subtle', onClick: () => {
|
|
5017
5458
|
setShowNewEntries(false);
|
|
5018
5459
|
setNewKey(undefined);
|
|
5019
5460
|
setNewValue(undefined);
|
|
@@ -5032,16 +5473,17 @@ const RecordInput$1 = ({ column, schema, prefix }) => {
|
|
|
5032
5473
|
setShowNewEntries(true);
|
|
5033
5474
|
setNewKey(undefined);
|
|
5034
5475
|
setNewValue(undefined);
|
|
5035
|
-
}, children: translate.t(`${column}.addNew`) })
|
|
5476
|
+
}, children: translate.t(`${column}.addNew`) })] }));
|
|
5036
5477
|
};
|
|
5037
5478
|
|
|
5038
5479
|
const StringInputField = ({ column, schema, prefix, }) => {
|
|
5039
5480
|
const { register, formState: { errors }, } = reactHookForm.useFormContext();
|
|
5040
5481
|
const { translate } = useSchemaContext();
|
|
5041
|
-
const { required, gridColumn =
|
|
5482
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
5042
5483
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5043
5484
|
const colLabel = `${prefix}${column}`;
|
|
5044
|
-
|
|
5485
|
+
const fieldError = getFieldError(errors, colLabel);
|
|
5486
|
+
return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, errorText: fieldError, invalid: !!fieldError, children: jsxRuntime.jsx(react.Input, { ...register(`${colLabel}`, { required: isRequired }), autoComplete: "off" }) }) }));
|
|
5045
5487
|
};
|
|
5046
5488
|
|
|
5047
5489
|
const RadioCardItem = React__namespace.forwardRef(function RadioCardItem(props, ref) {
|
|
@@ -5227,13 +5669,18 @@ Textarea.displayName = "Textarea";
|
|
|
5227
5669
|
const TextAreaInput = ({ column, schema, prefix, }) => {
|
|
5228
5670
|
const { register, formState: { errors }, } = reactHookForm.useFormContext();
|
|
5229
5671
|
const { translate } = useSchemaContext();
|
|
5230
|
-
const { required, gridColumn =
|
|
5672
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
5231
5673
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5232
5674
|
const colLabel = `${prefix}${column}`;
|
|
5233
5675
|
const form = reactHookForm.useFormContext();
|
|
5234
5676
|
const { setValue, watch } = form;
|
|
5677
|
+
const fieldError = getFieldError(errors, colLabel);
|
|
5235
5678
|
const watchValue = watch(colLabel);
|
|
5236
|
-
return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.
|
|
5679
|
+
return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn ?? 'span 4', gridRow: gridRow ?? 'span 1', display: "grid", errorText: fieldError
|
|
5680
|
+
? fieldError.includes('required')
|
|
5681
|
+
? translate.t(removeIndex(`${colLabel}.field_required`))
|
|
5682
|
+
: fieldError
|
|
5683
|
+
: undefined, invalid: !!fieldError, children: jsxRuntime.jsx(Textarea, { value: watchValue, onChange: (value) => setValue(colLabel, value) }) }) }));
|
|
5237
5684
|
};
|
|
5238
5685
|
|
|
5239
5686
|
function TimePicker$1({ hour, setHour, minute, setMinute, meridiem, setMeridiem, meridiemLabel = {
|
|
@@ -5364,25 +5811,25 @@ dayjs.extend(timezone);
|
|
|
5364
5811
|
const TimePicker = ({ column, schema, prefix }) => {
|
|
5365
5812
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
5366
5813
|
const { translate, timezone } = useSchemaContext();
|
|
5367
|
-
const { required, gridColumn =
|
|
5814
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', timeFormat = 'HH:mm:ssZ', displayTimeFormat = 'hh:mm A', } = schema;
|
|
5368
5815
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5369
5816
|
const colLabel = `${prefix}${column}`;
|
|
5370
5817
|
const [open, setOpen] = React.useState(false);
|
|
5371
5818
|
const value = watch(colLabel);
|
|
5372
5819
|
const displayedTime = dayjs(`1970-01-01T${value}`).tz(timezone).isValid()
|
|
5373
5820
|
? dayjs(`1970-01-01T${value}`).tz(timezone).format(displayTimeFormat)
|
|
5374
|
-
:
|
|
5821
|
+
: '';
|
|
5375
5822
|
// Parse the initial time parts from the time string (HH:mm:ssZ)
|
|
5376
5823
|
const parseTime = (time) => {
|
|
5377
5824
|
if (!time)
|
|
5378
|
-
return { hour: 12, minute: 0, meridiem:
|
|
5825
|
+
return { hour: 12, minute: 0, meridiem: 'am' };
|
|
5379
5826
|
const parsed = dayjs(`1970-01-01T${time}`).tz(timezone);
|
|
5380
5827
|
if (!parsed.isValid()) {
|
|
5381
|
-
return { hour: 12, minute: 0, meridiem:
|
|
5828
|
+
return { hour: 12, minute: 0, meridiem: 'am' };
|
|
5382
5829
|
}
|
|
5383
5830
|
let hour = parsed.hour();
|
|
5384
5831
|
const minute = parsed.minute();
|
|
5385
|
-
const meridiem = hour >= 12 ?
|
|
5832
|
+
const meridiem = hour >= 12 ? 'pm' : 'am';
|
|
5386
5833
|
if (hour === 0)
|
|
5387
5834
|
hour = 12;
|
|
5388
5835
|
else if (hour > 12)
|
|
@@ -5403,10 +5850,15 @@ const TimePicker = ({ column, schema, prefix }) => {
|
|
|
5403
5850
|
if (hour === null || minute === null || meridiem === null)
|
|
5404
5851
|
return null;
|
|
5405
5852
|
let newHour = hour;
|
|
5406
|
-
if (meridiem ===
|
|
5853
|
+
if (meridiem === 'pm' && hour !== 12) {
|
|
5407
5854
|
newHour = hour + 12;
|
|
5408
5855
|
}
|
|
5409
|
-
return dayjs()
|
|
5856
|
+
return dayjs()
|
|
5857
|
+
.tz(timezone)
|
|
5858
|
+
.hour(newHour)
|
|
5859
|
+
.minute(minute)
|
|
5860
|
+
.second(0)
|
|
5861
|
+
.format(timeFormat);
|
|
5410
5862
|
};
|
|
5411
5863
|
// Handle changes to time parts
|
|
5412
5864
|
const handleTimeChange = ({ hour: newHour, minute: newMinute, meridiem: newMeridiem, }) => {
|
|
@@ -5416,13 +5868,15 @@ const TimePicker = ({ column, schema, prefix }) => {
|
|
|
5416
5868
|
const timeString = getTimeString(newHour, newMinute, newMeridiem);
|
|
5417
5869
|
setValue(colLabel, timeString, { shouldValidate: true, shouldDirty: true });
|
|
5418
5870
|
};
|
|
5419
|
-
return (jsxRuntime.
|
|
5420
|
-
gridRow,
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5871
|
+
return (jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
|
|
5872
|
+
gridRow, errorText: errors[`${colLabel}`]
|
|
5873
|
+
? translate.t(removeIndex(`${colLabel}.field_required`))
|
|
5874
|
+
: undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsxs(react.Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(react.Popover.Trigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
5875
|
+
setOpen(true);
|
|
5876
|
+
}, justifyContent: 'start', children: [jsxRuntime.jsx(io.IoMdClock, {}), !!value ? `${displayedTime}` : ''] }) }), jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { children: jsxRuntime.jsx(react.Popover.Body, { children: jsxRuntime.jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, meridiemLabel: {
|
|
5877
|
+
am: translate.t(`common.am`, { defaultValue: 'AM' }),
|
|
5878
|
+
pm: translate.t(`common.pm`, { defaultValue: 'PM' }),
|
|
5879
|
+
} }) }) }) })] }) }));
|
|
5426
5880
|
};
|
|
5427
5881
|
|
|
5428
5882
|
function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond, onChange = (_newValue) => { }, }) {
|
|
@@ -5628,9 +6082,9 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
5628
6082
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
5629
6083
|
const { timezone, dateTimePickerLabels } = useSchemaContext();
|
|
5630
6084
|
const formI18n = useFormI18n(column, prefix);
|
|
5631
|
-
const { required, gridColumn =
|
|
6085
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD HH:mm:ss',
|
|
5632
6086
|
// with timezone
|
|
5633
|
-
dateFormat =
|
|
6087
|
+
dateFormat = 'YYYY-MM-DD[T]HH:mm:ssZ', } = schema;
|
|
5634
6088
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5635
6089
|
const colLabel = formI18n.colLabel;
|
|
5636
6090
|
const [open, setOpen] = React.useState(false);
|
|
@@ -5661,102 +6115,143 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
5661
6115
|
console.error(e);
|
|
5662
6116
|
}
|
|
5663
6117
|
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
5664
|
-
return (jsxRuntime.
|
|
5665
|
-
gridRow, children:
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
defaultValue:
|
|
6118
|
+
return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
6119
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], 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: () => {
|
|
6120
|
+
setOpen(true);
|
|
6121
|
+
}, 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) => {
|
|
6122
|
+
setValue(colLabel, dayjs(date).tz(timezone).format(dateFormat));
|
|
6123
|
+
}, timezone: timezone, labels: {
|
|
6124
|
+
monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
|
|
6125
|
+
formI18n.translate.t(`common.month_1`, {
|
|
6126
|
+
defaultValue: 'January',
|
|
6127
|
+
}),
|
|
6128
|
+
formI18n.translate.t(`common.month_2`, {
|
|
6129
|
+
defaultValue: 'February',
|
|
6130
|
+
}),
|
|
6131
|
+
formI18n.translate.t(`common.month_3`, {
|
|
6132
|
+
defaultValue: 'March',
|
|
6133
|
+
}),
|
|
6134
|
+
formI18n.translate.t(`common.month_4`, {
|
|
6135
|
+
defaultValue: 'April',
|
|
6136
|
+
}),
|
|
6137
|
+
formI18n.translate.t(`common.month_5`, {
|
|
6138
|
+
defaultValue: 'May',
|
|
6139
|
+
}),
|
|
6140
|
+
formI18n.translate.t(`common.month_6`, {
|
|
6141
|
+
defaultValue: 'June',
|
|
6142
|
+
}),
|
|
6143
|
+
formI18n.translate.t(`common.month_7`, {
|
|
6144
|
+
defaultValue: 'July',
|
|
6145
|
+
}),
|
|
6146
|
+
formI18n.translate.t(`common.month_8`, {
|
|
6147
|
+
defaultValue: 'August',
|
|
6148
|
+
}),
|
|
6149
|
+
formI18n.translate.t(`common.month_9`, {
|
|
6150
|
+
defaultValue: 'September',
|
|
6151
|
+
}),
|
|
6152
|
+
formI18n.translate.t(`common.month_10`, {
|
|
6153
|
+
defaultValue: 'October',
|
|
5697
6154
|
}),
|
|
5698
|
-
|
|
5699
|
-
defaultValue:
|
|
6155
|
+
formI18n.translate.t(`common.month_11`, {
|
|
6156
|
+
defaultValue: 'November',
|
|
5700
6157
|
}),
|
|
5701
|
-
|
|
6158
|
+
formI18n.translate.t(`common.month_12`, {
|
|
6159
|
+
defaultValue: 'December',
|
|
6160
|
+
}),
|
|
6161
|
+
],
|
|
6162
|
+
weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
|
|
6163
|
+
formI18n.translate.t(`common.weekday_1`, {
|
|
6164
|
+
defaultValue: 'Sun',
|
|
6165
|
+
}),
|
|
6166
|
+
formI18n.translate.t(`common.weekday_2`, {
|
|
6167
|
+
defaultValue: 'Mon',
|
|
6168
|
+
}),
|
|
6169
|
+
formI18n.translate.t(`common.weekday_3`, {
|
|
6170
|
+
defaultValue: 'Tue',
|
|
6171
|
+
}),
|
|
6172
|
+
formI18n.translate.t(`common.weekday_4`, {
|
|
6173
|
+
defaultValue: 'Wed',
|
|
6174
|
+
}),
|
|
6175
|
+
formI18n.translate.t(`common.weekday_5`, {
|
|
6176
|
+
defaultValue: 'Thu',
|
|
6177
|
+
}),
|
|
6178
|
+
formI18n.translate.t(`common.weekday_6`, {
|
|
6179
|
+
defaultValue: 'Fri',
|
|
6180
|
+
}),
|
|
6181
|
+
formI18n.translate.t(`common.weekday_7`, {
|
|
6182
|
+
defaultValue: 'Sat',
|
|
6183
|
+
}),
|
|
6184
|
+
],
|
|
6185
|
+
backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
|
|
6186
|
+
formI18n.translate.t(`common.back_button`, {
|
|
6187
|
+
defaultValue: 'Back',
|
|
6188
|
+
}),
|
|
6189
|
+
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
|
|
6190
|
+
formI18n.translate.t(`common.forward_button`, {
|
|
6191
|
+
defaultValue: 'Forward',
|
|
6192
|
+
}),
|
|
6193
|
+
} })] }) })] }) }));
|
|
5702
6194
|
};
|
|
5703
6195
|
|
|
5704
6196
|
const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
5705
6197
|
const colSchema = schema;
|
|
5706
6198
|
const { type, variant, properties: innerProperties, foreign_key, format, items, } = schema;
|
|
5707
|
-
if (variant ===
|
|
6199
|
+
if (variant === 'custom-input') {
|
|
5708
6200
|
return jsxRuntime.jsx(CustomInput, { schema: colSchema, prefix, column });
|
|
5709
6201
|
}
|
|
5710
|
-
if (type ===
|
|
6202
|
+
if (type === 'string') {
|
|
5711
6203
|
if ((schema.enum ?? []).length > 0) {
|
|
5712
6204
|
return jsxRuntime.jsx(EnumPicker, { schema: colSchema, prefix, column });
|
|
5713
6205
|
}
|
|
5714
|
-
if (variant ===
|
|
6206
|
+
if (variant === 'id-picker') {
|
|
5715
6207
|
idPickerSanityCheck(column, foreign_key);
|
|
5716
6208
|
return jsxRuntime.jsx(IdPicker, { schema: colSchema, prefix, column });
|
|
5717
6209
|
}
|
|
5718
|
-
if (format ===
|
|
6210
|
+
if (format === 'date') {
|
|
5719
6211
|
return jsxRuntime.jsx(DatePicker, { schema: colSchema, prefix, column });
|
|
5720
6212
|
}
|
|
5721
|
-
if (format ===
|
|
6213
|
+
if (format === 'time') {
|
|
5722
6214
|
return jsxRuntime.jsx(TimePicker, { schema: colSchema, prefix, column });
|
|
5723
6215
|
}
|
|
5724
|
-
if (format ===
|
|
6216
|
+
if (format === 'date-time') {
|
|
5725
6217
|
return jsxRuntime.jsx(DateTimePicker, { schema: colSchema, prefix, column });
|
|
5726
6218
|
}
|
|
5727
|
-
if (variant ===
|
|
6219
|
+
if (variant === 'text-area') {
|
|
5728
6220
|
return jsxRuntime.jsx(TextAreaInput, { schema: colSchema, prefix, column });
|
|
5729
6221
|
}
|
|
5730
6222
|
return jsxRuntime.jsx(StringInputField, { schema: colSchema, prefix, column });
|
|
5731
6223
|
}
|
|
5732
|
-
if (type ===
|
|
6224
|
+
if (type === 'number' || type === 'integer') {
|
|
5733
6225
|
return jsxRuntime.jsx(NumberInputField, { schema: colSchema, prefix, column });
|
|
5734
6226
|
}
|
|
5735
|
-
if (type ===
|
|
6227
|
+
if (type === 'boolean') {
|
|
5736
6228
|
return jsxRuntime.jsx(BooleanPicker, { schema: colSchema, prefix, column });
|
|
5737
6229
|
}
|
|
5738
|
-
if (type ===
|
|
6230
|
+
if (type === 'object') {
|
|
5739
6231
|
if (innerProperties) {
|
|
5740
6232
|
return jsxRuntime.jsx(ObjectInput, { schema: colSchema, prefix, column });
|
|
5741
6233
|
}
|
|
5742
6234
|
return jsxRuntime.jsx(RecordInput$1, { schema: colSchema, prefix, column });
|
|
5743
6235
|
}
|
|
5744
|
-
if (type ===
|
|
5745
|
-
if (variant ===
|
|
6236
|
+
if (type === 'array') {
|
|
6237
|
+
if (variant === 'id-picker') {
|
|
5746
6238
|
idPickerSanityCheck(column, foreign_key);
|
|
5747
6239
|
return (jsxRuntime.jsx(IdPicker, { schema: colSchema, prefix, column, isMultiple: true }));
|
|
5748
6240
|
}
|
|
5749
|
-
if (variant ===
|
|
6241
|
+
if (variant === 'tag-picker') {
|
|
5750
6242
|
return jsxRuntime.jsx(TagPicker, { schema: colSchema, prefix, column });
|
|
5751
6243
|
}
|
|
5752
|
-
if (variant ===
|
|
6244
|
+
if (variant === 'file-picker') {
|
|
5753
6245
|
return jsxRuntime.jsx(FilePicker, { schema: colSchema, prefix, column });
|
|
5754
6246
|
}
|
|
5755
|
-
if (variant ===
|
|
6247
|
+
if (variant === 'date-range') {
|
|
6248
|
+
return jsxRuntime.jsx(DateRangePicker, { schema: colSchema, prefix, column });
|
|
6249
|
+
}
|
|
6250
|
+
if (variant === 'enum-picker') {
|
|
5756
6251
|
const { items } = colSchema;
|
|
5757
6252
|
const { enum: enumItems } = items;
|
|
5758
6253
|
const enumSchema = {
|
|
5759
|
-
type:
|
|
6254
|
+
type: 'string',
|
|
5760
6255
|
enum: enumItems,
|
|
5761
6256
|
};
|
|
5762
6257
|
return (jsxRuntime.jsx(EnumPicker, { isMultiple: true, schema: enumSchema, prefix, column }));
|
|
@@ -5766,19 +6261,24 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
5766
6261
|
}
|
|
5767
6262
|
return jsxRuntime.jsx(react.Text, { children: `array ${column}` });
|
|
5768
6263
|
}
|
|
5769
|
-
if (type ===
|
|
6264
|
+
if (type === 'null') {
|
|
5770
6265
|
return jsxRuntime.jsx(react.Text, { children: `null ${column}` });
|
|
5771
6266
|
}
|
|
5772
6267
|
return jsxRuntime.jsx(react.Text, { children: "missing type" });
|
|
5773
6268
|
};
|
|
5774
6269
|
|
|
5775
|
-
const ColumnRenderer = ({ column, properties, prefix, }) => {
|
|
6270
|
+
const ColumnRenderer = ({ column, properties, prefix, parentRequired, }) => {
|
|
5776
6271
|
const colSchema = properties[column];
|
|
5777
6272
|
const colLabel = `${prefix}${column}`;
|
|
5778
6273
|
if (colSchema === undefined) {
|
|
5779
6274
|
throw new Error(`${colLabel} does not exist when using ColumnRenderer`);
|
|
5780
6275
|
}
|
|
5781
|
-
|
|
6276
|
+
// Merge parent's required array with the schema's required array
|
|
6277
|
+
const schemaWithRequired = {
|
|
6278
|
+
...colSchema,
|
|
6279
|
+
required: parentRequired || colSchema.required,
|
|
6280
|
+
};
|
|
6281
|
+
return jsxRuntime.jsx(SchemaRenderer, { schema: schemaWithRequired, prefix, column });
|
|
5782
6282
|
};
|
|
5783
6283
|
|
|
5784
6284
|
const ArrayViewer = ({ schema, column, prefix }) => {
|
|
@@ -6219,15 +6719,15 @@ const SubmitButton = () => {
|
|
|
6219
6719
|
const methods = reactHookForm.useFormContext();
|
|
6220
6720
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6221
6721
|
const onValid = (data) => {
|
|
6222
|
-
const { isValid, errors } = validateData(data, schema);
|
|
6223
|
-
if (!isValid) {
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
}
|
|
6722
|
+
// const { isValid, errors } = validateData(data, schema);
|
|
6723
|
+
// if (!isValid) {
|
|
6724
|
+
// setError({
|
|
6725
|
+
// type: 'validation',
|
|
6726
|
+
// errors,
|
|
6727
|
+
// });
|
|
6728
|
+
// setIsError(true);
|
|
6729
|
+
// return;
|
|
6730
|
+
// }
|
|
6231
6731
|
// If validation passes, check if confirmation is required
|
|
6232
6732
|
if (requireConfirmation) {
|
|
6233
6733
|
// Show confirmation (existing behavior)
|
|
@@ -6252,10 +6752,6 @@ const FormBody = () => {
|
|
|
6252
6752
|
const { showSubmitButton, showResetButton } = displayConfig;
|
|
6253
6753
|
const methods = reactHookForm.useFormContext();
|
|
6254
6754
|
const { properties } = schema;
|
|
6255
|
-
// Custom error renderer for validation errors with i18n support
|
|
6256
|
-
const renderValidationErrors = (validationErrors) => {
|
|
6257
|
-
return (jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: "2", children: validationErrors.map((err, index) => (jsxRuntime.jsxs(react.Alert.Root, { status: "error", display: "flex", alignItems: "center", children: [jsxRuntime.jsx(react.Alert.Indicator, {}), jsxRuntime.jsx(react.Alert.Content, { children: jsxRuntime.jsx(react.Alert.Description, { children: err.message }) })] }, index))) }));
|
|
6258
|
-
};
|
|
6259
6755
|
const renderColumns = ({ order, keys, ignore, include, }) => {
|
|
6260
6756
|
const included = include.length > 0 ? include : keys;
|
|
6261
6757
|
const not_exist = included.filter((columnA) => !order.some((columnB) => columnA === columnB));
|
|
@@ -6295,19 +6791,17 @@ const FormBody = () => {
|
|
|
6295
6791
|
setIsConfirming(false);
|
|
6296
6792
|
}, variant: 'subtle', children: translate.t('cancel') }), jsxRuntime.jsx(react.Button, { onClick: () => {
|
|
6297
6793
|
onFormSubmit(validatedData);
|
|
6298
|
-
}, children: translate.t('confirm') })] }), isSubmiting && (jsxRuntime.jsx(react.Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsxRuntime.jsx(react.Center, { h: "full", children: jsxRuntime.jsx(react.Spinner, { color: "teal.500" }) }) })), isError &&
|
|
6299
|
-
error?.errors ? (renderValidationErrors(error.errors)) : (jsxRuntime.jsxs(react.Alert.Root, { status: "error", children: [jsxRuntime.jsx(react.Alert.Indicator, {}), jsxRuntime.jsxs(react.Alert.Content, { children: [jsxRuntime.jsx(react.Alert.Title, { children: "Error" }), jsxRuntime.jsx(react.Alert.Description, { children: jsxRuntime.jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxRuntime.jsxs(AccordionItem, { value: 'b', children: [jsxRuntime.jsx(AccordionItemTrigger, { children: `${error}` }), jsxRuntime.jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) })] })] })) })) }))] }));
|
|
6794
|
+
}, children: translate.t('confirm') })] }), isSubmiting && (jsxRuntime.jsx(react.Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsxRuntime.jsx(react.Center, { h: "full", children: jsxRuntime.jsx(react.Spinner, { color: "teal.500" }) }) })), isError && customErrorRenderer && customErrorRenderer(error)] }));
|
|
6300
6795
|
}
|
|
6301
6796
|
return (jsxRuntime.jsxs(react.Flex, { flexFlow: 'column', gap: "2", children: [jsxRuntime.jsx(react.Grid, { gap: "4", gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: ordered.map((column) => {
|
|
6302
6797
|
return (jsxRuntime.jsx(ColumnRenderer
|
|
6303
6798
|
// @ts-expect-error find suitable types
|
|
6304
6799
|
, {
|
|
6305
6800
|
// @ts-expect-error find suitable types
|
|
6306
|
-
properties: properties, prefix: ``, column }, `form-input-${column}`));
|
|
6801
|
+
properties: properties, prefix: ``, parentRequired: schema.required, column }, `form-input-${column}`));
|
|
6307
6802
|
}) }), jsxRuntime.jsxs(react.Flex, { justifyContent: 'end', gap: "2", children: [showResetButton && (jsxRuntime.jsx(react.Button, { onClick: () => {
|
|
6308
6803
|
methods.reset();
|
|
6309
|
-
}, variant: 'subtle', children: translate.t('reset') })), showSubmitButton && jsxRuntime.jsx(SubmitButton, {})] }), isError &&
|
|
6310
|
-
error?.errors ? (renderValidationErrors(error.errors)) : (jsxRuntime.jsxs(react.Alert.Root, { status: "error", children: [jsxRuntime.jsx(react.Alert.Indicator, {}), jsxRuntime.jsxs(react.Alert.Content, { children: [jsxRuntime.jsx(react.Alert.Title, { children: "Error" }), jsxRuntime.jsx(react.Alert.Description, { children: jsxRuntime.jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxRuntime.jsxs(AccordionItem, { value: 'b', children: [jsxRuntime.jsx(AccordionItemTrigger, { children: `${error}` }), jsxRuntime.jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) })] })] })) })) }))] }));
|
|
6804
|
+
}, variant: 'subtle', children: translate.t('reset') })), showSubmitButton && jsxRuntime.jsx(SubmitButton, {})] }), isError && customErrorRenderer && customErrorRenderer(error)] }));
|
|
6311
6805
|
};
|
|
6312
6806
|
|
|
6313
6807
|
const FormTitle = () => {
|
|
@@ -6320,12 +6814,15 @@ const DefaultForm = ({ formConfig, }) => {
|
|
|
6320
6814
|
return (jsxRuntime.jsx(FormRoot, { ...formConfig, children: jsxRuntime.jsxs(react.Grid, { gap: "2", children: [showTitle && jsxRuntime.jsx(FormTitle, {}), jsxRuntime.jsx(FormBody, {})] }) }));
|
|
6321
6815
|
};
|
|
6322
6816
|
|
|
6323
|
-
const useForm = ({ preLoadedValues, keyPrefix, namespace }) => {
|
|
6817
|
+
const useForm = ({ preLoadedValues, keyPrefix, namespace, schema, }) => {
|
|
6324
6818
|
const form = reactHookForm.useForm({
|
|
6325
6819
|
values: preLoadedValues,
|
|
6820
|
+
resolver: schema ? ajvResolver(schema) : undefined,
|
|
6821
|
+
mode: 'onBlur',
|
|
6822
|
+
reValidateMode: 'onBlur',
|
|
6326
6823
|
});
|
|
6327
6824
|
const [idMap, setIdMap] = React.useState({});
|
|
6328
|
-
const translate = reactI18next.useTranslation(namespace ||
|
|
6825
|
+
const translate = reactI18next.useTranslation(namespace || '', { keyPrefix });
|
|
6329
6826
|
return {
|
|
6330
6827
|
form,
|
|
6331
6828
|
idMap,
|
|
@@ -6395,15 +6892,15 @@ const buildErrorMessages = (config) => {
|
|
|
6395
6892
|
}
|
|
6396
6893
|
// Add global fallback error messages
|
|
6397
6894
|
const globalKeys = [
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6895
|
+
'minLength',
|
|
6896
|
+
'maxLength',
|
|
6897
|
+
'pattern',
|
|
6898
|
+
'minimum',
|
|
6899
|
+
'maximum',
|
|
6900
|
+
'multipleOf',
|
|
6901
|
+
'format',
|
|
6902
|
+
'type',
|
|
6903
|
+
'enum',
|
|
6407
6904
|
];
|
|
6408
6905
|
globalKeys.forEach((key) => {
|
|
6409
6906
|
if (config[key]) {
|
|
@@ -6412,6 +6909,46 @@ const buildErrorMessages = (config) => {
|
|
|
6412
6909
|
});
|
|
6413
6910
|
return result;
|
|
6414
6911
|
};
|
|
6912
|
+
/**
|
|
6913
|
+
* Converts buildErrorMessages result to ajv-errors compatible format
|
|
6914
|
+
*/
|
|
6915
|
+
const convertToAjvErrorsFormat = (errorMessages) => {
|
|
6916
|
+
const result = {};
|
|
6917
|
+
// Convert required field errors
|
|
6918
|
+
if (errorMessages.required) {
|
|
6919
|
+
result.required = errorMessages.required;
|
|
6920
|
+
}
|
|
6921
|
+
// Convert properties errors to ajv-errors format
|
|
6922
|
+
if (errorMessages.properties) {
|
|
6923
|
+
result.properties = {};
|
|
6924
|
+
Object.keys(errorMessages.properties).forEach((fieldName) => {
|
|
6925
|
+
const fieldErrors = errorMessages.properties[fieldName];
|
|
6926
|
+
result.properties[fieldName] = {};
|
|
6927
|
+
Object.keys(fieldErrors).forEach((keyword) => {
|
|
6928
|
+
result.properties[fieldName][keyword] =
|
|
6929
|
+
fieldErrors[keyword];
|
|
6930
|
+
});
|
|
6931
|
+
});
|
|
6932
|
+
}
|
|
6933
|
+
// Add global fallback errors
|
|
6934
|
+
const globalKeys = [
|
|
6935
|
+
'minLength',
|
|
6936
|
+
'maxLength',
|
|
6937
|
+
'pattern',
|
|
6938
|
+
'minimum',
|
|
6939
|
+
'maximum',
|
|
6940
|
+
'multipleOf',
|
|
6941
|
+
'format',
|
|
6942
|
+
'type',
|
|
6943
|
+
'enum',
|
|
6944
|
+
];
|
|
6945
|
+
globalKeys.forEach((key) => {
|
|
6946
|
+
if (errorMessages[key]) {
|
|
6947
|
+
result[key] = errorMessages[key];
|
|
6948
|
+
}
|
|
6949
|
+
});
|
|
6950
|
+
return result;
|
|
6951
|
+
};
|
|
6415
6952
|
/**
|
|
6416
6953
|
* Helper function to build required field errors
|
|
6417
6954
|
*
|
|
@@ -6454,10 +6991,10 @@ const buildErrorMessages = (config) => {
|
|
|
6454
6991
|
* // Result: { username: "user.username.field_required", email: "user.email.field_required" }
|
|
6455
6992
|
* ```
|
|
6456
6993
|
*/
|
|
6457
|
-
const buildRequiredErrors = (fields, messageOrGenerator, keyPrefix =
|
|
6994
|
+
const buildRequiredErrors = (fields, messageOrGenerator, keyPrefix = '') => {
|
|
6458
6995
|
const result = {};
|
|
6459
6996
|
fields.forEach((field) => {
|
|
6460
|
-
if (typeof messageOrGenerator ===
|
|
6997
|
+
if (typeof messageOrGenerator === 'function') {
|
|
6461
6998
|
const message = messageOrGenerator(field);
|
|
6462
6999
|
result[field] = keyPrefix ? `${keyPrefix}.${message}` : message;
|
|
6463
7000
|
}
|
|
@@ -6528,11 +7065,14 @@ const buildFieldErrors = (config) => {
|
|
|
6528
7065
|
* ```
|
|
6529
7066
|
*/
|
|
6530
7067
|
const createErrorMessage = (required, properties, globalFallbacks) => {
|
|
6531
|
-
|
|
7068
|
+
const config = {
|
|
6532
7069
|
required,
|
|
6533
7070
|
properties,
|
|
6534
|
-
|
|
6535
|
-
|
|
7071
|
+
};
|
|
7072
|
+
if (globalFallbacks) {
|
|
7073
|
+
Object.assign(config, globalFallbacks);
|
|
7074
|
+
}
|
|
7075
|
+
return buildErrorMessages(config);
|
|
6536
7076
|
};
|
|
6537
7077
|
|
|
6538
7078
|
const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) => {
|
|
@@ -6595,6 +7135,7 @@ exports.ViewDialog = ViewDialog;
|
|
|
6595
7135
|
exports.buildErrorMessages = buildErrorMessages;
|
|
6596
7136
|
exports.buildFieldErrors = buildFieldErrors;
|
|
6597
7137
|
exports.buildRequiredErrors = buildRequiredErrors;
|
|
7138
|
+
exports.convertToAjvErrorsFormat = convertToAjvErrorsFormat;
|
|
6598
7139
|
exports.createErrorMessage = createErrorMessage;
|
|
6599
7140
|
exports.getColumns = getColumns;
|
|
6600
7141
|
exports.getMultiDates = getMultiDates;
|