@openg2p/registry-widgets 1.1.0 → 1.1.1
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 +11 -0
- package/dist/index.esm.js +385 -126
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +384 -125
- 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/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/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
|
@@ -808,6 +808,40 @@ const parseDateFromFormat = (dateString, format) => {
|
|
|
808
808
|
}
|
|
809
809
|
return parseDate(dateString);
|
|
810
810
|
};
|
|
811
|
+
/**
|
|
812
|
+
* Resolve a stored date value (ISO or parseable string) to YYYY-MM-DD for comparisons.
|
|
813
|
+
*/
|
|
814
|
+
const resolveDateBoundFromFieldValue = (fieldValue) => {
|
|
815
|
+
if (fieldValue == null || fieldValue === '') {
|
|
816
|
+
return undefined;
|
|
817
|
+
}
|
|
818
|
+
const iso = formatDateToISO(fieldValue);
|
|
819
|
+
return iso || undefined;
|
|
820
|
+
};
|
|
821
|
+
/**
|
|
822
|
+
* Pick the stricter (later) minimum when combining static and field-based bounds.
|
|
823
|
+
*/
|
|
824
|
+
const mergeMinDateBounds = (boundA, boundB) => {
|
|
825
|
+
if (!boundA) {
|
|
826
|
+
return boundB;
|
|
827
|
+
}
|
|
828
|
+
if (!boundB) {
|
|
829
|
+
return boundA;
|
|
830
|
+
}
|
|
831
|
+
return boundA > boundB ? boundA : boundB;
|
|
832
|
+
};
|
|
833
|
+
/**
|
|
834
|
+
* Pick the stricter (earlier) maximum when combining static and field-based bounds.
|
|
835
|
+
*/
|
|
836
|
+
const mergeMaxDateBounds = (boundA, boundB) => {
|
|
837
|
+
if (!boundA) {
|
|
838
|
+
return boundB;
|
|
839
|
+
}
|
|
840
|
+
if (!boundB) {
|
|
841
|
+
return boundA;
|
|
842
|
+
}
|
|
843
|
+
return boundA < boundB ? boundA : boundB;
|
|
844
|
+
};
|
|
811
845
|
/**
|
|
812
846
|
* Get min date based on constraint type
|
|
813
847
|
*/
|
|
@@ -850,10 +884,7 @@ const getMaxDate = (constraint, maxDate) => {
|
|
|
850
884
|
}
|
|
851
885
|
return undefined;
|
|
852
886
|
};
|
|
853
|
-
|
|
854
|
-
* Validate date constraints
|
|
855
|
-
*/
|
|
856
|
-
const validateDateConstraints = (date, minDate, maxDate, constraint) => {
|
|
887
|
+
const validateDateConstraints = (date, minDate, maxDate, constraint, messages) => {
|
|
857
888
|
if (!date)
|
|
858
889
|
return null;
|
|
859
890
|
const dateObj = date instanceof Date ? date : parseDate(date);
|
|
@@ -872,15 +903,12 @@ const validateDateConstraints = (date, minDate, maxDate, constraint) => {
|
|
|
872
903
|
return 'Date must be in the future';
|
|
873
904
|
}
|
|
874
905
|
}
|
|
875
|
-
//
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
return `Date must be on or after ${effectiveMinDate}`;
|
|
906
|
+
// minDate / maxDate are effective bounds (static + field-based), resolved by the caller
|
|
907
|
+
if (minDate && dateISO < minDate) {
|
|
908
|
+
return messages?.minDateMessage ?? `Date must be on or after ${minDate}`;
|
|
879
909
|
}
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
if (effectiveMaxDate && dateISO > effectiveMaxDate) {
|
|
883
|
-
return `Date must be on or before ${effectiveMaxDate}`;
|
|
910
|
+
if (maxDate && dateISO > maxDate) {
|
|
911
|
+
return messages?.maxDateMessage ?? `Date must be on or before ${maxDate}`;
|
|
884
912
|
}
|
|
885
913
|
return null;
|
|
886
914
|
};
|
|
@@ -3794,6 +3822,116 @@ const namespaceSectionConfig = (section, namespace) => {
|
|
|
3794
3822
|
return namespaced;
|
|
3795
3823
|
};
|
|
3796
3824
|
|
|
3825
|
+
/** Table-style widgets that bind to an array path in the store / schema. */
|
|
3826
|
+
function isTableLikeWidget(widget) {
|
|
3827
|
+
const w = widget.widget;
|
|
3828
|
+
/** widget-type union in types omits legacy values like simple-table still used at runtime */
|
|
3829
|
+
const t = widget['widget-type'];
|
|
3830
|
+
return (w === 'table' ||
|
|
3831
|
+
w === 'dialog-table' ||
|
|
3832
|
+
w === 'simple-table' ||
|
|
3833
|
+
t === 'table' ||
|
|
3834
|
+
t === 'simple-table');
|
|
3835
|
+
}
|
|
3836
|
+
/**
|
|
3837
|
+
* Resolve `records` for section save payloads.
|
|
3838
|
+
* - Back-compat: path ending in `.records` (e.g. `regId.records`)
|
|
3839
|
+
* - Else: first array snapshot at a string `widget-data-path` on a table-like widget
|
|
3840
|
+
* (e.g. `household.members` for dialog-table)
|
|
3841
|
+
*/
|
|
3842
|
+
function extractTableRecordsFromSnapshot(snapshot, sectionWidgets) {
|
|
3843
|
+
const convention = Object.entries(snapshot).find(([key, value]) => key.endsWith('.records') && Array.isArray(value));
|
|
3844
|
+
if (convention) {
|
|
3845
|
+
return convention[1];
|
|
3846
|
+
}
|
|
3847
|
+
const tablePaths = [];
|
|
3848
|
+
sectionWidgets.forEach((widget) => {
|
|
3849
|
+
if (!isTableLikeWidget(widget))
|
|
3850
|
+
return;
|
|
3851
|
+
const p = widget['widget-data-path'];
|
|
3852
|
+
if (typeof p === 'string' && p.length > 0) {
|
|
3853
|
+
tablePaths.push(p);
|
|
3854
|
+
}
|
|
3855
|
+
else if (p && typeof p === 'object') {
|
|
3856
|
+
Object.values(p).forEach((sub) => {
|
|
3857
|
+
if (typeof sub === 'string' && sub.length > 0)
|
|
3858
|
+
tablePaths.push(sub);
|
|
3859
|
+
});
|
|
3860
|
+
}
|
|
3861
|
+
});
|
|
3862
|
+
for (const path of tablePaths) {
|
|
3863
|
+
const val = snapshot[path];
|
|
3864
|
+
if (Array.isArray(val)) {
|
|
3865
|
+
return val;
|
|
3866
|
+
}
|
|
3867
|
+
}
|
|
3868
|
+
return [];
|
|
3869
|
+
}
|
|
3870
|
+
|
|
3871
|
+
const isColumnRequired = (column, skipRequired) => {
|
|
3872
|
+
if (skipRequired)
|
|
3873
|
+
return false;
|
|
3874
|
+
const validation = column['widget-data-validation'];
|
|
3875
|
+
return !!(column['widget-required'] || validation?.required);
|
|
3876
|
+
};
|
|
3877
|
+
const validateTableLikeWidget = (widget, currentSchemaData, dispatch, skipRequired) => {
|
|
3878
|
+
const widgetId = widget['widget-id'];
|
|
3879
|
+
if (!widgetId)
|
|
3880
|
+
return true;
|
|
3881
|
+
const columns = (widget['widget-data-columns'] || []);
|
|
3882
|
+
const value = getWidgetValue(currentSchemaData, widget['widget-data-path'], widgetId);
|
|
3883
|
+
const rows = Array.isArray(value)
|
|
3884
|
+
? value
|
|
3885
|
+
: [];
|
|
3886
|
+
const activeRows = rows.filter((row) => row?.edit_action !== 'DELETE');
|
|
3887
|
+
const rowErrors = [];
|
|
3888
|
+
let isValid = true;
|
|
3889
|
+
if (!skipRequired && widget['widget-required'] && activeRows.length === 0) {
|
|
3890
|
+
dispatch(setTouched({ widgetId, touched: true }));
|
|
3891
|
+
dispatch(setError({ widgetId, errors: ['At least one record is required'] }));
|
|
3892
|
+
return false;
|
|
3893
|
+
}
|
|
3894
|
+
const hasRequiredColumns = columns.some((col) => isColumnRequired(col, skipRequired));
|
|
3895
|
+
if (!skipRequired && hasRequiredColumns && activeRows.length === 0) {
|
|
3896
|
+
dispatch(setTouched({ widgetId, touched: true }));
|
|
3897
|
+
dispatch(setError({
|
|
3898
|
+
widgetId,
|
|
3899
|
+
errors: ['Add at least one record and fill all required fields'],
|
|
3900
|
+
}));
|
|
3901
|
+
return false;
|
|
3902
|
+
}
|
|
3903
|
+
activeRows.forEach((row, rowIndex) => {
|
|
3904
|
+
columns.forEach((col) => {
|
|
3905
|
+
if (col['widget-readonly'])
|
|
3906
|
+
return;
|
|
3907
|
+
const key = col['column-key'];
|
|
3908
|
+
if (!key)
|
|
3909
|
+
return;
|
|
3910
|
+
const required = isColumnRequired(col, skipRequired);
|
|
3911
|
+
const cellValue = row[key];
|
|
3912
|
+
const errors = validateWidget(cellValue, col['widget-data-validation'], required, skipRequired);
|
|
3913
|
+
if (errors.length > 0) {
|
|
3914
|
+
isValid = false;
|
|
3915
|
+
const label = col['widget-label'] || key;
|
|
3916
|
+
rowErrors.push(`Row ${rowIndex + 1}, ${label}: ${errors[0]}`);
|
|
3917
|
+
}
|
|
3918
|
+
});
|
|
3919
|
+
});
|
|
3920
|
+
if (!isValid) {
|
|
3921
|
+
dispatch(setTouched({ widgetId, touched: true }));
|
|
3922
|
+
dispatch(setError({
|
|
3923
|
+
widgetId,
|
|
3924
|
+
errors: rowErrors.length > 0
|
|
3925
|
+
? rowErrors.slice(0, 5)
|
|
3926
|
+
: ['Please fix required fields in the table'],
|
|
3927
|
+
}));
|
|
3928
|
+
}
|
|
3929
|
+
else {
|
|
3930
|
+
dispatch(setTouched({ widgetId, touched: false }));
|
|
3931
|
+
dispatch(setError({ widgetId, errors: [] }));
|
|
3932
|
+
}
|
|
3933
|
+
return isValid;
|
|
3934
|
+
};
|
|
3797
3935
|
const collectWidgets = (panels) => {
|
|
3798
3936
|
let widgets = [];
|
|
3799
3937
|
panels.forEach((panel) => {
|
|
@@ -3822,6 +3960,13 @@ const sectionValidate = (section, currentSchemaData, dispatch, skipRequired = fa
|
|
|
3822
3960
|
if (!isVisible)
|
|
3823
3961
|
continue;
|
|
3824
3962
|
const widgetId = widget['widget-id'];
|
|
3963
|
+
if (isTableLikeWidget(widget)) {
|
|
3964
|
+
const tableValid = validateTableLikeWidget(widget, currentSchemaData, dispatch, skipRequired);
|
|
3965
|
+
if (!tableValid) {
|
|
3966
|
+
isValid = false;
|
|
3967
|
+
}
|
|
3968
|
+
continue;
|
|
3969
|
+
}
|
|
3825
3970
|
const value = getWidgetValue(currentSchemaData, widget['widget-data-path'], widgetId);
|
|
3826
3971
|
const errors = validateWidget(value, widget['widget-data-validation'], widget['widget-required'], skipRequired);
|
|
3827
3972
|
if (errors.length > 0) {
|
|
@@ -3856,52 +4001,6 @@ const sectionValidate = (section, currentSchemaData, dispatch, skipRequired = fa
|
|
|
3856
4001
|
return isValid;
|
|
3857
4002
|
};
|
|
3858
4003
|
|
|
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
4004
|
/** Root class on readonly label/value rows; SectionRenderer scopes overflow/ellipsis rules here. */
|
|
3906
4005
|
const READONLY_VALUE_ROW_ROOT_CLASSES = [
|
|
3907
4006
|
'TextDisplayWidget',
|
|
@@ -7511,6 +7610,8 @@ const BooleanWidget = ({ config }) => {
|
|
|
7511
7610
|
return labels[representation];
|
|
7512
7611
|
}, [representation, formatConfig, translateConfig]);
|
|
7513
7612
|
const { trueLabel, falseLabel } = getLabels();
|
|
7613
|
+
const unsetLabel = React.useMemo(() => translateConfig(formatConfig?.booleanUnsetLabel || 'Not set'), [formatConfig?.booleanUnsetLabel, translateConfig]);
|
|
7614
|
+
const radioGroupName = `${widgetConfig['widget-id'] ?? 'boolean'}__${React.useId().replace(/:/g, '')}`;
|
|
7514
7615
|
// Determine current value (handle null/undefined)
|
|
7515
7616
|
const currentValue = React.useMemo(() => {
|
|
7516
7617
|
if (value === null || value === undefined) {
|
|
@@ -7542,7 +7643,7 @@ const BooleanWidget = ({ config }) => {
|
|
|
7542
7643
|
const label = translateConfig(widgetConfig['widget-label']);
|
|
7543
7644
|
let displayValue = '';
|
|
7544
7645
|
if (currentValue === null) {
|
|
7545
|
-
displayValue = '
|
|
7646
|
+
displayValue = '';
|
|
7546
7647
|
}
|
|
7547
7648
|
else if (currentValue === true) {
|
|
7548
7649
|
displayValue = trueLabel;
|
|
@@ -7554,18 +7655,20 @@ const BooleanWidget = ({ config }) => {
|
|
|
7554
7655
|
}
|
|
7555
7656
|
// Render based on control type
|
|
7556
7657
|
if (controlType === 'checkbox') {
|
|
7557
|
-
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-
|
|
7658
|
+
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
7659
|
}
|
|
7559
7660
|
if (controlType === 'radio') {
|
|
7560
7661
|
const containerClass = orientation === 'horizontal'
|
|
7561
|
-
? 'flex flex-row
|
|
7562
|
-
: 'flex flex-col
|
|
7563
|
-
|
|
7662
|
+
? 'flex flex-row flex-wrap items-baseline gap-x-4 gap-y-2'
|
|
7663
|
+
: 'flex flex-col items-start gap-2';
|
|
7664
|
+
const radioDisabled = !isEnabled || widgetConfig['widget-readonly'];
|
|
7665
|
+
const optionDisabledClass = radioDisabled ? 'opacity-50 cursor-not-allowed' : '';
|
|
7666
|
+
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
7667
|
}
|
|
7565
7668
|
// 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-
|
|
7669
|
+
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
7670
|
? '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:
|
|
7671
|
+
: '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
7672
|
? 'bg-blue-600 text-white border-blue-600'
|
|
7570
7673
|
: '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
7674
|
? 'bg-blue-600 text-white border-blue-600'
|
|
@@ -7573,42 +7676,76 @@ const BooleanWidget = ({ config }) => {
|
|
|
7573
7676
|
};
|
|
7574
7677
|
|
|
7575
7678
|
const DateInputWidget = ({ config }) => {
|
|
7576
|
-
const { value,
|
|
7577
|
-
const
|
|
7679
|
+
const { value, error, touched, isEnabled, onChange, onBlur, setError, config: widgetConfig, } = useBaseWidget({ config });
|
|
7680
|
+
const formValues = reactRedux.useSelector((state) => state.widget.values);
|
|
7681
|
+
const { translateConfig } = useWidgetTranslation();
|
|
7578
7682
|
const formatConfig = widgetConfig['widget-data-format'];
|
|
7579
7683
|
const optionsConfig = widgetConfig['widget-data-options'];
|
|
7580
7684
|
const dateFormat = formatConfig?.dateFormat || 'YYYY-MM-DD';
|
|
7581
|
-
const inputMethod = formatConfig?.inputMethod || 'picker';
|
|
7685
|
+
const inputMethod = formatConfig?.inputMethod || 'picker';
|
|
7582
7686
|
const dateConstraint = formatConfig?.dateConstraint || 'any';
|
|
7583
7687
|
const minDate = optionsConfig?.minDate;
|
|
7584
7688
|
const maxDate = optionsConfig?.maxDate;
|
|
7689
|
+
const minDateField = optionsConfig?.minDateField;
|
|
7690
|
+
const maxDateField = optionsConfig?.maxDateField;
|
|
7691
|
+
const minDateMessage = optionsConfig?.minDateMessage
|
|
7692
|
+
? translateConfig(optionsConfig.minDateMessage)
|
|
7693
|
+
: undefined;
|
|
7694
|
+
const maxDateMessage = optionsConfig?.maxDateMessage
|
|
7695
|
+
? translateConfig(optionsConfig.maxDateMessage)
|
|
7696
|
+
: undefined;
|
|
7585
7697
|
const defaultToToday = widgetConfig['widget-data-default'] === 'today';
|
|
7586
|
-
// Track manual input value (for manual/hybrid modes)
|
|
7587
7698
|
const [manualInputValue, setManualInputValue] = React.useState('');
|
|
7588
7699
|
const [isFocused, setIsFocused] = React.useState(false);
|
|
7589
|
-
|
|
7700
|
+
const fieldMinDate = React.useMemo(() => {
|
|
7701
|
+
if (!minDateField) {
|
|
7702
|
+
return undefined;
|
|
7703
|
+
}
|
|
7704
|
+
return resolveDateBoundFromFieldValue(getValueByPath(formValues, minDateField));
|
|
7705
|
+
}, [formValues, minDateField]);
|
|
7706
|
+
const fieldMaxDate = React.useMemo(() => {
|
|
7707
|
+
if (!maxDateField) {
|
|
7708
|
+
return undefined;
|
|
7709
|
+
}
|
|
7710
|
+
return resolveDateBoundFromFieldValue(getValueByPath(formValues, maxDateField));
|
|
7711
|
+
}, [formValues, maxDateField]);
|
|
7712
|
+
const effectiveMinDate = React.useMemo(() => {
|
|
7713
|
+
const staticMin = getMinDate(dateConstraint, minDate);
|
|
7714
|
+
return mergeMinDateBounds(staticMin, fieldMinDate);
|
|
7715
|
+
}, [dateConstraint, minDate, fieldMinDate]);
|
|
7716
|
+
const effectiveMaxDate = React.useMemo(() => {
|
|
7717
|
+
const staticMax = getMaxDate(dateConstraint, maxDate);
|
|
7718
|
+
return mergeMaxDateBounds(staticMax, fieldMaxDate);
|
|
7719
|
+
}, [dateConstraint, maxDate, fieldMaxDate]);
|
|
7720
|
+
const constraintMessages = React.useMemo(() => ({ minDateMessage, maxDateMessage }), [minDateMessage, maxDateMessage]);
|
|
7721
|
+
const runDateConstraintValidation = React.useCallback((dateValue) => {
|
|
7722
|
+
if (!dateValue) {
|
|
7723
|
+
return null;
|
|
7724
|
+
}
|
|
7725
|
+
return validateDateConstraints(dateValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages);
|
|
7726
|
+
}, [effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages]);
|
|
7590
7727
|
React.useEffect(() => {
|
|
7591
7728
|
if (defaultToToday && (value === null || value === undefined || value === '')) {
|
|
7592
7729
|
const todayISO = formatDateToISO(new Date());
|
|
7593
7730
|
onChange(todayISO);
|
|
7594
7731
|
}
|
|
7595
7732
|
}, [defaultToToday, value, onChange]);
|
|
7596
|
-
//
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7733
|
+
// Re-validate when a relative bound field changes (e.g. start date set after end date)
|
|
7734
|
+
React.useEffect(() => {
|
|
7735
|
+
if (!value) {
|
|
7736
|
+
return;
|
|
7737
|
+
}
|
|
7738
|
+
const constraintError = runDateConstraintValidation(value);
|
|
7739
|
+
if (constraintError) {
|
|
7740
|
+
setError([constraintError]);
|
|
7741
|
+
}
|
|
7742
|
+
}, [fieldMinDate, fieldMaxDate, value, runDateConstraintValidation, setError]);
|
|
7604
7743
|
const getDisplayValue = React.useCallback(() => {
|
|
7605
|
-
// For picker mode, always use YYYY-MM-DD
|
|
7606
7744
|
if (inputMethod === 'picker') {
|
|
7607
7745
|
if (!value)
|
|
7608
7746
|
return '';
|
|
7609
7747
|
return formatDateToISO(value);
|
|
7610
7748
|
}
|
|
7611
|
-
// For manual/hybrid modes, use custom format
|
|
7612
7749
|
if (isFocused && manualInputValue) {
|
|
7613
7750
|
return manualInputValue;
|
|
7614
7751
|
}
|
|
@@ -7619,7 +7756,6 @@ const DateInputWidget = ({ config }) => {
|
|
|
7619
7756
|
}
|
|
7620
7757
|
return formatDateToString(value, dateFormat);
|
|
7621
7758
|
}, [value, inputMethod, dateFormat, isFocused, manualInputValue]);
|
|
7622
|
-
// Initialize manual input value
|
|
7623
7759
|
React.useEffect(() => {
|
|
7624
7760
|
if (!isFocused && value) {
|
|
7625
7761
|
if (dateFormat === 'YYYY-MM-DD') {
|
|
@@ -7630,66 +7766,81 @@ const DateInputWidget = ({ config }) => {
|
|
|
7630
7766
|
}
|
|
7631
7767
|
}
|
|
7632
7768
|
}, [value, dateFormat, isFocused]);
|
|
7633
|
-
|
|
7769
|
+
const applyConstraintError = React.useCallback((dateValue) => {
|
|
7770
|
+
const constraintError = runDateConstraintValidation(dateValue);
|
|
7771
|
+
setError(constraintError ? [constraintError] : []);
|
|
7772
|
+
}, [runDateConstraintValidation, setError]);
|
|
7634
7773
|
const handleChange = React.useCallback((e) => {
|
|
7635
7774
|
const inputValue = e.target.value;
|
|
7636
7775
|
if (inputMethod === 'picker') {
|
|
7637
|
-
// Picker mode: input is always YYYY-MM-DD
|
|
7638
7776
|
if (inputValue) {
|
|
7639
7777
|
const date = parseDate(inputValue);
|
|
7640
7778
|
if (date) {
|
|
7641
|
-
|
|
7779
|
+
const iso = formatDateToISO(date);
|
|
7780
|
+
onChange(iso);
|
|
7781
|
+
applyConstraintError(iso);
|
|
7642
7782
|
}
|
|
7643
7783
|
else {
|
|
7644
7784
|
onChange('');
|
|
7785
|
+
setError([]);
|
|
7645
7786
|
}
|
|
7646
7787
|
}
|
|
7647
7788
|
else {
|
|
7648
7789
|
onChange('');
|
|
7790
|
+
setError([]);
|
|
7649
7791
|
}
|
|
7650
7792
|
}
|
|
7651
7793
|
else {
|
|
7652
|
-
// Manual/hybrid mode: parse custom format
|
|
7653
7794
|
setManualInputValue(inputValue);
|
|
7654
7795
|
if (inputValue) {
|
|
7655
7796
|
const date = parseDateFromFormat(inputValue, dateFormat);
|
|
7656
7797
|
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
|
-
}
|
|
7798
|
+
const iso = formatDateToISO(date);
|
|
7799
|
+
onChange(iso);
|
|
7800
|
+
applyConstraintError(iso);
|
|
7666
7801
|
}
|
|
7667
7802
|
}
|
|
7668
7803
|
else {
|
|
7669
7804
|
onChange('');
|
|
7805
|
+
setError([]);
|
|
7670
7806
|
}
|
|
7671
7807
|
}
|
|
7672
|
-
}, [inputMethod, dateFormat, onChange,
|
|
7673
|
-
// Handle blur - validate and format
|
|
7808
|
+
}, [inputMethod, dateFormat, onChange, applyConstraintError, setError]);
|
|
7674
7809
|
const handleBlur = React.useCallback(() => {
|
|
7675
7810
|
setIsFocused(false);
|
|
7676
7811
|
if (inputMethod !== 'picker' && manualInputValue) {
|
|
7677
7812
|
const date = parseDateFromFormat(manualInputValue, dateFormat);
|
|
7678
7813
|
if (date) {
|
|
7679
|
-
// Format the value according to the format
|
|
7680
7814
|
const formatted = formatDateToString(date, dateFormat);
|
|
7681
7815
|
setManualInputValue(formatted);
|
|
7682
|
-
|
|
7816
|
+
const iso = formatDateToISO(date);
|
|
7817
|
+
onChange(iso);
|
|
7818
|
+
applyConstraintError(iso);
|
|
7683
7819
|
}
|
|
7684
7820
|
else {
|
|
7685
|
-
// Invalid date, clear it
|
|
7686
7821
|
setManualInputValue('');
|
|
7687
7822
|
onChange('');
|
|
7823
|
+
setError([]);
|
|
7688
7824
|
}
|
|
7689
7825
|
}
|
|
7690
7826
|
onBlur();
|
|
7691
|
-
|
|
7692
|
-
|
|
7827
|
+
if (value) {
|
|
7828
|
+
const constraintError = runDateConstraintValidation(value);
|
|
7829
|
+
if (constraintError) {
|
|
7830
|
+
setError([constraintError]);
|
|
7831
|
+
}
|
|
7832
|
+
}
|
|
7833
|
+
}, [
|
|
7834
|
+
inputMethod,
|
|
7835
|
+
manualInputValue,
|
|
7836
|
+
dateFormat,
|
|
7837
|
+
onChange,
|
|
7838
|
+
onBlur,
|
|
7839
|
+
applyConstraintError,
|
|
7840
|
+
value,
|
|
7841
|
+
runDateConstraintValidation,
|
|
7842
|
+
setError,
|
|
7843
|
+
]);
|
|
7693
7844
|
const handleFocus = React.useCallback(() => {
|
|
7694
7845
|
setIsFocused(true);
|
|
7695
7846
|
if (value) {
|
|
@@ -7701,15 +7852,15 @@ const DateInputWidget = ({ config }) => {
|
|
|
7701
7852
|
}
|
|
7702
7853
|
}
|
|
7703
7854
|
}, [value, dateFormat]);
|
|
7704
|
-
// Determine placeholder
|
|
7705
7855
|
const placeholder = React.useMemo(() => {
|
|
7706
|
-
const
|
|
7856
|
+
const display = getDisplayValue();
|
|
7857
|
+
const hasValue = display && display.trim().length > 0;
|
|
7707
7858
|
const placeholderText = translateConfig(widgetConfig['widget-data-placeholder']);
|
|
7708
|
-
return hasValue ? undefined :
|
|
7859
|
+
return hasValue ? undefined : placeholderText || dateFormat;
|
|
7709
7860
|
}, [getDisplayValue, widgetConfig, translateConfig, dateFormat]);
|
|
7710
|
-
// Determine input type
|
|
7711
7861
|
const inputType = inputMethod === 'picker' ? 'date' : 'text';
|
|
7712
|
-
|
|
7862
|
+
const showRequiredError = widgetConfig['widget-required'] && (!value || value === '');
|
|
7863
|
+
const showValidationError = touched && error.length > 0;
|
|
7713
7864
|
if (widgetConfig['widget-readonly']) {
|
|
7714
7865
|
const label = translateConfig(widgetConfig['widget-label']);
|
|
7715
7866
|
let displayValue = '';
|
|
@@ -7726,9 +7877,9 @@ const DateInputWidget = ({ config }) => {
|
|
|
7726
7877
|
}
|
|
7727
7878
|
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
7879
|
}
|
|
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'] &&
|
|
7880
|
+
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
7881
|
? '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']) }),
|
|
7882
|
+
: '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
7883
|
};
|
|
7733
7884
|
|
|
7734
7885
|
/**
|
|
@@ -8276,7 +8427,7 @@ const CheckboxWidget = ({ config }) => {
|
|
|
8276
8427
|
const displayValue = isChecked ? 'Yes' : 'No';
|
|
8277
8428
|
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
8429
|
}
|
|
8279
|
-
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-
|
|
8430
|
+
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
8431
|
}
|
|
8281
8432
|
// Multiple checkboxes (with data source) - for array values
|
|
8282
8433
|
// Process and sort options if needed
|
|
@@ -8319,7 +8470,7 @@ const CheckboxWidget = ({ config }) => {
|
|
|
8319
8470
|
switch (layout) {
|
|
8320
8471
|
case 'horizontal':
|
|
8321
8472
|
return {
|
|
8322
|
-
className: 'flex flex-row flex-wrap gap-4',
|
|
8473
|
+
className: 'flex flex-row flex-wrap items-baseline gap-4',
|
|
8323
8474
|
style: undefined,
|
|
8324
8475
|
};
|
|
8325
8476
|
case 'grid':
|
|
@@ -8332,7 +8483,7 @@ const CheckboxWidget = ({ config }) => {
|
|
|
8332
8483
|
case 'vertical':
|
|
8333
8484
|
default:
|
|
8334
8485
|
return {
|
|
8335
|
-
className: 'flex flex-col
|
|
8486
|
+
className: 'flex flex-col gap-2',
|
|
8336
8487
|
style: undefined,
|
|
8337
8488
|
};
|
|
8338
8489
|
}
|
|
@@ -8346,7 +8497,7 @@ const CheckboxWidget = ({ config }) => {
|
|
|
8346
8497
|
: '-';
|
|
8347
8498
|
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
8499
|
}
|
|
8349
|
-
return (jsxRuntimeExports.jsx("div", { className: "mb-[10px]", children: jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-
|
|
8500
|
+
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
8501
|
};
|
|
8351
8502
|
|
|
8352
8503
|
const SimpleTableWidget = ({ config }) => {
|
|
@@ -8672,16 +8823,70 @@ const TableCellNumber = ({ config, value, onValueChange }) => {
|
|
|
8672
8823
|
backgroundColor: isReadonly ? 'var(--owt-color-bg-alt, #F6F6F6)' : 'var(--owt-color-bg, #FFFFFF)',
|
|
8673
8824
|
} }));
|
|
8674
8825
|
};
|
|
8675
|
-
const TableCellDate = ({ config, value, onValueChange }) => {
|
|
8826
|
+
const TableCellDate = ({ config, value, rowValues, onValueChange }) => {
|
|
8827
|
+
const { translateConfig } = useWidgetTranslation();
|
|
8676
8828
|
const isReadonly = config['widget-readonly'] || false;
|
|
8677
8829
|
const placeholder = config['widget-data-placeholder'] || '';
|
|
8830
|
+
const optionsConfig = config['widget-data-options'];
|
|
8831
|
+
const formatConfig = config['widget-data-format'];
|
|
8832
|
+
const dateConstraint = formatConfig?.dateConstraint || 'any';
|
|
8833
|
+
const minDate = optionsConfig?.minDate;
|
|
8834
|
+
const maxDate = optionsConfig?.maxDate;
|
|
8835
|
+
const minDateField = optionsConfig?.minDateField;
|
|
8836
|
+
const maxDateField = optionsConfig?.maxDateField;
|
|
8837
|
+
const minDateMessage = optionsConfig?.minDateMessage
|
|
8838
|
+
? translateConfig(optionsConfig.minDateMessage)
|
|
8839
|
+
: undefined;
|
|
8840
|
+
const maxDateMessage = optionsConfig?.maxDateMessage
|
|
8841
|
+
? translateConfig(optionsConfig.maxDateMessage)
|
|
8842
|
+
: undefined;
|
|
8843
|
+
const [constraintError, setConstraintError] = React.useState(null);
|
|
8844
|
+
const resolveSiblingDate = (fieldRef) => {
|
|
8845
|
+
if (!fieldRef || !rowValues) {
|
|
8846
|
+
return undefined;
|
|
8847
|
+
}
|
|
8848
|
+
const raw = getValueByPath(rowValues, fieldRef) ?? rowValues[fieldRef];
|
|
8849
|
+
return resolveDateBoundFromFieldValue(raw);
|
|
8850
|
+
};
|
|
8851
|
+
const fieldMinDate = React.useMemo(() => resolveSiblingDate(minDateField), [minDateField, rowValues]);
|
|
8852
|
+
const fieldMaxDate = React.useMemo(() => resolveSiblingDate(maxDateField), [maxDateField, rowValues]);
|
|
8853
|
+
const effectiveMinDate = React.useMemo(() => {
|
|
8854
|
+
const staticMin = getMinDate(dateConstraint, minDate);
|
|
8855
|
+
return mergeMinDateBounds(staticMin, fieldMinDate);
|
|
8856
|
+
}, [dateConstraint, minDate, fieldMinDate]);
|
|
8857
|
+
const effectiveMaxDate = React.useMemo(() => {
|
|
8858
|
+
const staticMax = getMaxDate(dateConstraint, maxDate);
|
|
8859
|
+
return mergeMaxDateBounds(staticMax, fieldMaxDate);
|
|
8860
|
+
}, [dateConstraint, maxDate, fieldMaxDate]);
|
|
8861
|
+
const constraintMessages = React.useMemo(() => ({ minDateMessage, maxDateMessage }), [minDateMessage, maxDateMessage]);
|
|
8678
8862
|
// input type="date" requires YYYY-MM-DD format
|
|
8679
8863
|
const displayValue = value && typeof value === 'string' ? value.split('T')[0] : '';
|
|
8680
|
-
|
|
8681
|
-
|
|
8682
|
-
|
|
8683
|
-
|
|
8684
|
-
}
|
|
8864
|
+
React.useEffect(() => {
|
|
8865
|
+
if (!displayValue) {
|
|
8866
|
+
setConstraintError(null);
|
|
8867
|
+
return;
|
|
8868
|
+
}
|
|
8869
|
+
const error = validateDateConstraints(displayValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages);
|
|
8870
|
+
setConstraintError(error);
|
|
8871
|
+
}, [displayValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages]);
|
|
8872
|
+
const handleChange = (e) => {
|
|
8873
|
+
const nextValue = e.target.value;
|
|
8874
|
+
onValueChange(nextValue);
|
|
8875
|
+
if (!nextValue) {
|
|
8876
|
+
setConstraintError(null);
|
|
8877
|
+
return;
|
|
8878
|
+
}
|
|
8879
|
+
const error = validateDateConstraints(nextValue, effectiveMinDate, effectiveMaxDate, dateConstraint, constraintMessages);
|
|
8880
|
+
setConstraintError(error);
|
|
8881
|
+
};
|
|
8882
|
+
const hasError = Boolean(constraintError);
|
|
8883
|
+
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: {
|
|
8884
|
+
borderRadius: '10px',
|
|
8885
|
+
borderColor: hasError
|
|
8886
|
+
? 'var(--owt-color-error, #B91C1C)'
|
|
8887
|
+
: 'var(--owt-widget-input-border, #C4C4C4)',
|
|
8888
|
+
backgroundColor: isReadonly ? 'var(--owt-color-bg-alt, #F6F6F6)' : 'var(--owt-color-bg, #FFFFFF)',
|
|
8889
|
+
} }), hasError && (jsxRuntimeExports.jsx("p", { className: "text-red-500 text-xs mt-0.5 leading-tight", children: constraintError }))] }));
|
|
8685
8890
|
};
|
|
8686
8891
|
const TableWidget = ({ config }) => {
|
|
8687
8892
|
const { value, error, touched, isEnabled, onChange, config: widgetConfig, } = useBaseWidget({ config });
|
|
@@ -9040,11 +9245,21 @@ const TableWidget = ({ config }) => {
|
|
|
9040
9245
|
});
|
|
9041
9246
|
}
|
|
9042
9247
|
}, [isAdding, newRowData, columns, widgetConfig, rows.length, dispatch]);
|
|
9248
|
+
const getRowValuesForEdit = React.useCallback((rowIndex) => {
|
|
9249
|
+
if (editingState && editingState.rowIndex === rowIndex) {
|
|
9250
|
+
return editingState.currentValue ?? {};
|
|
9251
|
+
}
|
|
9252
|
+
if (isAdding && rowIndex === rows.length && newRowData) {
|
|
9253
|
+
return newRowData;
|
|
9254
|
+
}
|
|
9255
|
+
return rows[rowIndex] ?? {};
|
|
9256
|
+
}, [editingState, isAdding, rows, newRowData]);
|
|
9043
9257
|
// Lightweight cell renderer for table cells (no labels, compact)
|
|
9044
9258
|
const renderTableCell = React.useCallback((rowIndex, column, cellValue, isReadonly) => {
|
|
9045
9259
|
const columnKey = column['column-key'];
|
|
9046
9260
|
const widgetType = column.widget || 'text';
|
|
9047
9261
|
const cellWidgetId = `${widgetConfig['widget-id']}-row-${rowIndex}-col-${columnKey}`;
|
|
9262
|
+
const rowValues = getRowValuesForEdit(rowIndex);
|
|
9048
9263
|
// Use lightweight cell config (no label, minimal styling)
|
|
9049
9264
|
const cellConfig = {
|
|
9050
9265
|
...column,
|
|
@@ -9067,7 +9282,7 @@ const TableWidget = ({ config }) => {
|
|
|
9067
9282
|
return jsxRuntimeExports.jsx(TableCellNumber, { config: cellConfig, value: cellValue, onValueChange: (newValue) => updateCellValue(columnKey, newValue, rowIndex) });
|
|
9068
9283
|
}
|
|
9069
9284
|
else if (widgetType === 'date') {
|
|
9070
|
-
return jsxRuntimeExports.jsx(TableCellDate, { config: cellConfig, value: cellValue, onValueChange: (newValue) => updateCellValue(columnKey, newValue, rowIndex) });
|
|
9285
|
+
return jsxRuntimeExports.jsx(TableCellDate, { config: cellConfig, value: cellValue, rowValues: rowValues, onValueChange: (newValue) => updateCellValue(columnKey, newValue, rowIndex) });
|
|
9071
9286
|
}
|
|
9072
9287
|
// For other widget types, use WidgetRenderer but with compact styling
|
|
9073
9288
|
return (jsxRuntimeExports.jsx("div", { className: "table-cell-widget", style: { margin: 0, padding: 0 }, children: jsxRuntimeExports.jsx(WidgetRenderer, { config: cellConfig, schemaData: {
|
|
@@ -9075,7 +9290,7 @@ const TableWidget = ({ config }) => {
|
|
|
9075
9290
|
}, onValueChange: (widgetId, newValue) => {
|
|
9076
9291
|
updateCellValue(columnKey, newValue, rowIndex);
|
|
9077
9292
|
} }) }));
|
|
9078
|
-
}, [widgetConfig, updateCellValue]);
|
|
9293
|
+
}, [widgetConfig, updateCellValue, getRowValuesForEdit]);
|
|
9079
9294
|
// Render cell content (widget in edit mode, formatted value in view mode)
|
|
9080
9295
|
const renderCell = React.useCallback((rowIndex, column, row) => {
|
|
9081
9296
|
const columnKey = column['column-key'];
|
|
@@ -9385,6 +9600,27 @@ const DialogTableWidget = ({ config }) => {
|
|
|
9385
9600
|
}, [formData, columns, storeValues, dialogFieldWidgetId]);
|
|
9386
9601
|
const saveDialog = React.useCallback(() => {
|
|
9387
9602
|
const payload = collectMergedRowPayload();
|
|
9603
|
+
let hasErrors = false;
|
|
9604
|
+
columns.forEach((col) => {
|
|
9605
|
+
const key = col['column-key'];
|
|
9606
|
+
const cellWidgetId = dialogFieldWidgetId(key);
|
|
9607
|
+
const isColReadonly = isReadonly || col['widget-readonly'] === true;
|
|
9608
|
+
if (isColReadonly)
|
|
9609
|
+
return;
|
|
9610
|
+
const cellValue = payload[key];
|
|
9611
|
+
const validationErrors = validateWidget(cellValue, col['widget-data-validation'], col['widget-required']);
|
|
9612
|
+
if (validationErrors && validationErrors.length > 0) {
|
|
9613
|
+
hasErrors = true;
|
|
9614
|
+
dispatch(setError({ widgetId: cellWidgetId, errors: validationErrors }));
|
|
9615
|
+
dispatch(setTouched({ widgetId: cellWidgetId, touched: true }));
|
|
9616
|
+
}
|
|
9617
|
+
else {
|
|
9618
|
+
dispatch(setError({ widgetId: cellWidgetId, errors: [] }));
|
|
9619
|
+
}
|
|
9620
|
+
});
|
|
9621
|
+
if (hasErrors) {
|
|
9622
|
+
return;
|
|
9623
|
+
}
|
|
9388
9624
|
if (dialogMode === 'add') {
|
|
9389
9625
|
const savedRow = { ...payload, edit_action: 'ADD' };
|
|
9390
9626
|
onChange([...rows, savedRow]);
|
|
@@ -9400,7 +9636,7 @@ const DialogTableWidget = ({ config }) => {
|
|
|
9400
9636
|
onChange(newRows);
|
|
9401
9637
|
closeDialog();
|
|
9402
9638
|
}
|
|
9403
|
-
}, [collectMergedRowPayload, dialogMode, onChange, rows, closeDialog, activeRowIndex]);
|
|
9639
|
+
}, [collectMergedRowPayload, dialogMode, onChange, rows, closeDialog, activeRowIndex, columns, dialogFieldWidgetId, isReadonly, dispatch]);
|
|
9404
9640
|
const deleteRow = React.useCallback((rowIndex) => {
|
|
9405
9641
|
const newRows = rows.filter((_, i) => i !== rowIndex);
|
|
9406
9642
|
onChange(newRows);
|
|
@@ -10226,20 +10462,29 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
10226
10462
|
.${cls} .hdr-field-row {
|
|
10227
10463
|
display: flex;
|
|
10228
10464
|
align-items: flex-start;
|
|
10229
|
-
gap: 0.5rem;
|
|
10230
10465
|
font-size: 1rem;
|
|
10231
10466
|
line-height: 1.6;
|
|
10232
10467
|
}
|
|
10233
10468
|
|
|
10234
10469
|
.${cls} .hdr-field-label {
|
|
10470
|
+
width: 50%;
|
|
10471
|
+
flex: 0 0 50%;
|
|
10235
10472
|
color: rgba(0, 0, 0, 0.5);
|
|
10236
10473
|
font-weight: 400;
|
|
10237
10474
|
white-space: nowrap;
|
|
10475
|
+
overflow: hidden;
|
|
10476
|
+
text-overflow: ellipsis;
|
|
10477
|
+
padding-right: 4px;
|
|
10238
10478
|
}
|
|
10239
10479
|
|
|
10240
10480
|
.${cls} .hdr-field-value {
|
|
10481
|
+
width: 50%;
|
|
10482
|
+
flex: 0 0 50%;
|
|
10241
10483
|
color: var(--owt-color-text, #111827);
|
|
10242
10484
|
font-weight: 500;
|
|
10485
|
+
white-space: nowrap;
|
|
10486
|
+
overflow: hidden;
|
|
10487
|
+
text-overflow: ellipsis;
|
|
10243
10488
|
}
|
|
10244
10489
|
|
|
10245
10490
|
.${cls} .hdr-status-badge {
|
|
@@ -10249,24 +10494,38 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
10249
10494
|
font-size: 0.75rem;
|
|
10250
10495
|
font-weight: 600;
|
|
10251
10496
|
color: #fff;
|
|
10497
|
+
max-width: 100%;
|
|
10498
|
+
overflow: hidden;
|
|
10499
|
+
text-overflow: ellipsis;
|
|
10500
|
+
white-space: nowrap;
|
|
10252
10501
|
}
|
|
10253
10502
|
|
|
10254
10503
|
.${cls} .hdr-meta-row {
|
|
10255
10504
|
display: flex;
|
|
10256
10505
|
align-items: baseline;
|
|
10257
|
-
gap: 0.35rem;
|
|
10258
10506
|
font-size: 1rem;
|
|
10259
10507
|
line-height: 1.6;
|
|
10260
10508
|
}
|
|
10261
10509
|
|
|
10262
10510
|
.${cls} .hdr-meta-label {
|
|
10511
|
+
width: 50%;
|
|
10512
|
+
flex: 0 0 50%;
|
|
10263
10513
|
color: rgba(0, 0, 0, 0.5);
|
|
10264
10514
|
font-weight: 400;
|
|
10515
|
+
white-space: nowrap;
|
|
10516
|
+
overflow: hidden;
|
|
10517
|
+
text-overflow: ellipsis;
|
|
10518
|
+
padding-right: 4px;
|
|
10265
10519
|
}
|
|
10266
10520
|
|
|
10267
10521
|
.${cls} .hdr-meta-value {
|
|
10522
|
+
width: 50%;
|
|
10523
|
+
flex: 0 0 50%;
|
|
10268
10524
|
color: var(--owt-color-text, #111827);
|
|
10269
10525
|
font-weight: 500;
|
|
10526
|
+
white-space: nowrap;
|
|
10527
|
+
overflow: hidden;
|
|
10528
|
+
text-overflow: ellipsis;
|
|
10270
10529
|
}
|
|
10271
10530
|
|
|
10272
10531
|
.${cls} .hdr-select {
|
|
@@ -10330,7 +10589,7 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
10330
10589
|
.parentElement?.querySelector('.hdr-avatar-placeholder');
|
|
10331
10590
|
if (placeholder)
|
|
10332
10591
|
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: () => {
|
|
10592
|
+
} })) : 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
10593
|
if (isReasonMissing)
|
|
10335
10594
|
setShowReasonRequired(true);
|
|
10336
10595
|
}, onChange: (e) => {
|
|
@@ -10338,7 +10597,7 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
10338
10597
|
if (showReasonRequired && String(e.target.value || '').trim().length > 0) {
|
|
10339
10598
|
setShowReasonRequired(false);
|
|
10340
10599
|
}
|
|
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] }) })] })] }));
|
|
10600
|
+
} }), !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
10601
|
};
|
|
10343
10602
|
|
|
10344
10603
|
function getValueByPathOrKey(obj, path) {
|