@openg2p/registry-widgets 1.1.0-dev.4 → 1.1.0-dev.5
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/SectionRenderer.d.ts.map +1 -1
- package/dist/components/SectionsContainer.d.ts.map +1 -1
- package/dist/index.esm.js +106 -23
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +106 -23
- package/dist/index.js.map +1 -1
- package/dist/utils/buildSectionChanges.d.ts.map +1 -1
- package/dist/utils/extractTableRecordsFromSnapshot.d.ts +11 -0
- package/dist/utils/extractTableRecordsFromSnapshot.d.ts.map +1 -0
- package/dist/widgets/DialogTableWidget.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3849,6 +3849,52 @@ const sectionValidate = (section, currentSchemaData, dispatch) => {
|
|
|
3849
3849
|
return isValid;
|
|
3850
3850
|
};
|
|
3851
3851
|
|
|
3852
|
+
/** Table-style widgets that bind to an array path in the store / schema. */
|
|
3853
|
+
function isTableLikeWidget(widget) {
|
|
3854
|
+
const w = widget.widget;
|
|
3855
|
+
/** widget-type union in types omits legacy values like simple-table still used at runtime */
|
|
3856
|
+
const t = widget['widget-type'];
|
|
3857
|
+
return (w === 'table' ||
|
|
3858
|
+
w === 'dialog-table' ||
|
|
3859
|
+
w === 'simple-table' ||
|
|
3860
|
+
t === 'table' ||
|
|
3861
|
+
t === 'simple-table');
|
|
3862
|
+
}
|
|
3863
|
+
/**
|
|
3864
|
+
* Resolve `records` for section save payloads.
|
|
3865
|
+
* - Back-compat: path ending in `.records` (e.g. `regId.records`)
|
|
3866
|
+
* - Else: first array snapshot at a string `widget-data-path` on a table-like widget
|
|
3867
|
+
* (e.g. `household.members` for dialog-table)
|
|
3868
|
+
*/
|
|
3869
|
+
function extractTableRecordsFromSnapshot(snapshot, sectionWidgets) {
|
|
3870
|
+
const convention = Object.entries(snapshot).find(([key, value]) => key.endsWith('.records') && Array.isArray(value));
|
|
3871
|
+
if (convention) {
|
|
3872
|
+
return convention[1];
|
|
3873
|
+
}
|
|
3874
|
+
const tablePaths = [];
|
|
3875
|
+
sectionWidgets.forEach((widget) => {
|
|
3876
|
+
if (!isTableLikeWidget(widget))
|
|
3877
|
+
return;
|
|
3878
|
+
const p = widget['widget-data-path'];
|
|
3879
|
+
if (typeof p === 'string' && p.length > 0) {
|
|
3880
|
+
tablePaths.push(p);
|
|
3881
|
+
}
|
|
3882
|
+
else if (p && typeof p === 'object') {
|
|
3883
|
+
Object.values(p).forEach((sub) => {
|
|
3884
|
+
if (typeof sub === 'string' && sub.length > 0)
|
|
3885
|
+
tablePaths.push(sub);
|
|
3886
|
+
});
|
|
3887
|
+
}
|
|
3888
|
+
});
|
|
3889
|
+
for (const path of tablePaths) {
|
|
3890
|
+
const val = snapshot[path];
|
|
3891
|
+
if (Array.isArray(val)) {
|
|
3892
|
+
return val;
|
|
3893
|
+
}
|
|
3894
|
+
}
|
|
3895
|
+
return [];
|
|
3896
|
+
}
|
|
3897
|
+
|
|
3852
3898
|
/** Root class on readonly label/value rows; SectionRenderer scopes overflow/ellipsis rules here. */
|
|
3853
3899
|
const READONLY_VALUE_ROW_ROOT_CLASSES = [
|
|
3854
3900
|
'TextDisplayWidget',
|
|
@@ -4214,9 +4260,7 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
|
|
|
4214
4260
|
const widgetPath = widget['widget-data-path'];
|
|
4215
4261
|
if (!widgetPath)
|
|
4216
4262
|
return;
|
|
4217
|
-
if (widget
|
|
4218
|
-
widget['widget-type'] === 'simple-table' ||
|
|
4219
|
-
widget['widget'] === 'table') {
|
|
4263
|
+
if (isTableLikeWidget(widget)) {
|
|
4220
4264
|
hasTable = true;
|
|
4221
4265
|
}
|
|
4222
4266
|
if (typeof widgetPath === 'object') {
|
|
@@ -4251,8 +4295,7 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
|
|
|
4251
4295
|
},
|
|
4252
4296
|
];
|
|
4253
4297
|
}
|
|
4254
|
-
|
|
4255
|
-
return tableEntry ? tableEntry[1] : [];
|
|
4298
|
+
return extractTableRecordsFromSnapshot(snapshot, widgets);
|
|
4256
4299
|
};
|
|
4257
4300
|
// Get original section (without namespace) for building snapshots
|
|
4258
4301
|
// This ensures we use the original data paths when saving
|
|
@@ -4962,10 +5005,7 @@ function buildSectionChanges(section, storeValues, namespace, options) {
|
|
|
4962
5005
|
const widgetPath = widget['widget-data-path'];
|
|
4963
5006
|
if (!widgetPath)
|
|
4964
5007
|
return;
|
|
4965
|
-
|
|
4966
|
-
if (widgetType === 'table' ||
|
|
4967
|
-
widgetType === 'simple-table' ||
|
|
4968
|
-
widget.widget === 'table') {
|
|
5008
|
+
if (isTableLikeWidget(widget)) {
|
|
4969
5009
|
hasTable = true;
|
|
4970
5010
|
}
|
|
4971
5011
|
if (typeof widgetPath === 'object') {
|
|
@@ -5003,8 +5043,7 @@ function buildSectionChanges(section, storeValues, namespace, options) {
|
|
|
5003
5043
|
];
|
|
5004
5044
|
}
|
|
5005
5045
|
else {
|
|
5006
|
-
|
|
5007
|
-
records = tableEntry ? tableEntry[1] : [];
|
|
5046
|
+
records = extractTableRecordsFromSnapshot(snapshot, sectionWidgets);
|
|
5008
5047
|
}
|
|
5009
5048
|
const files = [];
|
|
5010
5049
|
const supportingDocs = section['section-supporting-documents'] || [];
|
|
@@ -5030,7 +5069,9 @@ const hasTableWidget = (panels) => {
|
|
|
5030
5069
|
// Check widgets in this panel
|
|
5031
5070
|
if (panel.widgets) {
|
|
5032
5071
|
for (const widget of panel.widgets) {
|
|
5033
|
-
if (widget.widget === 'table' ||
|
|
5072
|
+
if (widget.widget === 'table' ||
|
|
5073
|
+
widget.widget === 'dialog-table' ||
|
|
5074
|
+
widget['widget-type'] === 'table') {
|
|
5034
5075
|
return true;
|
|
5035
5076
|
}
|
|
5036
5077
|
}
|
|
@@ -5052,7 +5093,9 @@ const getTableWidgetColumnSpan = (panels) => {
|
|
|
5052
5093
|
// Check widgets in this panel
|
|
5053
5094
|
if (panel.widgets) {
|
|
5054
5095
|
for (const widget of panel.widgets) {
|
|
5055
|
-
if (widget.widget === 'table' ||
|
|
5096
|
+
if (widget.widget === 'table' ||
|
|
5097
|
+
widget.widget === 'dialog-table' ||
|
|
5098
|
+
widget['widget-type'] === 'table') {
|
|
5056
5099
|
// Return the widget's column span if specified, otherwise null
|
|
5057
5100
|
return widget['widget-column-span'] || null;
|
|
5058
5101
|
}
|
|
@@ -9189,6 +9232,8 @@ const SelectDisplayValue = ({ config, value }) => {
|
|
|
9189
9232
|
const DialogTableWidget = ({ config }) => {
|
|
9190
9233
|
const { value, error, touched, isEnabled, onChange, config: widgetConfig } = useBaseWidget({ config });
|
|
9191
9234
|
const { translate, translateConfig } = useWidgetTranslation();
|
|
9235
|
+
const dispatch = reactRedux.useDispatch();
|
|
9236
|
+
const storeValues = reactRedux.useSelector((state) => state.widget?.values ?? {});
|
|
9192
9237
|
const rows = Array.isArray(value) ? value : [];
|
|
9193
9238
|
const columns = widgetConfig['widget-data-columns'] || [];
|
|
9194
9239
|
const operations = widgetConfig['widget-data-operations'] || {};
|
|
@@ -9207,6 +9252,9 @@ const DialogTableWidget = ({ config }) => {
|
|
|
9207
9252
|
const [dialogMode, setDialogMode] = React.useState('add');
|
|
9208
9253
|
const [activeRowIndex, setActiveRowIndex] = React.useState(null);
|
|
9209
9254
|
const [formData, setFormData] = React.useState({});
|
|
9255
|
+
/** Unique per dialog open so Redux widget ids don't reuse stale values across rows/add sessions */
|
|
9256
|
+
const dialogSessionRef = React.useRef(0);
|
|
9257
|
+
const [dialogSessionId, setDialogSessionId] = React.useState(0);
|
|
9210
9258
|
const addDialogTitle = translateConfig(widgetConfig['widget-data-dialog-title-add']) ||
|
|
9211
9259
|
translate('table.addRecordDialog') ||
|
|
9212
9260
|
'Add record';
|
|
@@ -9221,13 +9269,32 @@ const DialogTableWidget = ({ config }) => {
|
|
|
9221
9269
|
});
|
|
9222
9270
|
return emptyRow;
|
|
9223
9271
|
}, [columns]);
|
|
9272
|
+
const dialogFieldWidgetId = React.useCallback((columnKey) => `${widgetConfig['widget-id']}-dlg-${dialogSessionId}-${columnKey}`, [widgetConfig, dialogSessionId]);
|
|
9273
|
+
const resetDialogWidgets = React.useCallback((sessionId) => {
|
|
9274
|
+
if (sessionId <= 0)
|
|
9275
|
+
return;
|
|
9276
|
+
columns.forEach((col) => {
|
|
9277
|
+
const wid = `${widgetConfig['widget-id']}-dlg-${sessionId}-${col['column-key']}`;
|
|
9278
|
+
dispatch(resetWidget(wid));
|
|
9279
|
+
});
|
|
9280
|
+
}, [columns, widgetConfig, dispatch]);
|
|
9281
|
+
const beginDialogSession = React.useCallback(() => {
|
|
9282
|
+
dialogSessionRef.current += 1;
|
|
9283
|
+
const nextSession = dialogSessionRef.current;
|
|
9284
|
+
setDialogSessionId(nextSession);
|
|
9285
|
+
return nextSession;
|
|
9286
|
+
}, []);
|
|
9224
9287
|
const openAddDialog = React.useCallback(() => {
|
|
9288
|
+
resetDialogWidgets(dialogSessionId);
|
|
9289
|
+
beginDialogSession();
|
|
9225
9290
|
setDialogMode('add');
|
|
9226
9291
|
setActiveRowIndex(null);
|
|
9227
9292
|
setFormData(buildEmptyRow());
|
|
9228
9293
|
setDialogOpen(true);
|
|
9229
|
-
}, [buildEmptyRow]);
|
|
9294
|
+
}, [buildEmptyRow, beginDialogSession, resetDialogWidgets, dialogSessionId]);
|
|
9230
9295
|
const openEditDialog = React.useCallback((rowIndex) => {
|
|
9296
|
+
resetDialogWidgets(dialogSessionId);
|
|
9297
|
+
beginDialogSession();
|
|
9231
9298
|
const row = rows[rowIndex] || {};
|
|
9232
9299
|
const nextFormData = buildEmptyRow();
|
|
9233
9300
|
columns.forEach((col) => {
|
|
@@ -9239,18 +9306,33 @@ const DialogTableWidget = ({ config }) => {
|
|
|
9239
9306
|
setActiveRowIndex(rowIndex);
|
|
9240
9307
|
setFormData(nextFormData);
|
|
9241
9308
|
setDialogOpen(true);
|
|
9242
|
-
}, [rows, columns, buildEmptyRow]);
|
|
9309
|
+
}, [rows, columns, buildEmptyRow, resetDialogWidgets, dialogSessionId, beginDialogSession]);
|
|
9243
9310
|
const closeDialog = React.useCallback(() => {
|
|
9311
|
+
const sessionToClear = dialogSessionId;
|
|
9244
9312
|
setDialogOpen(false);
|
|
9245
9313
|
setActiveRowIndex(null);
|
|
9246
9314
|
setFormData({});
|
|
9247
|
-
|
|
9315
|
+
resetDialogWidgets(sessionToClear);
|
|
9316
|
+
setDialogSessionId(0);
|
|
9317
|
+
}, [dialogSessionId, resetDialogWidgets]);
|
|
9248
9318
|
const updateField = React.useCallback((columnKey, newValue) => {
|
|
9249
9319
|
setFormData((prev) => ({ ...prev, [columnKey]: newValue }));
|
|
9250
9320
|
}, []);
|
|
9321
|
+
const collectMergedRowPayload = React.useCallback(() => {
|
|
9322
|
+
const merged = { ...formData };
|
|
9323
|
+
columns.forEach((col) => {
|
|
9324
|
+
const k = col['column-key'];
|
|
9325
|
+
const wid = dialogFieldWidgetId(k);
|
|
9326
|
+
const fromStore = storeValues[wid];
|
|
9327
|
+
if (fromStore !== undefined)
|
|
9328
|
+
merged[k] = fromStore;
|
|
9329
|
+
});
|
|
9330
|
+
return merged;
|
|
9331
|
+
}, [formData, columns, storeValues, dialogFieldWidgetId]);
|
|
9251
9332
|
const saveDialog = React.useCallback(() => {
|
|
9333
|
+
const payload = collectMergedRowPayload();
|
|
9252
9334
|
if (dialogMode === 'add') {
|
|
9253
|
-
const savedRow = { ...
|
|
9335
|
+
const savedRow = { ...payload, edit_action: 'ADD' };
|
|
9254
9336
|
onChange([...rows, savedRow]);
|
|
9255
9337
|
closeDialog();
|
|
9256
9338
|
return;
|
|
@@ -9260,11 +9342,11 @@ const DialogTableWidget = ({ config }) => {
|
|
|
9260
9342
|
const currentRow = newRows[activeRowIndex] || {};
|
|
9261
9343
|
const wasDeleted = currentRow.edit_action === 'DELETE';
|
|
9262
9344
|
const editAction = wasDeleted ? 'UPDATE' : (currentRow.edit_action ?? 'UPDATE');
|
|
9263
|
-
newRows[activeRowIndex] = { ...currentRow, ...
|
|
9345
|
+
newRows[activeRowIndex] = { ...currentRow, ...payload, edit_action: editAction };
|
|
9264
9346
|
onChange(newRows);
|
|
9265
9347
|
closeDialog();
|
|
9266
9348
|
}
|
|
9267
|
-
}, [
|
|
9349
|
+
}, [collectMergedRowPayload, dialogMode, onChange, rows, closeDialog, activeRowIndex]);
|
|
9268
9350
|
const deleteRow = React.useCallback((rowIndex) => {
|
|
9269
9351
|
const newRows = rows.filter((_, i) => i !== rowIndex);
|
|
9270
9352
|
onChange(newRows);
|
|
@@ -9352,7 +9434,8 @@ const DialogTableWidget = ({ config }) => {
|
|
|
9352
9434
|
}, "aria-label": "Close", children: "\u00D7" })] }), jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", style: { maxHeight: '70vh', overflow: 'auto' }, children: columns.map((col) => {
|
|
9353
9435
|
const key = col['column-key'];
|
|
9354
9436
|
const widgetType = col.widget || 'text';
|
|
9355
|
-
const cellWidgetId =
|
|
9437
|
+
const cellWidgetId = dialogFieldWidgetId(key);
|
|
9438
|
+
const initialValue = formData[key] ?? col['widget-data-default'] ?? '';
|
|
9356
9439
|
const fieldConfig = {
|
|
9357
9440
|
...col,
|
|
9358
9441
|
widget: widgetType,
|
|
@@ -9361,10 +9444,10 @@ const DialogTableWidget = ({ config }) => {
|
|
|
9361
9444
|
'widget-label': col['widget-label'],
|
|
9362
9445
|
'widget-readonly': isReadonly || col['widget-readonly'] === true,
|
|
9363
9446
|
'widget-data-path': undefined,
|
|
9364
|
-
'widget-data-default':
|
|
9447
|
+
'widget-data-default': initialValue,
|
|
9365
9448
|
};
|
|
9366
|
-
return (jsxRuntimeExports.jsx("div", { className: "min-w-0", children: jsxRuntimeExports.jsx(WidgetRenderer, { config: fieldConfig, schemaData: { [cellWidgetId]:
|
|
9367
|
-
}) }), jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-3 mt-6", children: [jsxRuntimeExports.jsx("button", { type: "button", onClick: closeDialog, className: "px-4 py-2 text-sm font-medium", style: {
|
|
9449
|
+
return (jsxRuntimeExports.jsx("div", { className: "min-w-0", children: jsxRuntimeExports.jsx(WidgetRenderer, { config: fieldConfig, schemaData: { [cellWidgetId]: initialValue }, onValueChange: (_widgetId, newValue) => updateField(key, newValue) }) }, `${dialogSessionId}-${key}`));
|
|
9450
|
+
}) }, `dialog-fields-${dialogSessionId}`), jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-3 mt-6", children: [jsxRuntimeExports.jsx("button", { type: "button", onClick: closeDialog, className: "px-4 py-2 text-sm font-medium", style: {
|
|
9368
9451
|
borderRadius: 'var(--owt-btn-border-radius, 10px)',
|
|
9369
9452
|
border: '1px solid var(--owt-btn-secondary-border, #C4C4C4)',
|
|
9370
9453
|
backgroundColor: 'var(--owt-btn-secondary-bg, #FFFFFF)',
|