@openg2p/registry-widgets 1.1.0 → 1.1.2-dev.0
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/components/SectionBuilder/schemas.d.ts +48 -0
- package/dist/components/SectionBuilder/schemas.d.ts.map +1 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.esm.js +413 -128
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +412 -126
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/dateInput.d.ts +17 -1
- package/dist/utils/dateInput.d.ts.map +1 -1
- package/dist/utils/numberInput.d.ts +1 -0
- package/dist/utils/numberInput.d.ts.map +1 -1
- package/dist/utils/sectionValidate.d.ts.map +1 -1
- package/dist/widgets/BooleanWidget.d.ts.map +1 -1
- package/dist/widgets/DateInputWidget.d.ts +5 -0
- package/dist/widgets/DateInputWidget.d.ts.map +1 -1
- package/dist/widgets/DialogTableWidget.d.ts.map +1 -1
- package/dist/widgets/HeaderSectionWidget.d.ts.map +1 -1
- package/dist/widgets/NumberInputWidget.d.ts +2 -0
- package/dist/widgets/NumberInputWidget.d.ts.map +1 -1
- package/dist/widgets/TableWidget.d.ts.map +1 -1
- package/package.json +6 -1
- package/LICENSE +0 -373
- package/README.md +0 -433
- package/dist/events/types.d.ts +0 -27
- package/dist/events/types.d.ts.map +0 -1
- package/dist/index.css +0 -4
- package/dist/index.css.map +0 -1
package/dist/index.js
CHANGED
|
@@ -673,6 +673,21 @@ const getFormattedNumberLength = (value, format) => {
|
|
|
673
673
|
const formatted = formatNumber(typeof value === 'string' ? parseFloat(value) : value, format);
|
|
674
674
|
return formatted.length;
|
|
675
675
|
};
|
|
676
|
+
const normalizeNumericDefault = (defaultValue, format) => {
|
|
677
|
+
if (defaultValue === undefined) {
|
|
678
|
+
return undefined;
|
|
679
|
+
}
|
|
680
|
+
if (defaultValue === null || defaultValue === '') {
|
|
681
|
+
return null;
|
|
682
|
+
}
|
|
683
|
+
const numValue = typeof defaultValue === 'number'
|
|
684
|
+
? defaultValue
|
|
685
|
+
: parseNumber(String(defaultValue), format);
|
|
686
|
+
if (numValue === null || isNaN(numValue)) {
|
|
687
|
+
return undefined;
|
|
688
|
+
}
|
|
689
|
+
return applyDecimalPrecision(numValue, format);
|
|
690
|
+
};
|
|
676
691
|
|
|
677
692
|
/**
|
|
678
693
|
* Date input utilities for parsing, formatting, and validation
|
|
@@ -808,6 +823,40 @@ const parseDateFromFormat = (dateString, format) => {
|
|
|
808
823
|
}
|
|
809
824
|
return parseDate(dateString);
|
|
810
825
|
};
|
|
826
|
+
/**
|
|
827
|
+
* Resolve a stored date value (ISO or parseable string) to YYYY-MM-DD for comparisons.
|
|
828
|
+
*/
|
|
829
|
+
const resolveDateBoundFromFieldValue = (fieldValue) => {
|
|
830
|
+
if (fieldValue == null || fieldValue === '') {
|
|
831
|
+
return undefined;
|
|
832
|
+
}
|
|
833
|
+
const iso = formatDateToISO(fieldValue);
|
|
834
|
+
return iso || undefined;
|
|
835
|
+
};
|
|
836
|
+
/**
|
|
837
|
+
* Pick the stricter (later) minimum when combining static and field-based bounds.
|
|
838
|
+
*/
|
|
839
|
+
const mergeMinDateBounds = (boundA, boundB) => {
|
|
840
|
+
if (!boundA) {
|
|
841
|
+
return boundB;
|
|
842
|
+
}
|
|
843
|
+
if (!boundB) {
|
|
844
|
+
return boundA;
|
|
845
|
+
}
|
|
846
|
+
return boundA > boundB ? boundA : boundB;
|
|
847
|
+
};
|
|
848
|
+
/**
|
|
849
|
+
* Pick the stricter (earlier) maximum when combining static and field-based bounds.
|
|
850
|
+
*/
|
|
851
|
+
const mergeMaxDateBounds = (boundA, boundB) => {
|
|
852
|
+
if (!boundA) {
|
|
853
|
+
return boundB;
|
|
854
|
+
}
|
|
855
|
+
if (!boundB) {
|
|
856
|
+
return boundA;
|
|
857
|
+
}
|
|
858
|
+
return boundA < boundB ? boundA : boundB;
|
|
859
|
+
};
|
|
811
860
|
/**
|
|
812
861
|
* Get min date based on constraint type
|
|
813
862
|
*/
|
|
@@ -850,10 +899,7 @@ const getMaxDate = (constraint, maxDate) => {
|
|
|
850
899
|
}
|
|
851
900
|
return undefined;
|
|
852
901
|
};
|
|
853
|
-
|
|
854
|
-
* Validate date constraints
|
|
855
|
-
*/
|
|
856
|
-
const validateDateConstraints = (date, minDate, maxDate, constraint) => {
|
|
902
|
+
const validateDateConstraints = (date, minDate, maxDate, constraint, messages) => {
|
|
857
903
|
if (!date)
|
|
858
904
|
return null;
|
|
859
905
|
const dateObj = date instanceof Date ? date : parseDate(date);
|
|
@@ -872,15 +918,12 @@ const validateDateConstraints = (date, minDate, maxDate, constraint) => {
|
|
|
872
918
|
return 'Date must be in the future';
|
|
873
919
|
}
|
|
874
920
|
}
|
|
875
|
-
//
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
return `Date must be on or after ${effectiveMinDate}`;
|
|
921
|
+
// minDate / maxDate are effective bounds (static + field-based), resolved by the caller
|
|
922
|
+
if (minDate && dateISO < minDate) {
|
|
923
|
+
return messages?.minDateMessage ?? `Date must be on or after ${minDate}`;
|
|
879
924
|
}
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
if (effectiveMaxDate && dateISO > effectiveMaxDate) {
|
|
883
|
-
return `Date must be on or before ${effectiveMaxDate}`;
|
|
925
|
+
if (maxDate && dateISO > maxDate) {
|
|
926
|
+
return messages?.maxDateMessage ?? `Date must be on or before ${maxDate}`;
|
|
884
927
|
}
|
|
885
928
|
return null;
|
|
886
929
|
};
|
|
@@ -3794,6 +3837,116 @@ const namespaceSectionConfig = (section, namespace) => {
|
|
|
3794
3837
|
return namespaced;
|
|
3795
3838
|
};
|
|
3796
3839
|
|
|
3840
|
+
/** Table-style widgets that bind to an array path in the store / schema. */
|
|
3841
|
+
function isTableLikeWidget(widget) {
|
|
3842
|
+
const w = widget.widget;
|
|
3843
|
+
/** widget-type union in types omits legacy values like simple-table still used at runtime */
|
|
3844
|
+
const t = widget['widget-type'];
|
|
3845
|
+
return (w === 'table' ||
|
|
3846
|
+
w === 'dialog-table' ||
|
|
3847
|
+
w === 'simple-table' ||
|
|
3848
|
+
t === 'table' ||
|
|
3849
|
+
t === 'simple-table');
|
|
3850
|
+
}
|
|
3851
|
+
/**
|
|
3852
|
+
* Resolve `records` for section save payloads.
|
|
3853
|
+
* - Back-compat: path ending in `.records` (e.g. `regId.records`)
|
|
3854
|
+
* - Else: first array snapshot at a string `widget-data-path` on a table-like widget
|
|
3855
|
+
* (e.g. `household.members` for dialog-table)
|
|
3856
|
+
*/
|
|
3857
|
+
function extractTableRecordsFromSnapshot(snapshot, sectionWidgets) {
|
|
3858
|
+
const convention = Object.entries(snapshot).find(([key, value]) => key.endsWith('.records') && Array.isArray(value));
|
|
3859
|
+
if (convention) {
|
|
3860
|
+
return convention[1];
|
|
3861
|
+
}
|
|
3862
|
+
const tablePaths = [];
|
|
3863
|
+
sectionWidgets.forEach((widget) => {
|
|
3864
|
+
if (!isTableLikeWidget(widget))
|
|
3865
|
+
return;
|
|
3866
|
+
const p = widget['widget-data-path'];
|
|
3867
|
+
if (typeof p === 'string' && p.length > 0) {
|
|
3868
|
+
tablePaths.push(p);
|
|
3869
|
+
}
|
|
3870
|
+
else if (p && typeof p === 'object') {
|
|
3871
|
+
Object.values(p).forEach((sub) => {
|
|
3872
|
+
if (typeof sub === 'string' && sub.length > 0)
|
|
3873
|
+
tablePaths.push(sub);
|
|
3874
|
+
});
|
|
3875
|
+
}
|
|
3876
|
+
});
|
|
3877
|
+
for (const path of tablePaths) {
|
|
3878
|
+
const val = snapshot[path];
|
|
3879
|
+
if (Array.isArray(val)) {
|
|
3880
|
+
return val;
|
|
3881
|
+
}
|
|
3882
|
+
}
|
|
3883
|
+
return [];
|
|
3884
|
+
}
|
|
3885
|
+
|
|
3886
|
+
const isColumnRequired = (column, skipRequired) => {
|
|
3887
|
+
if (skipRequired)
|
|
3888
|
+
return false;
|
|
3889
|
+
const validation = column['widget-data-validation'];
|
|
3890
|
+
return !!(column['widget-required'] || validation?.required);
|
|
3891
|
+
};
|
|
3892
|
+
const validateTableLikeWidget = (widget, currentSchemaData, dispatch, skipRequired) => {
|
|
3893
|
+
const widgetId = widget['widget-id'];
|
|
3894
|
+
if (!widgetId)
|
|
3895
|
+
return true;
|
|
3896
|
+
const columns = (widget['widget-data-columns'] || []);
|
|
3897
|
+
const value = getWidgetValue(currentSchemaData, widget['widget-data-path'], widgetId);
|
|
3898
|
+
const rows = Array.isArray(value)
|
|
3899
|
+
? value
|
|
3900
|
+
: [];
|
|
3901
|
+
const activeRows = rows.filter((row) => row?.edit_action !== 'DELETE');
|
|
3902
|
+
const rowErrors = [];
|
|
3903
|
+
let isValid = true;
|
|
3904
|
+
if (!skipRequired && widget['widget-required'] && activeRows.length === 0) {
|
|
3905
|
+
dispatch(setTouched({ widgetId, touched: true }));
|
|
3906
|
+
dispatch(setError({ widgetId, errors: ['At least one record is required'] }));
|
|
3907
|
+
return false;
|
|
3908
|
+
}
|
|
3909
|
+
const hasRequiredColumns = columns.some((col) => isColumnRequired(col, skipRequired));
|
|
3910
|
+
if (!skipRequired && hasRequiredColumns && activeRows.length === 0) {
|
|
3911
|
+
dispatch(setTouched({ widgetId, touched: true }));
|
|
3912
|
+
dispatch(setError({
|
|
3913
|
+
widgetId,
|
|
3914
|
+
errors: ['Add at least one record and fill all required fields'],
|
|
3915
|
+
}));
|
|
3916
|
+
return false;
|
|
3917
|
+
}
|
|
3918
|
+
activeRows.forEach((row, rowIndex) => {
|
|
3919
|
+
columns.forEach((col) => {
|
|
3920
|
+
if (col['widget-readonly'])
|
|
3921
|
+
return;
|
|
3922
|
+
const key = col['column-key'];
|
|
3923
|
+
if (!key)
|
|
3924
|
+
return;
|
|
3925
|
+
const required = isColumnRequired(col, skipRequired);
|
|
3926
|
+
const cellValue = row[key];
|
|
3927
|
+
const errors = validateWidget(cellValue, col['widget-data-validation'], required, skipRequired);
|
|
3928
|
+
if (errors.length > 0) {
|
|
3929
|
+
isValid = false;
|
|
3930
|
+
const label = col['widget-label'] || key;
|
|
3931
|
+
rowErrors.push(`Row ${rowIndex + 1}, ${label}: ${errors[0]}`);
|
|
3932
|
+
}
|
|
3933
|
+
});
|
|
3934
|
+
});
|
|
3935
|
+
if (!isValid) {
|
|
3936
|
+
dispatch(setTouched({ widgetId, touched: true }));
|
|
3937
|
+
dispatch(setError({
|
|
3938
|
+
widgetId,
|
|
3939
|
+
errors: rowErrors.length > 0
|
|
3940
|
+
? rowErrors.slice(0, 5)
|
|
3941
|
+
: ['Please fix required fields in the table'],
|
|
3942
|
+
}));
|
|
3943
|
+
}
|
|
3944
|
+
else {
|
|
3945
|
+
dispatch(setTouched({ widgetId, touched: false }));
|
|
3946
|
+
dispatch(setError({ widgetId, errors: [] }));
|
|
3947
|
+
}
|
|
3948
|
+
return isValid;
|
|
3949
|
+
};
|
|
3797
3950
|
const collectWidgets = (panels) => {
|
|
3798
3951
|
let widgets = [];
|
|
3799
3952
|
panels.forEach((panel) => {
|
|
@@ -3822,6 +3975,13 @@ const sectionValidate = (section, currentSchemaData, dispatch, skipRequired = fa
|
|
|
3822
3975
|
if (!isVisible)
|
|
3823
3976
|
continue;
|
|
3824
3977
|
const widgetId = widget['widget-id'];
|
|
3978
|
+
if (isTableLikeWidget(widget)) {
|
|
3979
|
+
const tableValid = validateTableLikeWidget(widget, currentSchemaData, dispatch, skipRequired);
|
|
3980
|
+
if (!tableValid) {
|
|
3981
|
+
isValid = false;
|
|
3982
|
+
}
|
|
3983
|
+
continue;
|
|
3984
|
+
}
|
|
3825
3985
|
const value = getWidgetValue(currentSchemaData, widget['widget-data-path'], widgetId);
|
|
3826
3986
|
const errors = validateWidget(value, widget['widget-data-validation'], widget['widget-required'], skipRequired);
|
|
3827
3987
|
if (errors.length > 0) {
|
|
@@ -3856,52 +4016,6 @@ const sectionValidate = (section, currentSchemaData, dispatch, skipRequired = fa
|
|
|
3856
4016
|
return isValid;
|
|
3857
4017
|
};
|
|
3858
4018
|
|
|
3859
|
-
/** Table-style widgets that bind to an array path in the store / schema. */
|
|
3860
|
-
function isTableLikeWidget(widget) {
|
|
3861
|
-
const w = widget.widget;
|
|
3862
|
-
/** widget-type union in types omits legacy values like simple-table still used at runtime */
|
|
3863
|
-
const t = widget['widget-type'];
|
|
3864
|
-
return (w === 'table' ||
|
|
3865
|
-
w === 'dialog-table' ||
|
|
3866
|
-
w === 'simple-table' ||
|
|
3867
|
-
t === 'table' ||
|
|
3868
|
-
t === 'simple-table');
|
|
3869
|
-
}
|
|
3870
|
-
/**
|
|
3871
|
-
* Resolve `records` for section save payloads.
|
|
3872
|
-
* - Back-compat: path ending in `.records` (e.g. `regId.records`)
|
|
3873
|
-
* - Else: first array snapshot at a string `widget-data-path` on a table-like widget
|
|
3874
|
-
* (e.g. `household.members` for dialog-table)
|
|
3875
|
-
*/
|
|
3876
|
-
function extractTableRecordsFromSnapshot(snapshot, sectionWidgets) {
|
|
3877
|
-
const convention = Object.entries(snapshot).find(([key, value]) => key.endsWith('.records') && Array.isArray(value));
|
|
3878
|
-
if (convention) {
|
|
3879
|
-
return convention[1];
|
|
3880
|
-
}
|
|
3881
|
-
const tablePaths = [];
|
|
3882
|
-
sectionWidgets.forEach((widget) => {
|
|
3883
|
-
if (!isTableLikeWidget(widget))
|
|
3884
|
-
return;
|
|
3885
|
-
const p = widget['widget-data-path'];
|
|
3886
|
-
if (typeof p === 'string' && p.length > 0) {
|
|
3887
|
-
tablePaths.push(p);
|
|
3888
|
-
}
|
|
3889
|
-
else if (p && typeof p === 'object') {
|
|
3890
|
-
Object.values(p).forEach((sub) => {
|
|
3891
|
-
if (typeof sub === 'string' && sub.length > 0)
|
|
3892
|
-
tablePaths.push(sub);
|
|
3893
|
-
});
|
|
3894
|
-
}
|
|
3895
|
-
});
|
|
3896
|
-
for (const path of tablePaths) {
|
|
3897
|
-
const val = snapshot[path];
|
|
3898
|
-
if (Array.isArray(val)) {
|
|
3899
|
-
return val;
|
|
3900
|
-
}
|
|
3901
|
-
}
|
|
3902
|
-
return [];
|
|
3903
|
-
}
|
|
3904
|
-
|
|
3905
4019
|
/** Root class on readonly label/value rows; SectionRenderer scopes overflow/ellipsis rules here. */
|
|
3906
4020
|
const READONLY_VALUE_ROW_ROOT_CLASSES = [
|
|
3907
4021
|
'TextDisplayWidget',
|
|
@@ -7348,7 +7462,18 @@ const TextInputWidget = ({ config }) => {
|
|
|
7348
7462
|
};
|
|
7349
7463
|
|
|
7350
7464
|
const NumberInputWidget = ({ config }) => {
|
|
7351
|
-
const
|
|
7465
|
+
const resolvedConfig = React.useMemo(() => {
|
|
7466
|
+
const rawDefault = config['widget-data-default'];
|
|
7467
|
+
if (rawDefault === undefined) {
|
|
7468
|
+
return config;
|
|
7469
|
+
}
|
|
7470
|
+
const normalizedDefault = normalizeNumericDefault(rawDefault, config['widget-data-format']);
|
|
7471
|
+
if (normalizedDefault === undefined || normalizedDefault === rawDefault) {
|
|
7472
|
+
return config;
|
|
7473
|
+
}
|
|
7474
|
+
return { ...config, 'widget-data-default': normalizedDefault };
|
|
7475
|
+
}, [config]);
|
|
7476
|
+
const { value, formattedValue, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config: resolvedConfig });
|
|
7352
7477
|
const { translate, translateConfig } = useWidgetTranslation();
|
|
7353
7478
|
const formatConfig = widgetConfig['widget-data-format'];
|
|
7354
7479
|
const validationConfig = widgetConfig['widget-data-validation'];
|
|
@@ -7511,6 +7636,8 @@ const BooleanWidget = ({ config }) => {
|
|
|
7511
7636
|
return labels[representation];
|
|
7512
7637
|
}, [representation, formatConfig, translateConfig]);
|
|
7513
7638
|
const { trueLabel, falseLabel } = getLabels();
|
|
7639
|
+
const unsetLabel = React.useMemo(() => translateConfig(formatConfig?.booleanUnsetLabel || 'Not set'), [formatConfig?.booleanUnsetLabel, translateConfig]);
|
|
7640
|
+
const radioGroupName = `${widgetConfig['widget-id'] ?? 'boolean'}__${React.useId().replace(/:/g, '')}`;
|
|
7514
7641
|
// Determine current value (handle null/undefined)
|
|
7515
7642
|
const currentValue = React.useMemo(() => {
|
|
7516
7643
|
if (value === null || value === undefined) {
|
|
@@ -7542,7 +7669,7 @@ const BooleanWidget = ({ config }) => {
|
|
|
7542
7669
|
const label = translateConfig(widgetConfig['widget-label']);
|
|
7543
7670
|
let displayValue = '';
|
|
7544
7671
|
if (currentValue === null) {
|
|
7545
|
-
displayValue = '
|
|
7672
|
+
displayValue = '';
|
|
7546
7673
|
}
|
|
7547
7674
|
else if (currentValue === true) {
|
|
7548
7675
|
displayValue = trueLabel;
|
|
@@ -7554,18 +7681,20 @@ const BooleanWidget = ({ config }) => {
|
|
|
7554
7681
|
}
|
|
7555
7682
|
// Render based on control type
|
|
7556
7683
|
if (controlType === 'checkbox') {
|
|
7557
|
-
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-
|
|
7684
|
+
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-baseline", children: [jsxRuntimeExports.jsxs("label", { className: "text-base font-medium leading-normal text-gray-700 md:min-w-[120px] sm:pr-4 mb-1 sm:mb-0 sm:pt-0.5", style: { fontFamily: 'Roboto, sans-serif' }, title: translateConfig(widgetConfig['widget-label']), children: [translateConfig(widgetConfig['widget-label']), widgetConfig['widget-required'] && (jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", children: "*" }))] }), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntimeExports.jsxs("label", { className: "inline-flex items-baseline cursor-pointer gap-2", children: [jsxRuntimeExports.jsx("input", { type: "checkbox", checked: currentValue === true, onChange: handleCheckboxChange, onBlur: onBlur, disabled: !isEnabled || widgetConfig['widget-readonly'], className: "relative top-[0.2em] h-4 w-4 shrink-0 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" }), (currentValue === true || currentValue === false) && (jsxRuntimeExports.jsx("span", { className: "text-base text-gray-700 leading-normal", children: currentValue === true ? trueLabel : falseLabel }))] }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] }))] })] }) }));
|
|
7558
7685
|
}
|
|
7559
7686
|
if (controlType === 'radio') {
|
|
7560
7687
|
const containerClass = orientation === 'horizontal'
|
|
7561
|
-
? 'flex flex-row
|
|
7562
|
-
: 'flex flex-col
|
|
7563
|
-
|
|
7688
|
+
? 'flex flex-row flex-wrap items-baseline gap-x-4 gap-y-2'
|
|
7689
|
+
: 'flex flex-col items-start gap-2';
|
|
7690
|
+
const radioDisabled = !isEnabled || widgetConfig['widget-readonly'];
|
|
7691
|
+
const optionDisabledClass = radioDisabled ? 'opacity-50 cursor-not-allowed' : '';
|
|
7692
|
+
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-baseline", children: [jsxRuntimeExports.jsxs("label", { className: "text-base font-medium leading-normal text-gray-700 md:min-w-[120px] sm:pr-4 mb-1 sm:mb-0 sm:pt-0.5", style: { fontFamily: 'Roboto, sans-serif' }, title: translateConfig(widgetConfig['widget-label']), children: [translateConfig(widgetConfig['widget-label']), widgetConfig['widget-required'] && (jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", children: "*" }))] }), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntimeExports.jsxs("div", { className: containerClass, onBlur: onBlur, children: [allowUnset && (jsxRuntimeExports.jsxs("label", { className: `inline-flex items-baseline gap-2 cursor-pointer ${optionDisabledClass}`, children: [jsxRuntimeExports.jsx("input", { type: "radio", name: radioGroupName, checked: currentValue === null, onChange: () => handleRadioChange(null), disabled: radioDisabled, className: "relative top-[0.2em] h-4 w-4 shrink-0 text-blue-600 focus:ring-blue-500 border-gray-300" }), jsxRuntimeExports.jsx("span", { className: "text-base text-gray-700 leading-normal", children: unsetLabel })] })), jsxRuntimeExports.jsxs("label", { className: `inline-flex items-baseline gap-2 cursor-pointer ${optionDisabledClass}`, children: [jsxRuntimeExports.jsx("input", { type: "radio", name: radioGroupName, checked: currentValue === true, onChange: () => handleRadioChange(true), disabled: radioDisabled, className: "relative top-[0.2em] h-4 w-4 shrink-0 text-blue-600 focus:ring-blue-500 border-gray-300" }), jsxRuntimeExports.jsx("span", { className: "text-base text-gray-700 leading-normal", children: trueLabel })] }), jsxRuntimeExports.jsxs("label", { className: `inline-flex items-baseline gap-2 cursor-pointer ${optionDisabledClass}`, children: [jsxRuntimeExports.jsx("input", { type: "radio", name: radioGroupName, checked: currentValue === false, onChange: () => handleRadioChange(false), disabled: radioDisabled, className: "relative top-[0.2em] h-4 w-4 shrink-0 text-blue-600 focus:ring-blue-500 border-gray-300" }), jsxRuntimeExports.jsx("span", { className: "text-base text-gray-700 leading-normal", children: falseLabel })] })] }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] }))] })] }) }));
|
|
7564
7693
|
}
|
|
7565
7694
|
// Toggle/switch control type
|
|
7566
|
-
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-
|
|
7695
|
+
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-baseline", children: [jsxRuntimeExports.jsxs("label", { className: "text-base font-medium leading-normal text-gray-700 sm:min-w-[150px] sm:pr-4 mb-1 sm:mb-0 sm:pt-0.5", style: { fontFamily: 'Roboto, sans-serif' }, title: translateConfig(widgetConfig['widget-label']), children: [translateConfig(widgetConfig['widget-label']), widgetConfig['widget-required'] && (jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", children: "*" }))] }), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-3", onBlur: onBlur, children: [allowUnset && (jsxRuntimeExports.jsx("button", { type: "button", onClick: () => handleChange(null), disabled: !isEnabled || widgetConfig['widget-readonly'], className: `px-3 py-1 text-sm border ${currentValue === null
|
|
7567
7696
|
? 'bg-blue-600 text-white border-blue-600'
|
|
7568
|
-
: 'bg-white text-gray-700 border-gray-300'} ${!isEnabled || widgetConfig['widget-readonly'] ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-50'}`, style: { borderRadius: '15px' }, children:
|
|
7697
|
+
: 'bg-white text-gray-700 border-gray-300'} ${!isEnabled || widgetConfig['widget-readonly'] ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-50'}`, style: { borderRadius: '15px' }, children: unsetLabel })), jsxRuntimeExports.jsx("button", { type: "button", onClick: () => handleChange(true), disabled: !isEnabled || widgetConfig['widget-readonly'], className: `px-3 py-1 text-sm border ${currentValue === true
|
|
7569
7698
|
? 'bg-blue-600 text-white border-blue-600'
|
|
7570
7699
|
: 'bg-white text-gray-700 border-gray-300'} ${!isEnabled || widgetConfig['widget-readonly'] ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-50'}`, style: { borderRadius: '15px' }, children: trueLabel }), jsxRuntimeExports.jsx("button", { type: "button", onClick: () => handleChange(false), disabled: !isEnabled || widgetConfig['widget-readonly'], className: `px-3 py-1 text-sm border ${currentValue === false
|
|
7571
7700
|
? 'bg-blue-600 text-white border-blue-600'
|
|
@@ -7573,42 +7702,76 @@ const BooleanWidget = ({ config }) => {
|
|
|
7573
7702
|
};
|
|
7574
7703
|
|
|
7575
7704
|
const DateInputWidget = ({ config }) => {
|
|
7576
|
-
const { value,
|
|
7577
|
-
const
|
|
7705
|
+
const { value, error, touched, isEnabled, onChange, onBlur, setError, config: widgetConfig, } = useBaseWidget({ config });
|
|
7706
|
+
const formValues = reactRedux.useSelector((state) => state.widget.values);
|
|
7707
|
+
const { translateConfig } = useWidgetTranslation();
|
|
7578
7708
|
const formatConfig = widgetConfig['widget-data-format'];
|
|
7579
7709
|
const optionsConfig = widgetConfig['widget-data-options'];
|
|
7580
7710
|
const dateFormat = formatConfig?.dateFormat || 'YYYY-MM-DD';
|
|
7581
|
-
const inputMethod = formatConfig?.inputMethod || 'picker';
|
|
7711
|
+
const inputMethod = formatConfig?.inputMethod || 'picker';
|
|
7582
7712
|
const dateConstraint = formatConfig?.dateConstraint || 'any';
|
|
7583
7713
|
const minDate = optionsConfig?.minDate;
|
|
7584
7714
|
const maxDate = optionsConfig?.maxDate;
|
|
7715
|
+
const minDateField = optionsConfig?.minDateField;
|
|
7716
|
+
const maxDateField = optionsConfig?.maxDateField;
|
|
7717
|
+
const minDateMessage = optionsConfig?.minDateMessage
|
|
7718
|
+
? translateConfig(optionsConfig.minDateMessage)
|
|
7719
|
+
: undefined;
|
|
7720
|
+
const maxDateMessage = optionsConfig?.maxDateMessage
|
|
7721
|
+
? translateConfig(optionsConfig.maxDateMessage)
|
|
7722
|
+
: undefined;
|
|
7585
7723
|
const defaultToToday = widgetConfig['widget-data-default'] === 'today';
|
|
7586
|
-
// Track manual input value (for manual/hybrid modes)
|
|
7587
7724
|
const [manualInputValue, setManualInputValue] = React.useState('');
|
|
7588
7725
|
const [isFocused, setIsFocused] = React.useState(false);
|
|
7589
|
-
|
|
7726
|
+
const fieldMinDate = React.useMemo(() => {
|
|
7727
|
+
if (!minDateField) {
|
|
7728
|
+
return undefined;
|
|
7729
|
+
}
|
|
7730
|
+
return resolveDateBoundFromFieldValue(getValueByPath(formValues, minDateField));
|
|
7731
|
+
}, [formValues, minDateField]);
|
|
7732
|
+
const fieldMaxDate = React.useMemo(() => {
|
|
7733
|
+
if (!maxDateField) {
|
|
7734
|
+
return undefined;
|
|
7735
|
+
}
|
|
7736
|
+
return resolveDateBoundFromFieldValue(getValueByPath(formValues, maxDateField));
|
|
7737
|
+
}, [formValues, maxDateField]);
|
|
7738
|
+
const effectiveMinDate = React.useMemo(() => {
|
|
7739
|
+
const staticMin = getMinDate(dateConstraint, minDate);
|
|
7740
|
+
return mergeMinDateBounds(staticMin, fieldMinDate);
|
|
7741
|
+
}, [dateConstraint, minDate, fieldMinDate]);
|
|
7742
|
+
const effectiveMaxDate = React.useMemo(() => {
|
|
7743
|
+
const staticMax = getMaxDate(dateConstraint, maxDate);
|
|
7744
|
+
return mergeMaxDateBounds(staticMax, fieldMaxDate);
|
|
7745
|
+
}, [dateConstraint, maxDate, fieldMaxDate]);
|
|
7746
|
+
const constraintMessages = React.useMemo(() => ({ minDateMessage, maxDateMessage }), [minDateMessage, maxDateMessage]);
|
|
7747
|
+
const runDateConstraintValidation = React.useCallback((dateValue) => {
|
|
7748
|
+
if (!dateValue) {
|
|
7749
|
+
return null;
|
|
7750
|
+
}
|
|
7751
|
+
return validateDateConstraints(dateValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages);
|
|
7752
|
+
}, [effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages]);
|
|
7590
7753
|
React.useEffect(() => {
|
|
7591
7754
|
if (defaultToToday && (value === null || value === undefined || value === '')) {
|
|
7592
7755
|
const todayISO = formatDateToISO(new Date());
|
|
7593
7756
|
onChange(todayISO);
|
|
7594
7757
|
}
|
|
7595
7758
|
}, [defaultToToday, value, onChange]);
|
|
7596
|
-
//
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7759
|
+
// Re-validate when a relative bound field changes (e.g. start date set after end date)
|
|
7760
|
+
React.useEffect(() => {
|
|
7761
|
+
if (!value) {
|
|
7762
|
+
return;
|
|
7763
|
+
}
|
|
7764
|
+
const constraintError = runDateConstraintValidation(value);
|
|
7765
|
+
if (constraintError) {
|
|
7766
|
+
setError([constraintError]);
|
|
7767
|
+
}
|
|
7768
|
+
}, [fieldMinDate, fieldMaxDate, value, runDateConstraintValidation, setError]);
|
|
7604
7769
|
const getDisplayValue = React.useCallback(() => {
|
|
7605
|
-
// For picker mode, always use YYYY-MM-DD
|
|
7606
7770
|
if (inputMethod === 'picker') {
|
|
7607
7771
|
if (!value)
|
|
7608
7772
|
return '';
|
|
7609
7773
|
return formatDateToISO(value);
|
|
7610
7774
|
}
|
|
7611
|
-
// For manual/hybrid modes, use custom format
|
|
7612
7775
|
if (isFocused && manualInputValue) {
|
|
7613
7776
|
return manualInputValue;
|
|
7614
7777
|
}
|
|
@@ -7619,7 +7782,6 @@ const DateInputWidget = ({ config }) => {
|
|
|
7619
7782
|
}
|
|
7620
7783
|
return formatDateToString(value, dateFormat);
|
|
7621
7784
|
}, [value, inputMethod, dateFormat, isFocused, manualInputValue]);
|
|
7622
|
-
// Initialize manual input value
|
|
7623
7785
|
React.useEffect(() => {
|
|
7624
7786
|
if (!isFocused && value) {
|
|
7625
7787
|
if (dateFormat === 'YYYY-MM-DD') {
|
|
@@ -7630,66 +7792,81 @@ const DateInputWidget = ({ config }) => {
|
|
|
7630
7792
|
}
|
|
7631
7793
|
}
|
|
7632
7794
|
}, [value, dateFormat, isFocused]);
|
|
7633
|
-
|
|
7795
|
+
const applyConstraintError = React.useCallback((dateValue) => {
|
|
7796
|
+
const constraintError = runDateConstraintValidation(dateValue);
|
|
7797
|
+
setError(constraintError ? [constraintError] : []);
|
|
7798
|
+
}, [runDateConstraintValidation, setError]);
|
|
7634
7799
|
const handleChange = React.useCallback((e) => {
|
|
7635
7800
|
const inputValue = e.target.value;
|
|
7636
7801
|
if (inputMethod === 'picker') {
|
|
7637
|
-
// Picker mode: input is always YYYY-MM-DD
|
|
7638
7802
|
if (inputValue) {
|
|
7639
7803
|
const date = parseDate(inputValue);
|
|
7640
7804
|
if (date) {
|
|
7641
|
-
|
|
7805
|
+
const iso = formatDateToISO(date);
|
|
7806
|
+
onChange(iso);
|
|
7807
|
+
applyConstraintError(iso);
|
|
7642
7808
|
}
|
|
7643
7809
|
else {
|
|
7644
7810
|
onChange('');
|
|
7811
|
+
setError([]);
|
|
7645
7812
|
}
|
|
7646
7813
|
}
|
|
7647
7814
|
else {
|
|
7648
7815
|
onChange('');
|
|
7816
|
+
setError([]);
|
|
7649
7817
|
}
|
|
7650
7818
|
}
|
|
7651
7819
|
else {
|
|
7652
|
-
// Manual/hybrid mode: parse custom format
|
|
7653
7820
|
setManualInputValue(inputValue);
|
|
7654
7821
|
if (inputValue) {
|
|
7655
7822
|
const date = parseDateFromFormat(inputValue, dateFormat);
|
|
7656
7823
|
if (date) {
|
|
7657
|
-
|
|
7658
|
-
|
|
7659
|
-
|
|
7660
|
-
onChange(formatDateToISO(date));
|
|
7661
|
-
}
|
|
7662
|
-
else {
|
|
7663
|
-
// Still update the value but validation will catch it
|
|
7664
|
-
onChange(formatDateToISO(date));
|
|
7665
|
-
}
|
|
7824
|
+
const iso = formatDateToISO(date);
|
|
7825
|
+
onChange(iso);
|
|
7826
|
+
applyConstraintError(iso);
|
|
7666
7827
|
}
|
|
7667
7828
|
}
|
|
7668
7829
|
else {
|
|
7669
7830
|
onChange('');
|
|
7831
|
+
setError([]);
|
|
7670
7832
|
}
|
|
7671
7833
|
}
|
|
7672
|
-
}, [inputMethod, dateFormat, onChange,
|
|
7673
|
-
// Handle blur - validate and format
|
|
7834
|
+
}, [inputMethod, dateFormat, onChange, applyConstraintError, setError]);
|
|
7674
7835
|
const handleBlur = React.useCallback(() => {
|
|
7675
7836
|
setIsFocused(false);
|
|
7676
7837
|
if (inputMethod !== 'picker' && manualInputValue) {
|
|
7677
7838
|
const date = parseDateFromFormat(manualInputValue, dateFormat);
|
|
7678
7839
|
if (date) {
|
|
7679
|
-
// Format the value according to the format
|
|
7680
7840
|
const formatted = formatDateToString(date, dateFormat);
|
|
7681
7841
|
setManualInputValue(formatted);
|
|
7682
|
-
|
|
7842
|
+
const iso = formatDateToISO(date);
|
|
7843
|
+
onChange(iso);
|
|
7844
|
+
applyConstraintError(iso);
|
|
7683
7845
|
}
|
|
7684
7846
|
else {
|
|
7685
|
-
// Invalid date, clear it
|
|
7686
7847
|
setManualInputValue('');
|
|
7687
7848
|
onChange('');
|
|
7849
|
+
setError([]);
|
|
7688
7850
|
}
|
|
7689
7851
|
}
|
|
7690
7852
|
onBlur();
|
|
7691
|
-
|
|
7692
|
-
|
|
7853
|
+
if (value) {
|
|
7854
|
+
const constraintError = runDateConstraintValidation(value);
|
|
7855
|
+
if (constraintError) {
|
|
7856
|
+
setError([constraintError]);
|
|
7857
|
+
}
|
|
7858
|
+
}
|
|
7859
|
+
}, [
|
|
7860
|
+
inputMethod,
|
|
7861
|
+
manualInputValue,
|
|
7862
|
+
dateFormat,
|
|
7863
|
+
onChange,
|
|
7864
|
+
onBlur,
|
|
7865
|
+
applyConstraintError,
|
|
7866
|
+
value,
|
|
7867
|
+
runDateConstraintValidation,
|
|
7868
|
+
setError,
|
|
7869
|
+
]);
|
|
7693
7870
|
const handleFocus = React.useCallback(() => {
|
|
7694
7871
|
setIsFocused(true);
|
|
7695
7872
|
if (value) {
|
|
@@ -7701,15 +7878,15 @@ const DateInputWidget = ({ config }) => {
|
|
|
7701
7878
|
}
|
|
7702
7879
|
}
|
|
7703
7880
|
}, [value, dateFormat]);
|
|
7704
|
-
// Determine placeholder
|
|
7705
7881
|
const placeholder = React.useMemo(() => {
|
|
7706
|
-
const
|
|
7882
|
+
const display = getDisplayValue();
|
|
7883
|
+
const hasValue = display && display.trim().length > 0;
|
|
7707
7884
|
const placeholderText = translateConfig(widgetConfig['widget-data-placeholder']);
|
|
7708
|
-
return hasValue ? undefined :
|
|
7885
|
+
return hasValue ? undefined : placeholderText || dateFormat;
|
|
7709
7886
|
}, [getDisplayValue, widgetConfig, translateConfig, dateFormat]);
|
|
7710
|
-
// Determine input type
|
|
7711
7887
|
const inputType = inputMethod === 'picker' ? 'date' : 'text';
|
|
7712
|
-
|
|
7888
|
+
const showRequiredError = widgetConfig['widget-required'] && (!value || value === '');
|
|
7889
|
+
const showValidationError = touched && error.length > 0;
|
|
7713
7890
|
if (widgetConfig['widget-readonly']) {
|
|
7714
7891
|
const label = translateConfig(widgetConfig['widget-label']);
|
|
7715
7892
|
let displayValue = '';
|
|
@@ -7726,9 +7903,9 @@ const DateInputWidget = ({ config }) => {
|
|
|
7726
7903
|
}
|
|
7727
7904
|
return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px] DateDisplayWidget flex flex-col sm:flex-row sm:items-start", children: [label && (jsxRuntimeExports.jsxs("div", { className: "text-base text-gray-600 font-medium md:min-w-[120px] sm:pr-4 mb-1 sm:mb-0", style: { fontFamily: 'Roboto, sans-serif' }, title: label, children: [label, ":"] })), jsxRuntimeExports.jsx("div", { className: "flex-1", children: jsxRuntimeExports.jsx("div", { className: "text-base text-gray-900 font-medium", title: String(displayValue ?? ''), children: displayValue }) })] }));
|
|
7728
7905
|
}
|
|
7729
|
-
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start", children: [jsxRuntimeExports.jsxs("label", { className: "text-base font-medium text-gray-700 md:min-w-[120px] sm:pr-4 sm:pt-1 mb-1 sm:mb-0", style: { fontFamily: 'Roboto, sans-serif' }, title: translateConfig(widgetConfig['widget-label']), children: [translateConfig(widgetConfig['widget-label']), widgetConfig['widget-required'] &&
|
|
7906
|
+
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-start", children: [jsxRuntimeExports.jsxs("label", { className: "text-base font-medium text-gray-700 md:min-w-[120px] sm:pr-4 sm:pt-1 mb-1 sm:mb-0", style: { fontFamily: 'Roboto, sans-serif' }, title: translateConfig(widgetConfig['widget-label']), children: [translateConfig(widgetConfig['widget-label']), widgetConfig['widget-required'] && jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", children: "*" })] }), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntimeExports.jsx("input", { type: inputType, value: getDisplayValue(), onChange: handleChange, onBlur: handleBlur, onFocus: handleFocus, disabled: !isEnabled || widgetConfig['widget-readonly'], placeholder: placeholder, min: inputMethod === 'picker' ? effectiveMinDate : undefined, max: inputMethod === 'picker' ? effectiveMaxDate : undefined, className: `w-full sm:w-[180px] max-w-full h-[30px] px-3 border shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${showValidationError || showRequiredError
|
|
7730
7907
|
? 'border-red-500 focus:ring-red-500 focus:border-red-500'
|
|
7731
|
-
: 'border-gray-300'} ${!isEnabled || widgetConfig['widget-readonly'] ? 'bg-gray-100 cursor-not-allowed' : 'bg-white'}`, style: { borderRadius: '10px' }, title: translateConfig(widgetConfig['widget-data-tooltip']) }),
|
|
7908
|
+
: 'border-gray-300'} ${!isEnabled || widgetConfig['widget-readonly'] ? 'bg-gray-100 cursor-not-allowed' : 'bg-white'}`, style: { borderRadius: '10px' }, title: translateConfig(widgetConfig['widget-data-tooltip']) }), showValidationError && jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] })] })] }) }));
|
|
7732
7909
|
};
|
|
7733
7910
|
|
|
7734
7911
|
/**
|
|
@@ -8276,7 +8453,7 @@ const CheckboxWidget = ({ config }) => {
|
|
|
8276
8453
|
const displayValue = isChecked ? 'Yes' : 'No';
|
|
8277
8454
|
return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px] CheckboxDisplayWidget flex flex-col sm:flex-row sm:items-start", children: [label && (jsxRuntimeExports.jsxs("div", { className: "text-base text-gray-600 font-medium md:min-w-[120px] sm:pr-4 mb-1 sm:mb-0", style: { fontFamily: 'Roboto, sans-serif' }, title: label, children: [label, ":"] })), jsxRuntimeExports.jsx("div", { className: "flex-1", children: jsxRuntimeExports.jsx("div", { className: "text-base text-gray-900 font-medium", title: String(displayValue ?? ''), children: displayValue }) })] }));
|
|
8278
8455
|
}
|
|
8279
|
-
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-
|
|
8456
|
+
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-baseline", children: [jsxRuntimeExports.jsxs("label", { className: "text-base font-medium leading-normal text-gray-700 md:min-w-[120px] sm:pr-4 mb-1 sm:mb-0 sm:pt-0.5", style: { fontFamily: 'Roboto, sans-serif' }, title: translateConfig(widgetConfig['widget-label']), children: [translateConfig(widgetConfig['widget-label']), widgetConfig['widget-required'] && (jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", children: "*" }))] }), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntimeExports.jsxs("label", { className: "inline-flex cursor-pointer items-baseline gap-2", children: [jsxRuntimeExports.jsx("input", { type: "checkbox", checked: isChecked, onChange: (e) => onChange(e.target.checked), onBlur: onBlur, disabled: !isEnabled || widgetConfig['widget-readonly'], className: "relative top-[0.2em] h-4 w-4 shrink-0 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" }), jsxRuntimeExports.jsx("span", { className: "text-base leading-normal text-gray-700", children: isChecked ? 'Yes' : 'No' })] }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] }))] })] }) }));
|
|
8280
8457
|
}
|
|
8281
8458
|
// Multiple checkboxes (with data source) - for array values
|
|
8282
8459
|
// Process and sort options if needed
|
|
@@ -8319,7 +8496,7 @@ const CheckboxWidget = ({ config }) => {
|
|
|
8319
8496
|
switch (layout) {
|
|
8320
8497
|
case 'horizontal':
|
|
8321
8498
|
return {
|
|
8322
|
-
className: 'flex flex-row flex-wrap gap-4',
|
|
8499
|
+
className: 'flex flex-row flex-wrap items-baseline gap-4',
|
|
8323
8500
|
style: undefined,
|
|
8324
8501
|
};
|
|
8325
8502
|
case 'grid':
|
|
@@ -8332,7 +8509,7 @@ const CheckboxWidget = ({ config }) => {
|
|
|
8332
8509
|
case 'vertical':
|
|
8333
8510
|
default:
|
|
8334
8511
|
return {
|
|
8335
|
-
className: 'flex flex-col
|
|
8512
|
+
className: 'flex flex-col gap-2',
|
|
8336
8513
|
style: undefined,
|
|
8337
8514
|
};
|
|
8338
8515
|
}
|
|
@@ -8346,7 +8523,7 @@ const CheckboxWidget = ({ config }) => {
|
|
|
8346
8523
|
: '-';
|
|
8347
8524
|
return (jsxRuntimeExports.jsxs("div", { className: "mb-3 CheckboxDisplayWidget flex flex-col sm:flex-row sm:items-start", children: [label && (jsxRuntimeExports.jsxs("div", { className: "text-sm text-gray-600 font-medium md:min-w-[120px] sm:pr-4 mb-1 sm:mb-0", title: label, children: [label, ":"] })), jsxRuntimeExports.jsx("div", { className: "flex-1", children: jsxRuntimeExports.jsx("div", { className: "text-base text-gray-900 font-medium", title: String(displayValue ?? ''), children: displayValue }) })] }));
|
|
8348
8525
|
}
|
|
8349
|
-
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-
|
|
8526
|
+
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-baseline", children: [jsxRuntimeExports.jsxs("label", { className: "text-base font-medium leading-normal text-gray-700 md:min-w-[120px] sm:pr-4 mb-1 sm:mb-0 sm:pt-0.5", style: { fontFamily: 'Roboto, sans-serif' }, title: translateConfig(widgetConfig['widget-label']), children: [translateConfig(widgetConfig['widget-label']), widgetConfig['widget-required'] && (jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", children: "*" }))] }), jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntimeExports.jsx("div", { className: layoutConfig.className, style: layoutConfig.style, onBlur: onBlur, children: loading ? (jsxRuntimeExports.jsx("p", { className: "text-sm text-gray-500", children: translate('common.loading') })) : (processedOptions.map((option) => (jsxRuntimeExports.jsxs("label", { className: `inline-flex cursor-pointer items-baseline gap-2 ${!isEnabled || widgetConfig['widget-readonly'] ? 'opacity-50 cursor-not-allowed' : ''}`, children: [jsxRuntimeExports.jsx("input", { type: "checkbox", value: option.value, checked: selectedValues.includes(option.value), onChange: (e) => handleCheckboxChange(option.value, e.target.checked), disabled: !isEnabled || widgetConfig['widget-readonly'], className: "relative top-[0.2em] h-4 w-4 shrink-0 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" }), jsxRuntimeExports.jsx("span", { className: "text-base leading-normal text-gray-700", children: translateConfig(option.label) })] }, option.value)))) }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-sm mt-1", children: error[0] }))] })] }) }));
|
|
8350
8527
|
};
|
|
8351
8528
|
|
|
8352
8529
|
const SimpleTableWidget = ({ config }) => {
|
|
@@ -8672,16 +8849,70 @@ const TableCellNumber = ({ config, value, onValueChange }) => {
|
|
|
8672
8849
|
backgroundColor: isReadonly ? 'var(--owt-color-bg-alt, #F6F6F6)' : 'var(--owt-color-bg, #FFFFFF)',
|
|
8673
8850
|
} }));
|
|
8674
8851
|
};
|
|
8675
|
-
const TableCellDate = ({ config, value, onValueChange }) => {
|
|
8852
|
+
const TableCellDate = ({ config, value, rowValues, onValueChange }) => {
|
|
8853
|
+
const { translateConfig } = useWidgetTranslation();
|
|
8676
8854
|
const isReadonly = config['widget-readonly'] || false;
|
|
8677
8855
|
const placeholder = config['widget-data-placeholder'] || '';
|
|
8856
|
+
const optionsConfig = config['widget-data-options'];
|
|
8857
|
+
const formatConfig = config['widget-data-format'];
|
|
8858
|
+
const dateConstraint = formatConfig?.dateConstraint || 'any';
|
|
8859
|
+
const minDate = optionsConfig?.minDate;
|
|
8860
|
+
const maxDate = optionsConfig?.maxDate;
|
|
8861
|
+
const minDateField = optionsConfig?.minDateField;
|
|
8862
|
+
const maxDateField = optionsConfig?.maxDateField;
|
|
8863
|
+
const minDateMessage = optionsConfig?.minDateMessage
|
|
8864
|
+
? translateConfig(optionsConfig.minDateMessage)
|
|
8865
|
+
: undefined;
|
|
8866
|
+
const maxDateMessage = optionsConfig?.maxDateMessage
|
|
8867
|
+
? translateConfig(optionsConfig.maxDateMessage)
|
|
8868
|
+
: undefined;
|
|
8869
|
+
const [constraintError, setConstraintError] = React.useState(null);
|
|
8870
|
+
const resolveSiblingDate = (fieldRef) => {
|
|
8871
|
+
if (!fieldRef || !rowValues) {
|
|
8872
|
+
return undefined;
|
|
8873
|
+
}
|
|
8874
|
+
const raw = getValueByPath(rowValues, fieldRef) ?? rowValues[fieldRef];
|
|
8875
|
+
return resolveDateBoundFromFieldValue(raw);
|
|
8876
|
+
};
|
|
8877
|
+
const fieldMinDate = React.useMemo(() => resolveSiblingDate(minDateField), [minDateField, rowValues]);
|
|
8878
|
+
const fieldMaxDate = React.useMemo(() => resolveSiblingDate(maxDateField), [maxDateField, rowValues]);
|
|
8879
|
+
const effectiveMinDate = React.useMemo(() => {
|
|
8880
|
+
const staticMin = getMinDate(dateConstraint, minDate);
|
|
8881
|
+
return mergeMinDateBounds(staticMin, fieldMinDate);
|
|
8882
|
+
}, [dateConstraint, minDate, fieldMinDate]);
|
|
8883
|
+
const effectiveMaxDate = React.useMemo(() => {
|
|
8884
|
+
const staticMax = getMaxDate(dateConstraint, maxDate);
|
|
8885
|
+
return mergeMaxDateBounds(staticMax, fieldMaxDate);
|
|
8886
|
+
}, [dateConstraint, maxDate, fieldMaxDate]);
|
|
8887
|
+
const constraintMessages = React.useMemo(() => ({ minDateMessage, maxDateMessage }), [minDateMessage, maxDateMessage]);
|
|
8678
8888
|
// input type="date" requires YYYY-MM-DD format
|
|
8679
8889
|
const displayValue = value && typeof value === 'string' ? value.split('T')[0] : '';
|
|
8680
|
-
|
|
8681
|
-
|
|
8682
|
-
|
|
8683
|
-
|
|
8684
|
-
}
|
|
8890
|
+
React.useEffect(() => {
|
|
8891
|
+
if (!displayValue) {
|
|
8892
|
+
setConstraintError(null);
|
|
8893
|
+
return;
|
|
8894
|
+
}
|
|
8895
|
+
const error = validateDateConstraints(displayValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages);
|
|
8896
|
+
setConstraintError(error);
|
|
8897
|
+
}, [displayValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages]);
|
|
8898
|
+
const handleChange = (e) => {
|
|
8899
|
+
const nextValue = e.target.value;
|
|
8900
|
+
onValueChange(nextValue);
|
|
8901
|
+
if (!nextValue) {
|
|
8902
|
+
setConstraintError(null);
|
|
8903
|
+
return;
|
|
8904
|
+
}
|
|
8905
|
+
const error = validateDateConstraints(nextValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages);
|
|
8906
|
+
setConstraintError(error);
|
|
8907
|
+
};
|
|
8908
|
+
const hasError = Boolean(constraintError);
|
|
8909
|
+
return (jsxRuntimeExports.jsxs("div", { className: "w-full", children: [jsxRuntimeExports.jsx("input", { type: "date", value: displayValue, onChange: handleChange, disabled: isReadonly, placeholder: placeholder, min: effectiveMinDate, max: effectiveMaxDate, title: constraintError || translateConfig(config['widget-data-tooltip']), className: `w-full h-[28px] px-2 text-sm border focus:outline-none ${isReadonly ? 'cursor-not-allowed' : ''} ${hasError ? 'border-red-500' : ''} table-cell-input`, style: {
|
|
8910
|
+
borderRadius: '10px',
|
|
8911
|
+
borderColor: hasError
|
|
8912
|
+
? 'var(--owt-color-error, #B91C1C)'
|
|
8913
|
+
: 'var(--owt-widget-input-border, #C4C4C4)',
|
|
8914
|
+
backgroundColor: isReadonly ? 'var(--owt-color-bg-alt, #F6F6F6)' : 'var(--owt-color-bg, #FFFFFF)',
|
|
8915
|
+
} }), hasError && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-xs mt-0.5 leading-tight", children: constraintError }))] }));
|
|
8685
8916
|
};
|
|
8686
8917
|
const TableWidget = ({ config }) => {
|
|
8687
8918
|
const { value, error, touched, isEnabled, onChange, config: widgetConfig, } = useBaseWidget({ config });
|
|
@@ -9040,11 +9271,21 @@ const TableWidget = ({ config }) => {
|
|
|
9040
9271
|
});
|
|
9041
9272
|
}
|
|
9042
9273
|
}, [isAdding, newRowData, columns, widgetConfig, rows.length, dispatch]);
|
|
9274
|
+
const getRowValuesForEdit = React.useCallback((rowIndex) => {
|
|
9275
|
+
if (editingState && editingState.rowIndex === rowIndex) {
|
|
9276
|
+
return editingState.currentValue ?? {};
|
|
9277
|
+
}
|
|
9278
|
+
if (isAdding && rowIndex === rows.length && newRowData) {
|
|
9279
|
+
return newRowData;
|
|
9280
|
+
}
|
|
9281
|
+
return rows[rowIndex] ?? {};
|
|
9282
|
+
}, [editingState, isAdding, rows, newRowData]);
|
|
9043
9283
|
// Lightweight cell renderer for table cells (no labels, compact)
|
|
9044
9284
|
const renderTableCell = React.useCallback((rowIndex, column, cellValue, isReadonly) => {
|
|
9045
9285
|
const columnKey = column['column-key'];
|
|
9046
9286
|
const widgetType = column.widget || 'text';
|
|
9047
9287
|
const cellWidgetId = `${widgetConfig['widget-id']}-row-${rowIndex}-col-${columnKey}`;
|
|
9288
|
+
const rowValues = getRowValuesForEdit(rowIndex);
|
|
9048
9289
|
// Use lightweight cell config (no label, minimal styling)
|
|
9049
9290
|
const cellConfig = {
|
|
9050
9291
|
...column,
|
|
@@ -9067,7 +9308,7 @@ const TableWidget = ({ config }) => {
|
|
|
9067
9308
|
return jsxRuntimeExports.jsx(TableCellNumber, { config: cellConfig, value: cellValue, onValueChange: (newValue) => updateCellValue(columnKey, newValue, rowIndex) });
|
|
9068
9309
|
}
|
|
9069
9310
|
else if (widgetType === 'date') {
|
|
9070
|
-
return jsxRuntimeExports.jsx(TableCellDate, { config: cellConfig, value: cellValue, onValueChange: (newValue) => updateCellValue(columnKey, newValue, rowIndex) });
|
|
9311
|
+
return jsxRuntimeExports.jsx(TableCellDate, { config: cellConfig, value: cellValue, rowValues: rowValues, onValueChange: (newValue) => updateCellValue(columnKey, newValue, rowIndex) });
|
|
9071
9312
|
}
|
|
9072
9313
|
// For other widget types, use WidgetRenderer but with compact styling
|
|
9073
9314
|
return (jsxRuntimeExports.jsx("div", { className: "table-cell-widget", style: { margin: 0, padding: 0 }, children: jsxRuntimeExports.jsx(WidgetRenderer, { config: cellConfig, schemaData: {
|
|
@@ -9075,7 +9316,7 @@ const TableWidget = ({ config }) => {
|
|
|
9075
9316
|
}, onValueChange: (widgetId, newValue) => {
|
|
9076
9317
|
updateCellValue(columnKey, newValue, rowIndex);
|
|
9077
9318
|
} }) }));
|
|
9078
|
-
}, [widgetConfig, updateCellValue]);
|
|
9319
|
+
}, [widgetConfig, updateCellValue, getRowValuesForEdit]);
|
|
9079
9320
|
// Render cell content (widget in edit mode, formatted value in view mode)
|
|
9080
9321
|
const renderCell = React.useCallback((rowIndex, column, row) => {
|
|
9081
9322
|
const columnKey = column['column-key'];
|
|
@@ -9385,6 +9626,27 @@ const DialogTableWidget = ({ config }) => {
|
|
|
9385
9626
|
}, [formData, columns, storeValues, dialogFieldWidgetId]);
|
|
9386
9627
|
const saveDialog = React.useCallback(() => {
|
|
9387
9628
|
const payload = collectMergedRowPayload();
|
|
9629
|
+
let hasErrors = false;
|
|
9630
|
+
columns.forEach((col) => {
|
|
9631
|
+
const key = col['column-key'];
|
|
9632
|
+
const cellWidgetId = dialogFieldWidgetId(key);
|
|
9633
|
+
const isColReadonly = isReadonly || col['widget-readonly'] === true;
|
|
9634
|
+
if (isColReadonly)
|
|
9635
|
+
return;
|
|
9636
|
+
const cellValue = payload[key];
|
|
9637
|
+
const validationErrors = validateWidget(cellValue, col['widget-data-validation'], col['widget-required']);
|
|
9638
|
+
if (validationErrors && validationErrors.length > 0) {
|
|
9639
|
+
hasErrors = true;
|
|
9640
|
+
dispatch(setError({ widgetId: cellWidgetId, errors: validationErrors }));
|
|
9641
|
+
dispatch(setTouched({ widgetId: cellWidgetId, touched: true }));
|
|
9642
|
+
}
|
|
9643
|
+
else {
|
|
9644
|
+
dispatch(setError({ widgetId: cellWidgetId, errors: [] }));
|
|
9645
|
+
}
|
|
9646
|
+
});
|
|
9647
|
+
if (hasErrors) {
|
|
9648
|
+
return;
|
|
9649
|
+
}
|
|
9388
9650
|
if (dialogMode === 'add') {
|
|
9389
9651
|
const savedRow = { ...payload, edit_action: 'ADD' };
|
|
9390
9652
|
onChange([...rows, savedRow]);
|
|
@@ -9400,7 +9662,7 @@ const DialogTableWidget = ({ config }) => {
|
|
|
9400
9662
|
onChange(newRows);
|
|
9401
9663
|
closeDialog();
|
|
9402
9664
|
}
|
|
9403
|
-
}, [collectMergedRowPayload, dialogMode, onChange, rows, closeDialog, activeRowIndex]);
|
|
9665
|
+
}, [collectMergedRowPayload, dialogMode, onChange, rows, closeDialog, activeRowIndex, columns, dialogFieldWidgetId, isReadonly, dispatch]);
|
|
9404
9666
|
const deleteRow = React.useCallback((rowIndex) => {
|
|
9405
9667
|
const newRows = rows.filter((_, i) => i !== rowIndex);
|
|
9406
9668
|
onChange(newRows);
|
|
@@ -10226,20 +10488,29 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
10226
10488
|
.${cls} .hdr-field-row {
|
|
10227
10489
|
display: flex;
|
|
10228
10490
|
align-items: flex-start;
|
|
10229
|
-
gap: 0.5rem;
|
|
10230
10491
|
font-size: 1rem;
|
|
10231
10492
|
line-height: 1.6;
|
|
10232
10493
|
}
|
|
10233
10494
|
|
|
10234
10495
|
.${cls} .hdr-field-label {
|
|
10496
|
+
width: 50%;
|
|
10497
|
+
flex: 0 0 50%;
|
|
10235
10498
|
color: rgba(0, 0, 0, 0.5);
|
|
10236
10499
|
font-weight: 400;
|
|
10237
10500
|
white-space: nowrap;
|
|
10501
|
+
overflow: hidden;
|
|
10502
|
+
text-overflow: ellipsis;
|
|
10503
|
+
padding-right: 4px;
|
|
10238
10504
|
}
|
|
10239
10505
|
|
|
10240
10506
|
.${cls} .hdr-field-value {
|
|
10507
|
+
width: 50%;
|
|
10508
|
+
flex: 0 0 50%;
|
|
10241
10509
|
color: var(--owt-color-text, #111827);
|
|
10242
10510
|
font-weight: 500;
|
|
10511
|
+
white-space: nowrap;
|
|
10512
|
+
overflow: hidden;
|
|
10513
|
+
text-overflow: ellipsis;
|
|
10243
10514
|
}
|
|
10244
10515
|
|
|
10245
10516
|
.${cls} .hdr-status-badge {
|
|
@@ -10249,24 +10520,38 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
10249
10520
|
font-size: 0.75rem;
|
|
10250
10521
|
font-weight: 600;
|
|
10251
10522
|
color: #fff;
|
|
10523
|
+
max-width: 100%;
|
|
10524
|
+
overflow: hidden;
|
|
10525
|
+
text-overflow: ellipsis;
|
|
10526
|
+
white-space: nowrap;
|
|
10252
10527
|
}
|
|
10253
10528
|
|
|
10254
10529
|
.${cls} .hdr-meta-row {
|
|
10255
10530
|
display: flex;
|
|
10256
10531
|
align-items: baseline;
|
|
10257
|
-
gap: 0.35rem;
|
|
10258
10532
|
font-size: 1rem;
|
|
10259
10533
|
line-height: 1.6;
|
|
10260
10534
|
}
|
|
10261
10535
|
|
|
10262
10536
|
.${cls} .hdr-meta-label {
|
|
10537
|
+
width: 50%;
|
|
10538
|
+
flex: 0 0 50%;
|
|
10263
10539
|
color: rgba(0, 0, 0, 0.5);
|
|
10264
10540
|
font-weight: 400;
|
|
10541
|
+
white-space: nowrap;
|
|
10542
|
+
overflow: hidden;
|
|
10543
|
+
text-overflow: ellipsis;
|
|
10544
|
+
padding-right: 4px;
|
|
10265
10545
|
}
|
|
10266
10546
|
|
|
10267
10547
|
.${cls} .hdr-meta-value {
|
|
10548
|
+
width: 50%;
|
|
10549
|
+
flex: 0 0 50%;
|
|
10268
10550
|
color: var(--owt-color-text, #111827);
|
|
10269
10551
|
font-weight: 500;
|
|
10552
|
+
white-space: nowrap;
|
|
10553
|
+
overflow: hidden;
|
|
10554
|
+
text-overflow: ellipsis;
|
|
10270
10555
|
}
|
|
10271
10556
|
|
|
10272
10557
|
.${cls} .hdr-select {
|
|
@@ -10330,7 +10615,7 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
10330
10615
|
.parentElement?.querySelector('.hdr-avatar-placeholder');
|
|
10331
10616
|
if (placeholder)
|
|
10332
10617
|
placeholder.style.display = 'flex';
|
|
10333
|
-
} })) : null, jsxRuntimeExports.jsx("div", { className: "hdr-avatar-placeholder", style: { display: displayImageUrl ? 'none' : 'flex' }, children: jsxRuntimeExports.jsx("img", { src: img$f, alt: "Profile Placeholder" }) }), !isReadonly && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsxs("div", { className: "hdr-avatar-overlay", children: [jsxRuntimeExports.jsxs("button", { type: "button", className: "hdr-avatar-action", onClick: () => fileInputRef.current?.click(), children: [jsxRuntimeExports.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }), jsxRuntimeExports.jsx("polyline", { points: "17 8 12 3 7 8" }), jsxRuntimeExports.jsx("line", { x1: "12", y1: "3", x2: "12", y2: "15" })] }), "Upload"] }), jsxRuntimeExports.jsxs("button", { type: "button", className: "hdr-avatar-action hdr-avatar-action--delete", onClick: handleImageDelete, children: [jsxRuntimeExports.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("polyline", { points: "3 6 5 6 21 6" }), jsxRuntimeExports.jsx("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })] }), "Delete"] })] }), jsxRuntimeExports.jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", style: { display: 'none' }, onChange: handleImageUpload })] }))] }), jsxRuntimeExports.jsxs("div", { className: "hdr-info", children: [displayName && jsxRuntimeExports.jsx("div", { className: "hdr-name", children: displayName }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-field-label", children: [getLabel('functionalId'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-field-value", children: functionalId || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsx("span", { className: "hdr-field-label", children: getLabel('status') }), isReadonly ? (statusLabel ? (jsxRuntimeExports.jsx("span", { className: "hdr-status-badge", style: { backgroundColor: statusColor }, children: statusLabel })) : (jsxRuntimeExports.jsx("span", { className: "hdr-field-value", children: "-" }))) : (jsxRuntimeExports.jsxs("select", { className: "hdr-select", value: statusValue, onChange: (e) => updateFieldValue('status', e.target.value), children: [jsxRuntimeExports.jsx("option", { value: "", children: getLabel('select') }), statusOptions.map((opt) => (jsxRuntimeExports.jsx("option", { value: opt.value, children: opt.label }, opt.value)))] }))] }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-field-label", children: [getLabel('statusReason'), " :"] }), isReadonly ? (jsxRuntimeExports.jsx("span", { className: "hdr-field-value", children: statusReason || '-' })) : (jsxRuntimeExports.jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 4 }, children: [jsxRuntimeExports.jsx("input", { type: "text", className: `hdr-input ${(!isReadonly && (showReasonRequired || isReasonMissing) && isReasonMissing) ? 'hdr-input--error' : ''}`, value: statusReason, placeholder: getLabel('enterReason'), required: isStatusChanged, "aria-required": isStatusChanged, "aria-invalid": !isReadonly && (showReasonRequired || isReasonMissing) && isReasonMissing, onBlur: () => {
|
|
10618
|
+
} })) : null, jsxRuntimeExports.jsx("div", { className: "hdr-avatar-placeholder", style: { display: displayImageUrl ? 'none' : 'flex' }, children: jsxRuntimeExports.jsx("img", { src: img$f, alt: "Profile Placeholder" }) }), !isReadonly && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsxs("div", { className: "hdr-avatar-overlay", children: [jsxRuntimeExports.jsxs("button", { type: "button", className: "hdr-avatar-action", onClick: () => fileInputRef.current?.click(), children: [jsxRuntimeExports.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }), jsxRuntimeExports.jsx("polyline", { points: "17 8 12 3 7 8" }), jsxRuntimeExports.jsx("line", { x1: "12", y1: "3", x2: "12", y2: "15" })] }), "Upload"] }), jsxRuntimeExports.jsxs("button", { type: "button", className: "hdr-avatar-action hdr-avatar-action--delete", onClick: handleImageDelete, children: [jsxRuntimeExports.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("polyline", { points: "3 6 5 6 21 6" }), jsxRuntimeExports.jsx("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })] }), "Delete"] })] }), jsxRuntimeExports.jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", style: { display: 'none' }, onChange: handleImageUpload })] }))] }), jsxRuntimeExports.jsxs("div", { className: "hdr-info", children: [displayName && jsxRuntimeExports.jsx("div", { className: "hdr-name", children: displayName }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-field-label", title: `${getLabel('functionalId')} :`, children: [getLabel('functionalId'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-field-value", title: functionalId || '-', children: functionalId || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsx("span", { className: "hdr-field-label", title: getLabel('status'), children: getLabel('status') }), isReadonly ? (statusLabel ? (jsxRuntimeExports.jsx("span", { className: "hdr-status-badge", style: { backgroundColor: statusColor }, title: statusLabel, children: statusLabel })) : (jsxRuntimeExports.jsx("span", { className: "hdr-field-value", title: "-", children: "-" }))) : (jsxRuntimeExports.jsxs("select", { className: "hdr-select", value: statusValue, onChange: (e) => updateFieldValue('status', e.target.value), children: [jsxRuntimeExports.jsx("option", { value: "", children: getLabel('select') }), statusOptions.map((opt) => (jsxRuntimeExports.jsx("option", { value: opt.value, children: opt.label }, opt.value)))] }))] }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-field-label", title: `${getLabel('statusReason')} :`, children: [getLabel('statusReason'), " :"] }), isReadonly ? (jsxRuntimeExports.jsx("span", { className: "hdr-field-value", title: statusReason || '-', children: statusReason || '-' })) : (jsxRuntimeExports.jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 4 }, children: [jsxRuntimeExports.jsx("input", { type: "text", className: `hdr-input ${(!isReadonly && (showReasonRequired || isReasonMissing) && isReasonMissing) ? 'hdr-input--error' : ''}`, value: statusReason, placeholder: getLabel('enterReason'), required: isStatusChanged, "aria-required": isStatusChanged, "aria-invalid": !isReadonly && (showReasonRequired || isReasonMissing) && isReasonMissing, onBlur: () => {
|
|
10334
10619
|
if (isReasonMissing)
|
|
10335
10620
|
setShowReasonRequired(true);
|
|
10336
10621
|
}, onChange: (e) => {
|
|
@@ -10338,7 +10623,7 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
10338
10623
|
if (showReasonRequired && String(e.target.value || '').trim().length > 0) {
|
|
10339
10624
|
setShowReasonRequired(false);
|
|
10340
10625
|
}
|
|
10341
|
-
} }), !isReadonly && (showReasonRequired || isReasonMissing) && isReasonMissing ? (jsxRuntimeExports.jsx("div", { className: "hdr-error-text", children: getLabel('enterReason') })) : null] }))] })] })] }), jsxRuntimeExports.jsx("div", { className: "hdr-right", children: jsxRuntimeExports.jsxs("div", { className: "hdr-right-top", children: [jsxRuntimeExports.jsxs("div", { className: "hdr-meta-col", children: [jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", children: [getLabel('createdBy'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", children: createdBy || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", children: [getLabel('createdAt'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", children: createdAt || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", children: [getLabel('lastApprovedBy'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", children: lastApprovedBy || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", children: [getLabel('lastApprovedAt'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", children: lastApprovedAt || '-' })] })] }), score ? (jsxRuntimeExports.jsx("div", { className: "hdr-score-ring", style: { ['--pct']: score.percent }, "aria-label": `Completion score ${score.completionDisplay} of ${score.idealDisplay} (${score.percent}%)`, title: `${score.completionDisplay} / ${score.idealDisplay} (${score.percent}%)`, children: jsxRuntimeExports.jsx("div", { className: "hdr-score-value", children: String(score.completionDisplay) }) })) : null] }) })] })] }));
|
|
10626
|
+
} }), !isReadonly && (showReasonRequired || isReasonMissing) && isReasonMissing ? (jsxRuntimeExports.jsx("div", { className: "hdr-error-text", children: getLabel('enterReason') })) : null] }))] })] })] }), jsxRuntimeExports.jsx("div", { className: "hdr-right", children: jsxRuntimeExports.jsxs("div", { className: "hdr-right-top", children: [jsxRuntimeExports.jsxs("div", { className: "hdr-meta-col", children: [jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", title: `${getLabel('createdBy')} :`, children: [getLabel('createdBy'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", title: createdBy || '-', children: createdBy || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", title: `${getLabel('createdAt')} :`, children: [getLabel('createdAt'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", title: createdAt || '-', children: createdAt || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", title: `${getLabel('lastApprovedBy')} :`, children: [getLabel('lastApprovedBy'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", title: lastApprovedBy || '-', children: lastApprovedBy || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", title: `${getLabel('lastApprovedAt')} :`, children: [getLabel('lastApprovedAt'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", title: lastApprovedAt || '-', children: lastApprovedAt || '-' })] })] }), score ? (jsxRuntimeExports.jsx("div", { className: "hdr-score-ring", style: { ['--pct']: score.percent }, "aria-label": `Completion score ${score.completionDisplay} of ${score.idealDisplay} (${score.percent}%)`, title: `${score.completionDisplay} / ${score.idealDisplay} (${score.percent}%)`, children: jsxRuntimeExports.jsx("div", { className: "hdr-score-value", children: String(score.completionDisplay) }) })) : null] }) })] })] }));
|
|
10342
10627
|
};
|
|
10343
10628
|
|
|
10344
10629
|
function getValueByPathOrKey(obj, path) {
|
|
@@ -11539,6 +11824,7 @@ exports.getValueByPath = getValueByPath;
|
|
|
11539
11824
|
exports.getWidgetValue = getWidgetValue;
|
|
11540
11825
|
exports.initI18n = initI18n;
|
|
11541
11826
|
exports.isAllowedKey = isAllowedKey;
|
|
11827
|
+
exports.normalizeNumericDefault = normalizeNumericDefault;
|
|
11542
11828
|
exports.parseDataPath = parseDataPath;
|
|
11543
11829
|
exports.parseNumber = parseNumber;
|
|
11544
11830
|
exports.registerDefaultWidgets = registerDefaultWidgets;
|