@openg2p/registry-widgets 1.1.0-dev.2 → 1.1.0-dev.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +24 -1
- package/dist/index.esm.js +441 -104
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +441 -103
- package/dist/index.js.map +1 -1
- package/dist/registry/defaultWidgets.d.ts.map +1 -1
- package/dist/widgets/DialogTableWidget.d.ts +25 -0
- package/dist/widgets/DialogTableWidget.d.ts.map +1 -0
- package/dist/widgets/HeaderSectionWidget.d.ts.map +1 -1
- package/dist/widgets/IdAuthenticationWidget.d.ts.map +1 -1
- package/dist/widgets/index.d.ts +1 -0
- package/dist/widgets/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8525,7 +8525,7 @@ const TableCellSelect = ({ config, value, onValueChange }) => {
|
|
|
8525
8525
|
backgroundColor: isReadonly || loading ? 'var(--owt-color-bg-alt, #F6F6F6)' : 'var(--owt-color-bg, #FFFFFF)',
|
|
8526
8526
|
}, children: [jsxRuntimeExports.jsx("option", { value: "", children: translate('common.select') || 'Select' }), dataSourceOptions.map((option) => (jsxRuntimeExports.jsx("option", { value: option.value, children: option.label }, option.value)))] }));
|
|
8527
8527
|
};
|
|
8528
|
-
const SelectDisplayValue = ({ config, value }) => {
|
|
8528
|
+
const SelectDisplayValue$1 = ({ config, value }) => {
|
|
8529
8529
|
const { dataSourceOptions, loading } = useBaseWidget({ config });
|
|
8530
8530
|
if (loading) {
|
|
8531
8531
|
return jsxRuntimeExports.jsx("span", { children: "-" });
|
|
@@ -9019,7 +9019,7 @@ const TableWidget = ({ config }) => {
|
|
|
9019
9019
|
'widget-readonly': true,
|
|
9020
9020
|
'widget-data-path': undefined,
|
|
9021
9021
|
};
|
|
9022
|
-
return (jsxRuntimeExports.jsx("div", { className: "text-sm", style: getCellStyle(), children: jsxRuntimeExports.jsx(SelectDisplayValue, { config: cellConfig, value: cellValue }) }));
|
|
9022
|
+
return (jsxRuntimeExports.jsx("div", { className: "text-sm", style: getCellStyle(), children: jsxRuntimeExports.jsx(SelectDisplayValue$1, { config: cellConfig, value: cellValue }) }));
|
|
9023
9023
|
}
|
|
9024
9024
|
return (jsxRuntimeExports.jsx("div", { className: "text-sm", style: getCellStyle(), children: displayValue }));
|
|
9025
9025
|
}
|
|
@@ -9158,6 +9158,225 @@ const TableWidget = ({ config }) => {
|
|
|
9158
9158
|
}, children: translate('common.cancel') || 'Cancel' })] }) })] }))] })] }) }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-sm mt-1", style: { color: 'var(--owt-widget-error-color, #B91C1C)' }, children: error[0] }))] })] }));
|
|
9159
9159
|
};
|
|
9160
9160
|
|
|
9161
|
+
// Display select value label in view mode
|
|
9162
|
+
const SelectDisplayValue = ({ config, value }) => {
|
|
9163
|
+
const { dataSourceOptions, loading } = useBaseWidget({ config });
|
|
9164
|
+
if (loading)
|
|
9165
|
+
return jsxRuntimeExports.jsx("span", { children: "-" });
|
|
9166
|
+
if (value === null || value === undefined || value === '')
|
|
9167
|
+
return jsxRuntimeExports.jsx("span", { children: "-" });
|
|
9168
|
+
const selectedOption = dataSourceOptions.find((option) => option.value === value);
|
|
9169
|
+
return jsxRuntimeExports.jsx("span", { children: selectedOption ? selectedOption.label : String(value) });
|
|
9170
|
+
};
|
|
9171
|
+
/**
|
|
9172
|
+
* Dialog table widget:
|
|
9173
|
+
* - Table displays a subset of columns (n out of x)
|
|
9174
|
+
* - Add/Edit happens in a modal dialog that shows ALL columns as a form
|
|
9175
|
+
*
|
|
9176
|
+
* Usage in schema:
|
|
9177
|
+
* {
|
|
9178
|
+
* "widget": "dialog-table",
|
|
9179
|
+
* "widget-type": "table",
|
|
9180
|
+
* "widget-label": "Household Members",
|
|
9181
|
+
* "widget-id": "householdMembers",
|
|
9182
|
+
* "widget-data-path": "household.members",
|
|
9183
|
+
* "widget-data-columns": [ ...all columns... ],
|
|
9184
|
+
* "widget-data-visible-columns": ["firstName", "lastName", "dob"], // optional override; default = by column flag
|
|
9185
|
+
* // Per-column control (recommended): set "column-visible-in-table": false to hide it in the table
|
|
9186
|
+
* "widget-data-operations": { "add": true, "edit": true, "remove": true }
|
|
9187
|
+
* }
|
|
9188
|
+
*/
|
|
9189
|
+
const DialogTableWidget = ({ config }) => {
|
|
9190
|
+
const { value, error, touched, isEnabled, onChange, config: widgetConfig } = useBaseWidget({ config });
|
|
9191
|
+
const { translate, translateConfig } = useWidgetTranslation();
|
|
9192
|
+
const rows = Array.isArray(value) ? value : [];
|
|
9193
|
+
const columns = widgetConfig['widget-data-columns'] || [];
|
|
9194
|
+
const operations = widgetConfig['widget-data-operations'] || {};
|
|
9195
|
+
const isReadonly = widgetConfig['widget-readonly'] || false;
|
|
9196
|
+
const visibleColumnKeys = widgetConfig['widget-data-visible-columns'];
|
|
9197
|
+
const visibleColumns = React.useMemo(() => {
|
|
9198
|
+
// 1) If explicit list provided, it wins
|
|
9199
|
+
if (Array.isArray(visibleColumnKeys) && visibleColumnKeys.length > 0) {
|
|
9200
|
+
const keySet = new Set(visibleColumnKeys);
|
|
9201
|
+
return columns.filter((c) => keySet.has(c['column-key']));
|
|
9202
|
+
}
|
|
9203
|
+
// 2) Otherwise decide per column (default = visible)
|
|
9204
|
+
return columns.filter((c) => c['column-visible-in-table'] !== false);
|
|
9205
|
+
}, [columns, visibleColumnKeys]);
|
|
9206
|
+
const [dialogOpen, setDialogOpen] = React.useState(false);
|
|
9207
|
+
const [dialogMode, setDialogMode] = React.useState('add');
|
|
9208
|
+
const [activeRowIndex, setActiveRowIndex] = React.useState(null);
|
|
9209
|
+
const [formData, setFormData] = React.useState({});
|
|
9210
|
+
const addDialogTitle = translateConfig(widgetConfig['widget-data-dialog-title-add']) ||
|
|
9211
|
+
translate('table.addRecordDialog') ||
|
|
9212
|
+
'Add record';
|
|
9213
|
+
const editDialogTitle = translateConfig(widgetConfig['widget-data-dialog-title-edit']) ||
|
|
9214
|
+
translate('table.editRecordDialog') ||
|
|
9215
|
+
'Edit record';
|
|
9216
|
+
const buildEmptyRow = React.useCallback(() => {
|
|
9217
|
+
const emptyRow = {};
|
|
9218
|
+
columns.forEach((col) => {
|
|
9219
|
+
const key = col['column-key'];
|
|
9220
|
+
emptyRow[key] = col['widget-data-default'] ?? '';
|
|
9221
|
+
});
|
|
9222
|
+
return emptyRow;
|
|
9223
|
+
}, [columns]);
|
|
9224
|
+
const openAddDialog = React.useCallback(() => {
|
|
9225
|
+
setDialogMode('add');
|
|
9226
|
+
setActiveRowIndex(null);
|
|
9227
|
+
setFormData(buildEmptyRow());
|
|
9228
|
+
setDialogOpen(true);
|
|
9229
|
+
}, [buildEmptyRow]);
|
|
9230
|
+
const openEditDialog = React.useCallback((rowIndex) => {
|
|
9231
|
+
const row = rows[rowIndex] || {};
|
|
9232
|
+
const nextFormData = buildEmptyRow();
|
|
9233
|
+
columns.forEach((col) => {
|
|
9234
|
+
const key = col['column-key'];
|
|
9235
|
+
if (row[key] !== undefined)
|
|
9236
|
+
nextFormData[key] = row[key];
|
|
9237
|
+
});
|
|
9238
|
+
setDialogMode('edit');
|
|
9239
|
+
setActiveRowIndex(rowIndex);
|
|
9240
|
+
setFormData(nextFormData);
|
|
9241
|
+
setDialogOpen(true);
|
|
9242
|
+
}, [rows, columns, buildEmptyRow]);
|
|
9243
|
+
const closeDialog = React.useCallback(() => {
|
|
9244
|
+
setDialogOpen(false);
|
|
9245
|
+
setActiveRowIndex(null);
|
|
9246
|
+
setFormData({});
|
|
9247
|
+
}, []);
|
|
9248
|
+
const updateField = React.useCallback((columnKey, newValue) => {
|
|
9249
|
+
setFormData((prev) => ({ ...prev, [columnKey]: newValue }));
|
|
9250
|
+
}, []);
|
|
9251
|
+
const saveDialog = React.useCallback(() => {
|
|
9252
|
+
if (dialogMode === 'add') {
|
|
9253
|
+
const savedRow = { ...formData, edit_action: 'ADD' };
|
|
9254
|
+
onChange([...rows, savedRow]);
|
|
9255
|
+
closeDialog();
|
|
9256
|
+
return;
|
|
9257
|
+
}
|
|
9258
|
+
if (dialogMode === 'edit' && activeRowIndex !== null) {
|
|
9259
|
+
const newRows = [...rows];
|
|
9260
|
+
const currentRow = newRows[activeRowIndex] || {};
|
|
9261
|
+
const wasDeleted = currentRow.edit_action === 'DELETE';
|
|
9262
|
+
const editAction = wasDeleted ? 'UPDATE' : (currentRow.edit_action ?? 'UPDATE');
|
|
9263
|
+
newRows[activeRowIndex] = { ...currentRow, ...formData, edit_action: editAction };
|
|
9264
|
+
onChange(newRows);
|
|
9265
|
+
closeDialog();
|
|
9266
|
+
}
|
|
9267
|
+
}, [dialogMode, formData, onChange, rows, closeDialog, activeRowIndex]);
|
|
9268
|
+
const deleteRow = React.useCallback((rowIndex) => {
|
|
9269
|
+
const newRows = rows.filter((_, i) => i !== rowIndex);
|
|
9270
|
+
onChange(newRows);
|
|
9271
|
+
}, [rows, onChange]);
|
|
9272
|
+
const getDisplayValue = React.useCallback((rowIndex, column) => {
|
|
9273
|
+
const key = column['column-key'];
|
|
9274
|
+
const cellValue = rows[rowIndex]?.[key];
|
|
9275
|
+
const widgetType = column.widget || 'text';
|
|
9276
|
+
if (cellValue === null || cellValue === undefined || cellValue === '')
|
|
9277
|
+
return '-';
|
|
9278
|
+
if (widgetType === 'select')
|
|
9279
|
+
return null; // handled by SelectDisplayValue
|
|
9280
|
+
if (column['widget-data-format'])
|
|
9281
|
+
return formatValue(cellValue, column['widget-data-format'], column.widget);
|
|
9282
|
+
return String(cellValue);
|
|
9283
|
+
}, [rows]);
|
|
9284
|
+
const tableWidgetId = `dialog-table-widget-${widgetConfig['widget-id']}`;
|
|
9285
|
+
const columnSpan = widgetConfig['widget-column-span'] || 2;
|
|
9286
|
+
const minWidth = columnSpan * 200;
|
|
9287
|
+
return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("style", { children: `
|
|
9288
|
+
.${tableWidgetId} {
|
|
9289
|
+
width: 100%;
|
|
9290
|
+
min-width: ${minWidth}px;
|
|
9291
|
+
}
|
|
9292
|
+
|
|
9293
|
+
.widget-container[data-widget-id="${widgetConfig['widget-id']}"] {
|
|
9294
|
+
min-width: ${minWidth}px;
|
|
9295
|
+
width: 100%;
|
|
9296
|
+
flex: none;
|
|
9297
|
+
}
|
|
9298
|
+
|
|
9299
|
+
.panel-horizontal .widget-container[data-widget-id="${widgetConfig['widget-id']}"],
|
|
9300
|
+
[data-panel-orientation="horizontal"] .widget-container[data-widget-id="${widgetConfig['widget-id']}"] {
|
|
9301
|
+
grid-column: span ${columnSpan};
|
|
9302
|
+
}
|
|
9303
|
+
` }), jsxRuntimeExports.jsxs("div", { className: `table-widget-container ${tableWidgetId}`, children: [operations.add && !isReadonly && isEnabled && (jsxRuntimeExports.jsx("div", { className: "flex justify-end mb-2", children: jsxRuntimeExports.jsx("button", { type: "button", onClick: openAddDialog, className: "px-3 py-1 text-sm disabled:opacity-50 disabled:cursor-not-allowed", style: {
|
|
9304
|
+
borderRadius: 'var(--owt-btn-border-radius, 10px)',
|
|
9305
|
+
border: '1px solid var(--owt-btn-primary-border, #F07B1A)',
|
|
9306
|
+
backgroundColor: 'var(--owt-color-primary, #F5BB1A)',
|
|
9307
|
+
color: 'var(--owt-color-bg, #FFFFFF)',
|
|
9308
|
+
}, children: translate('table.addRecord') || 'Add New Record' }) })), jsxRuntimeExports.jsx("div", { className: "overflow-x-auto border", style: {
|
|
9309
|
+
borderRadius: 'var(--owt-widget-table-border-radius, 15px)',
|
|
9310
|
+
borderColor: 'var(--owt-widget-table-border-color, #C4C4C4)',
|
|
9311
|
+
}, children: jsxRuntimeExports.jsxs("table", { className: "min-w-full", style: { borderCollapse: 'separate', borderSpacing: 0 }, children: [jsxRuntimeExports.jsx("thead", { style: { backgroundColor: 'var(--owt-widget-table-header-bg, #F6F6F6)' }, children: jsxRuntimeExports.jsxs("tr", { style: { borderBottom: '1px solid var(--owt-widget-table-row-divider, #E4E4E4)' }, children: [visibleColumns.map((col) => (jsxRuntimeExports.jsx("th", { className: "px-4 py-3 text-left text-xs font-medium uppercase tracking-wider", style: { color: 'var(--owt-widget-table-header-color, #727474)' }, children: translateConfig(col['widget-label']) }, col['column-key']))), ((operations.edit || operations.remove) && !isReadonly) && (jsxRuntimeExports.jsx("th", { className: "px-4 py-3 text-left text-xs font-medium uppercase tracking-wider", style: { color: 'var(--owt-widget-table-header-color, #727474)' }, children: translate('common.actions') || 'Actions' }))] }) }), jsxRuntimeExports.jsxs("tbody", { style: { backgroundColor: 'var(--owt-widget-table-body-bg, #FFFFFF)' }, children: [rows.length === 0 && (jsxRuntimeExports.jsx("tr", { children: jsxRuntimeExports.jsxs("td", { colSpan: visibleColumns.length + (((operations.edit || operations.remove) && !isReadonly) ? 1 : 0), className: "px-4 py-6 text-center text-sm", style: { color: 'var(--owt-widget-table-empty-color, #727474)' }, children: [translate('table.noData') || 'No records available.', operations.add && !isReadonly && ` ${translate('table.clickToAdd') || 'Click "Add New Record" to add one.'}`] }) })), rows.map((row, rowIndex) => (jsxRuntimeExports.jsxs("tr", { style: {
|
|
9312
|
+
borderBottom: '1px solid var(--owt-widget-table-row-divider, #E4E4E4)',
|
|
9313
|
+
backgroundColor: row?.edit_action === 'DELETE'
|
|
9314
|
+
? 'var(--owt-widget-table-deleted-row-bg, #FEE2E2)'
|
|
9315
|
+
: undefined,
|
|
9316
|
+
}, children: [visibleColumns.map((col) => {
|
|
9317
|
+
const key = col['column-key'];
|
|
9318
|
+
const widgetType = col.widget || 'text';
|
|
9319
|
+
const displayValue = getDisplayValue(rowIndex, col);
|
|
9320
|
+
if (widgetType === 'select' && displayValue === null) {
|
|
9321
|
+
const displayConfig = {
|
|
9322
|
+
...col,
|
|
9323
|
+
'widget-id': `${widgetConfig['widget-id']}-view-row-${rowIndex}-col-${key}`,
|
|
9324
|
+
'widget-label': '',
|
|
9325
|
+
'widget-readonly': true,
|
|
9326
|
+
'widget-data-path': undefined,
|
|
9327
|
+
};
|
|
9328
|
+
return (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: jsxRuntimeExports.jsx("div", { className: "text-sm", children: jsxRuntimeExports.jsx(SelectDisplayValue, { config: displayConfig, value: row?.[key] }) }) }, key));
|
|
9329
|
+
}
|
|
9330
|
+
return (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: jsxRuntimeExports.jsx("div", { className: "text-sm", children: displayValue }) }, key));
|
|
9331
|
+
}), ((operations.edit || operations.remove) && !isReadonly) && (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", style: { minWidth: '120px' }, children: jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [operations.edit && (jsxRuntimeExports.jsx("button", { type: "button", onClick: () => openEditDialog(rowIndex), disabled: !isEnabled, className: "px-3 py-1 text-xs disabled:opacity-50 disabled:cursor-not-allowed", style: {
|
|
9332
|
+
borderRadius: 'var(--owt-btn-border-radius, 10px)',
|
|
9333
|
+
color: 'var(--owt-color-primary-dark, #F07B1A)',
|
|
9334
|
+
backgroundColor: 'transparent',
|
|
9335
|
+
border: 'none',
|
|
9336
|
+
}, children: translate('common.edit') || 'Edit' })), operations.remove && (jsxRuntimeExports.jsx("button", { type: "button", onClick: () => deleteRow(rowIndex), disabled: !isEnabled, className: "px-3 py-1 text-xs disabled:opacity-50 disabled:cursor-not-allowed", style: {
|
|
9337
|
+
borderRadius: 'var(--owt-btn-border-radius, 10px)',
|
|
9338
|
+
color: 'var(--owt-color-error, #B91C1C)',
|
|
9339
|
+
backgroundColor: 'transparent',
|
|
9340
|
+
border: 'none',
|
|
9341
|
+
}, children: translate('common.remove') || 'Delete' }))] }) }))] }, rowIndex)))] })] }) }), touched && error.length > 0 && (jsxRuntimeExports.jsx("p", { className: "text-sm mt-1", style: { color: 'var(--owt-widget-error-color, #B91C1C)' }, children: error[0] }))] }), dialogOpen && (jsxRuntimeExports.jsx("div", { className: "fixed inset-0 flex items-center justify-center z-50", style: { backgroundColor: 'rgba(0,0,0,0.5)' }, children: jsxRuntimeExports.jsxs("div", { className: "rounded-lg p-6 w-full mx-4", style: {
|
|
9342
|
+
maxWidth: '900px',
|
|
9343
|
+
backgroundColor: 'var(--owt-color-bg, #FFFFFF)',
|
|
9344
|
+
borderRadius: 'var(--owt-widget-card-border-radius, 20px)',
|
|
9345
|
+
}, children: [jsxRuntimeExports.jsxs("div", { className: "flex items-start justify-between gap-4 mb-4", children: [jsxRuntimeExports.jsx("h3", { className: "text-lg font-semibold", style: { color: 'var(--owt-color-text, #011627)' }, children: dialogMode === 'add' ? addDialogTitle : editDialogTitle }), jsxRuntimeExports.jsx("button", { type: "button", onClick: closeDialog, style: {
|
|
9346
|
+
border: 'none',
|
|
9347
|
+
background: 'transparent',
|
|
9348
|
+
color: 'var(--owt-color-text-muted, #727474)',
|
|
9349
|
+
cursor: 'pointer',
|
|
9350
|
+
fontSize: '20px',
|
|
9351
|
+
lineHeight: 1,
|
|
9352
|
+
}, "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
|
+
const key = col['column-key'];
|
|
9354
|
+
const widgetType = col.widget || 'text';
|
|
9355
|
+
const cellWidgetId = `${widgetConfig['widget-id']}-dialog-${dialogMode}-${key}`;
|
|
9356
|
+
const fieldConfig = {
|
|
9357
|
+
...col,
|
|
9358
|
+
widget: widgetType,
|
|
9359
|
+
'widget-type': col['widget-type'] || 'input',
|
|
9360
|
+
'widget-id': cellWidgetId,
|
|
9361
|
+
'widget-label': col['widget-label'],
|
|
9362
|
+
'widget-readonly': isReadonly || col['widget-readonly'] === true,
|
|
9363
|
+
'widget-data-path': undefined,
|
|
9364
|
+
'widget-data-default': formData[key] ?? col['widget-data-default'] ?? '',
|
|
9365
|
+
};
|
|
9366
|
+
return (jsxRuntimeExports.jsx("div", { className: "min-w-0", children: jsxRuntimeExports.jsx(WidgetRenderer, { config: fieldConfig, schemaData: { [cellWidgetId]: formData[key] ?? col['widget-data-default'] ?? '' }, onValueChange: (_widgetId, newValue) => updateField(key, newValue) }) }, key));
|
|
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: {
|
|
9368
|
+
borderRadius: 'var(--owt-btn-border-radius, 10px)',
|
|
9369
|
+
border: '1px solid var(--owt-btn-secondary-border, #C4C4C4)',
|
|
9370
|
+
backgroundColor: 'var(--owt-btn-secondary-bg, #FFFFFF)',
|
|
9371
|
+
color: 'var(--owt-btn-secondary-color, #011627)',
|
|
9372
|
+
}, children: translate('common.cancel') || 'Cancel' }), jsxRuntimeExports.jsx("button", { type: "button", onClick: saveDialog, disabled: isReadonly || !isEnabled, className: "px-4 py-2 text-sm font-medium disabled:opacity-50 disabled:cursor-not-allowed", style: {
|
|
9373
|
+
borderRadius: 'var(--owt-btn-border-radius, 10px)',
|
|
9374
|
+
border: '1px solid var(--owt-btn-primary-border, #F07B1A)',
|
|
9375
|
+
backgroundColor: 'var(--owt-color-primary, #F5BB1A)',
|
|
9376
|
+
color: 'var(--owt-color-bg, #FFFFFF)',
|
|
9377
|
+
}, children: translate('common.save') || 'Save' })] })] }) }))] }));
|
|
9378
|
+
};
|
|
9379
|
+
|
|
9161
9380
|
const ProfileWidget = ({ config }) => {
|
|
9162
9381
|
const { value, config: widgetConfig, getFieldValue, } = useBaseWidget({ config });
|
|
9163
9382
|
const { translateConfig } = useWidgetTranslation();
|
|
@@ -9571,6 +9790,68 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
9571
9790
|
const createdAt = findValue('createdAt') || '';
|
|
9572
9791
|
const lastApprovedBy = findValue('lastApprovedBy') || '';
|
|
9573
9792
|
const lastApprovedAt = findValue('lastApprovedAt') || '';
|
|
9793
|
+
// ── Validation: status change requires reason ──────────────────
|
|
9794
|
+
// Behavior:
|
|
9795
|
+
// - When status changes away from its initial value, clear reason and require it.
|
|
9796
|
+
// - When status returns to initial value (or a parent "Cancel" restores it), restore initial reason.
|
|
9797
|
+
const initialStatusRef = React.useRef(null);
|
|
9798
|
+
const initialReasonRef = React.useRef(null);
|
|
9799
|
+
const prevStatusRef = React.useRef(null);
|
|
9800
|
+
const [showReasonRequired, setShowReasonRequired] = React.useState(false);
|
|
9801
|
+
React.useEffect(() => {
|
|
9802
|
+
// Capture initial status once when it becomes available.
|
|
9803
|
+
if (initialStatusRef.current === null) {
|
|
9804
|
+
const v = statusValue === undefined || statusValue === null ? '' : String(statusValue);
|
|
9805
|
+
initialStatusRef.current = v;
|
|
9806
|
+
}
|
|
9807
|
+
}, [statusValue]);
|
|
9808
|
+
React.useEffect(() => {
|
|
9809
|
+
// Capture initial reason once when it becomes available.
|
|
9810
|
+
if (initialReasonRef.current === null) {
|
|
9811
|
+
const v = statusReason === undefined || statusReason === null ? '' : String(statusReason);
|
|
9812
|
+
initialReasonRef.current = v;
|
|
9813
|
+
}
|
|
9814
|
+
}, [statusReason]);
|
|
9815
|
+
const isStatusChanged = React.useMemo(() => {
|
|
9816
|
+
const initial = initialStatusRef.current;
|
|
9817
|
+
if (initial === null)
|
|
9818
|
+
return false;
|
|
9819
|
+
return String(statusValue) !== initial;
|
|
9820
|
+
}, [statusValue]);
|
|
9821
|
+
const isReasonMissing = React.useMemo(() => {
|
|
9822
|
+
if (!isStatusChanged)
|
|
9823
|
+
return false;
|
|
9824
|
+
return String(statusReason || '').trim().length === 0;
|
|
9825
|
+
}, [isStatusChanged, statusReason]);
|
|
9826
|
+
React.useEffect(() => {
|
|
9827
|
+
// When status changes:
|
|
9828
|
+
// - If moved away from initial → clear reason.
|
|
9829
|
+
// - If returned to initial → restore initial reason.
|
|
9830
|
+
if (isReadonly)
|
|
9831
|
+
return;
|
|
9832
|
+
if (initialStatusRef.current === null)
|
|
9833
|
+
return;
|
|
9834
|
+
const currentStatus = String(statusValue || '');
|
|
9835
|
+
if (prevStatusRef.current === currentStatus)
|
|
9836
|
+
return;
|
|
9837
|
+
prevStatusRef.current = currentStatus;
|
|
9838
|
+
const initialStatus = initialStatusRef.current;
|
|
9839
|
+
const initialReason = initialReasonRef.current ?? '';
|
|
9840
|
+
if (currentStatus === initialStatus) {
|
|
9841
|
+
// Reverted / cancelled back to original
|
|
9842
|
+
if (String(statusReason || '') !== String(initialReason || '')) {
|
|
9843
|
+
updateFieldValue('statusReason', initialReason);
|
|
9844
|
+
}
|
|
9845
|
+
setShowReasonRequired(false);
|
|
9846
|
+
return;
|
|
9847
|
+
}
|
|
9848
|
+
// Status changed to a new value: clear reason (so user must re-enter)
|
|
9849
|
+
if (String(statusReason || '').trim().length > 0) {
|
|
9850
|
+
updateFieldValue('statusReason', '');
|
|
9851
|
+
}
|
|
9852
|
+
setShowReasonRequired(true);
|
|
9853
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
9854
|
+
}, [statusValue, isReadonly]);
|
|
9574
9855
|
const score = React.useMemo(() => {
|
|
9575
9856
|
const toNum = (v) => {
|
|
9576
9857
|
if (v === null || v === undefined || String(v).trim() === '')
|
|
@@ -9584,7 +9865,9 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
9584
9865
|
return null;
|
|
9585
9866
|
const ratio = completion / ideal;
|
|
9586
9867
|
const percent = Math.max(0, Math.min(100, Math.round(ratio * 100)));
|
|
9587
|
-
|
|
9868
|
+
const completionDisplay = Number.isInteger(completion) ? completion : Math.round(completion);
|
|
9869
|
+
const idealDisplay = Number.isInteger(ideal) ? ideal : Math.round(ideal);
|
|
9870
|
+
return { completion, ideal, completionDisplay, idealDisplay, percent };
|
|
9588
9871
|
}, [completionScoreRaw, idealScoreRaw]);
|
|
9589
9872
|
// ── Format options ────────────────────────────────────────────
|
|
9590
9873
|
const format = (widgetConfig['widget-data-format'] || {});
|
|
@@ -9880,6 +10163,19 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
9880
10163
|
box-shadow: 0 0 0 2px rgba(237, 124, 34, 0.15);
|
|
9881
10164
|
}
|
|
9882
10165
|
|
|
10166
|
+
.${cls} .hdr-input--error {
|
|
10167
|
+
border-color: var(--owt-color-danger, #DC2626);
|
|
10168
|
+
box-shadow: 0 0 0 2px rgba(220, 38, 38, 0.12);
|
|
10169
|
+
}
|
|
10170
|
+
|
|
10171
|
+
.${cls} .hdr-error-text {
|
|
10172
|
+
margin-left: calc(0px);
|
|
10173
|
+
color: var(--owt-color-danger, #DC2626);
|
|
10174
|
+
font-size: 0.75rem;
|
|
10175
|
+
line-height: 1.2;
|
|
10176
|
+
font-weight: 500;
|
|
10177
|
+
}
|
|
10178
|
+
|
|
9883
10179
|
@media (max-width: 768px) {
|
|
9884
10180
|
.${cls} {
|
|
9885
10181
|
flex-direction: column;
|
|
@@ -9894,7 +10190,15 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
9894
10190
|
.parentElement?.querySelector('.hdr-avatar-placeholder');
|
|
9895
10191
|
if (placeholder)
|
|
9896
10192
|
placeholder.style.display = 'flex';
|
|
9897
|
-
} })) : 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.
|
|
10193
|
+
} })) : 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: () => {
|
|
10194
|
+
if (isReasonMissing)
|
|
10195
|
+
setShowReasonRequired(true);
|
|
10196
|
+
}, onChange: (e) => {
|
|
10197
|
+
updateFieldValue('statusReason', e.target.value);
|
|
10198
|
+
if (showReasonRequired && String(e.target.value || '').trim().length > 0) {
|
|
10199
|
+
setShowReasonRequired(false);
|
|
10200
|
+
}
|
|
10201
|
+
} }), !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] }) })] })] }));
|
|
9898
10202
|
};
|
|
9899
10203
|
|
|
9900
10204
|
function getValueByPathOrKey(obj, path) {
|
|
@@ -10195,7 +10499,8 @@ function pickAuthorizationUrl(resp, explicitKey) {
|
|
|
10195
10499
|
if (v)
|
|
10196
10500
|
return v;
|
|
10197
10501
|
}
|
|
10198
|
-
return (tryKey('
|
|
10502
|
+
return (tryKey('authentication_url') ||
|
|
10503
|
+
tryKey('authorization_url') ||
|
|
10199
10504
|
tryKey('authorizationUrl') ||
|
|
10200
10505
|
tryKey('auth_url') ||
|
|
10201
10506
|
tryKey('authUrl') ||
|
|
@@ -10210,12 +10515,14 @@ function resolveValueFromSources(path, values, schemaData) {
|
|
|
10210
10515
|
return fromValues;
|
|
10211
10516
|
return getValueByPath(schemaData, path);
|
|
10212
10517
|
}
|
|
10213
|
-
|
|
10214
|
-
|
|
10215
|
-
|
|
10216
|
-
|
|
10217
|
-
|
|
10218
|
-
|
|
10518
|
+
function unwrapPayload(response) {
|
|
10519
|
+
if (response && typeof response === 'object') {
|
|
10520
|
+
if (response.response_body?.response_payload !== undefined)
|
|
10521
|
+
return response.response_body.response_payload;
|
|
10522
|
+
if (response.response_payload !== undefined)
|
|
10523
|
+
return response.response_payload;
|
|
10524
|
+
}
|
|
10525
|
+
return response;
|
|
10219
10526
|
}
|
|
10220
10527
|
const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
10221
10528
|
const { dataSourceRequestHandler, schemaData: ctxSchemaData } = useWidgetContext();
|
|
@@ -10229,6 +10536,11 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10229
10536
|
return dataPath;
|
|
10230
10537
|
}, [dataPath]);
|
|
10231
10538
|
const authConfig = config['widget-auth-config'];
|
|
10539
|
+
const registerId = resolveValueFromSources(paths.registerId, values, schemaData);
|
|
10540
|
+
const internalRecordId = resolveValueFromSources(paths.internalRecordId, values, schemaData);
|
|
10541
|
+
const initiatedByStaffId = resolveValueFromSources(paths.initiatedByStaffId, values, schemaData);
|
|
10542
|
+
const providerId = authConfig?.providerId;
|
|
10543
|
+
const providerName = authConfig?.providerName;
|
|
10232
10544
|
const foundationalId = resolveValueFromSources(paths.foundationalId, values, schemaData);
|
|
10233
10545
|
const lastAuthenticatedOn = resolveValueFromSources(paths.lastAuthenticatedOn, values, schemaData);
|
|
10234
10546
|
const lastAuthStatusRaw = resolveValueFromSources(paths.lastAuthenticationStatus, values, schemaData);
|
|
@@ -10237,11 +10549,11 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10237
10549
|
const status = React.useMemo(() => normalizeStatus(lastAuthStatusRaw), [lastAuthStatusRaw]);
|
|
10238
10550
|
/** URL from prefetch (or default); used when opening the OIDC / eSignet popup */
|
|
10239
10551
|
const [resolvedAuthUrl, setResolvedAuthUrl] = React.useState(null);
|
|
10240
|
-
const [providerLoading, setProviderLoading] = React.useState(false);
|
|
10241
10552
|
const [authActionLoading, setAuthActionLoading] = React.useState(false);
|
|
10242
10553
|
const [authError, setAuthError] = React.useState(null);
|
|
10243
10554
|
const popupRef = React.useRef(null);
|
|
10244
10555
|
const pollTimerRef = React.useRef(null);
|
|
10556
|
+
const [overlayUrl, setOverlayUrl] = React.useState(null);
|
|
10245
10557
|
const emitHostEvent = React.useCallback((detail) => {
|
|
10246
10558
|
if (typeof window === 'undefined')
|
|
10247
10559
|
return;
|
|
@@ -10270,72 +10582,16 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10270
10582
|
}
|
|
10271
10583
|
};
|
|
10272
10584
|
}, [cleanupPopup]);
|
|
10273
|
-
|
|
10274
|
-
if (!authConfig)
|
|
10275
|
-
return 'no-config';
|
|
10276
|
-
return JSON.stringify({
|
|
10277
|
-
s: authConfig.service,
|
|
10278
|
-
e: authConfig.endpoint,
|
|
10279
|
-
m: authConfig.method,
|
|
10280
|
-
def: authConfig.defaultAuthorizationUrl,
|
|
10281
|
-
prefetch: authConfig.prefetchOnMount,
|
|
10282
|
-
});
|
|
10283
|
-
}, [authConfig]);
|
|
10284
|
-
// Prefetch provider login URL on mount (and when params / config change)
|
|
10585
|
+
// Provider details are supplied by host; clear any previous resolved URL on provider change.
|
|
10285
10586
|
React.useEffect(() => {
|
|
10286
|
-
|
|
10287
|
-
|
|
10288
|
-
|
|
10289
|
-
|
|
10290
|
-
|
|
10291
|
-
|
|
10292
|
-
setResolvedAuthUrl(authConfig.defaultAuthorizationUrl || null);
|
|
10293
|
-
setProviderLoading(false);
|
|
10294
|
-
return;
|
|
10295
|
-
}
|
|
10296
|
-
const def = authConfig.defaultAuthorizationUrl;
|
|
10297
|
-
if (def) {
|
|
10298
|
-
setResolvedAuthUrl(def);
|
|
10299
|
-
}
|
|
10300
|
-
const canCallApi = Boolean(dataSourceRequestHandler && authConfig.service && authConfig.endpoint);
|
|
10301
|
-
if (!canCallApi) {
|
|
10302
|
-
setProviderLoading(false);
|
|
10303
|
-
if (!def) {
|
|
10304
|
-
setResolvedAuthUrl(null);
|
|
10305
|
-
}
|
|
10587
|
+
setResolvedAuthUrl(null);
|
|
10588
|
+
}, [providerId, providerName]);
|
|
10589
|
+
const openAuthPopup = React.useCallback((authUrl) => {
|
|
10590
|
+
if (authConfig?.useIframeOverlay !== false) {
|
|
10591
|
+
setOverlayUrl(authUrl);
|
|
10592
|
+
emitHostEvent({ type: 'overlay_opened' });
|
|
10306
10593
|
return;
|
|
10307
10594
|
}
|
|
10308
|
-
let cancelled = false;
|
|
10309
|
-
setProviderLoading(true);
|
|
10310
|
-
(async () => {
|
|
10311
|
-
try {
|
|
10312
|
-
const url = await fetchProviderAuthorizationUrl(authConfig, dataSourceRequestHandler, values, schemaData);
|
|
10313
|
-
if (cancelled)
|
|
10314
|
-
return;
|
|
10315
|
-
if (url) {
|
|
10316
|
-
setResolvedAuthUrl(url);
|
|
10317
|
-
}
|
|
10318
|
-
else if (!def) {
|
|
10319
|
-
setResolvedAuthUrl(null);
|
|
10320
|
-
}
|
|
10321
|
-
}
|
|
10322
|
-
catch {
|
|
10323
|
-
if (cancelled)
|
|
10324
|
-
return;
|
|
10325
|
-
if (!def) {
|
|
10326
|
-
setResolvedAuthUrl(null);
|
|
10327
|
-
}
|
|
10328
|
-
}
|
|
10329
|
-
finally {
|
|
10330
|
-
if (!cancelled)
|
|
10331
|
-
setProviderLoading(false);
|
|
10332
|
-
}
|
|
10333
|
-
})();
|
|
10334
|
-
return () => {
|
|
10335
|
-
cancelled = true;
|
|
10336
|
-
};
|
|
10337
|
-
}, [authConfig, dataSourceRequestHandler, prefetchKey, values, schemaData]);
|
|
10338
|
-
const openAuthPopup = React.useCallback((authUrl) => {
|
|
10339
10595
|
const pw = authConfig?.popupWidth ?? 1024;
|
|
10340
10596
|
const ph = authConfig?.popupHeight ?? 800;
|
|
10341
10597
|
const features = getCenteredPopupFeatures(pw, ph);
|
|
@@ -10371,20 +10627,24 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10371
10627
|
setAuthError('Missing widget-auth-config.');
|
|
10372
10628
|
return;
|
|
10373
10629
|
}
|
|
10374
|
-
const
|
|
10375
|
-
const canCallApi = Boolean(dataSourceRequestHandler && authConfig.service && authConfig.endpoint);
|
|
10630
|
+
const canCallAuthApi = Boolean(dataSourceRequestHandler && authConfig.service && authConfig.authenticateEndpoint);
|
|
10376
10631
|
let url = resolvedAuthUrl;
|
|
10377
|
-
if (!url &&
|
|
10632
|
+
if (!url && canCallAuthApi) {
|
|
10378
10633
|
setAuthActionLoading(true);
|
|
10379
10634
|
try {
|
|
10380
|
-
const
|
|
10381
|
-
|
|
10382
|
-
|
|
10383
|
-
|
|
10384
|
-
|
|
10635
|
+
const resp = await dataSourceRequestHandler(authConfig.service, authConfig.authenticateEndpoint, authConfig.authenticateMethod || 'POST', {
|
|
10636
|
+
register_id: registerId,
|
|
10637
|
+
internal_record_id: internalRecordId,
|
|
10638
|
+
provider_id: authConfig.providerId,
|
|
10639
|
+
initiated_by_staff_id: initiatedByStaffId,
|
|
10640
|
+
});
|
|
10641
|
+
const payload = unwrapPayload(resp);
|
|
10642
|
+
const authUrl = pickAuthorizationUrl(payload, authConfig.authorizationUrlKey);
|
|
10643
|
+
url = authUrl || null;
|
|
10644
|
+
if (authUrl)
|
|
10645
|
+
setResolvedAuthUrl(authUrl);
|
|
10385
10646
|
}
|
|
10386
10647
|
catch (e) {
|
|
10387
|
-
url = def || null;
|
|
10388
10648
|
if (!url) {
|
|
10389
10649
|
setAuthError(e?.message || 'Could not load provider URL.');
|
|
10390
10650
|
return;
|
|
@@ -10394,15 +10654,20 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10394
10654
|
setAuthActionLoading(false);
|
|
10395
10655
|
}
|
|
10396
10656
|
}
|
|
10397
|
-
else if (!url) {
|
|
10398
|
-
url = def || null;
|
|
10399
|
-
}
|
|
10400
10657
|
if (!url) {
|
|
10401
|
-
setAuthError('No authorization URL
|
|
10658
|
+
setAuthError('No authorization URL returned from authenticate_registrant.');
|
|
10402
10659
|
return;
|
|
10403
10660
|
}
|
|
10404
10661
|
openAuthPopup(url);
|
|
10405
|
-
}, [
|
|
10662
|
+
}, [
|
|
10663
|
+
authConfig,
|
|
10664
|
+
dataSourceRequestHandler,
|
|
10665
|
+
openAuthPopup,
|
|
10666
|
+
registerId,
|
|
10667
|
+
internalRecordId,
|
|
10668
|
+
initiatedByStaffId,
|
|
10669
|
+
resolvedAuthUrl,
|
|
10670
|
+
]);
|
|
10406
10671
|
React.useEffect(() => {
|
|
10407
10672
|
const successType = authConfig?.successMessageType || 'openg2p:oidc:success';
|
|
10408
10673
|
const handler = (event) => {
|
|
@@ -10447,8 +10712,7 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10447
10712
|
return 'var(--owt-color-warning, #D97706)';
|
|
10448
10713
|
return 'var(--owt-color-text-muted, #6B7280)';
|
|
10449
10714
|
}, [status]);
|
|
10450
|
-
const buttonBusy = authActionLoading
|
|
10451
|
-
(providerLoading && !resolvedAuthUrl && !authConfig?.defaultAuthorizationUrl);
|
|
10715
|
+
const buttonBusy = authActionLoading;
|
|
10452
10716
|
const buttonDisabled = !authConfig || buttonBusy;
|
|
10453
10717
|
return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("style", { children: `
|
|
10454
10718
|
.${cls} {
|
|
@@ -10484,6 +10748,14 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10484
10748
|
grid-column: 1 / -1;
|
|
10485
10749
|
}
|
|
10486
10750
|
|
|
10751
|
+
/* Action cell: no left label spacer, align button to column start */
|
|
10752
|
+
.${cls} .auth-cell.auth-cell--action .auth-label {
|
|
10753
|
+
display: none;
|
|
10754
|
+
}
|
|
10755
|
+
.${cls} .auth-cell.auth-cell--action .auth-value {
|
|
10756
|
+
flex: 1 1 auto;
|
|
10757
|
+
}
|
|
10758
|
+
|
|
10487
10759
|
.${cls} .auth-label {
|
|
10488
10760
|
flex: 0 0 auto;
|
|
10489
10761
|
min-width: 200px;
|
|
@@ -10506,17 +10778,15 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10506
10778
|
word-break: break-word;
|
|
10507
10779
|
}
|
|
10508
10780
|
|
|
10509
|
-
.${cls} .auth-
|
|
10510
|
-
|
|
10511
|
-
|
|
10512
|
-
|
|
10513
|
-
|
|
10514
|
-
gap: 8px;
|
|
10515
|
-
width: 100%;
|
|
10516
|
-
margin-top: 20px;
|
|
10517
|
-
margin-bottom: 0;
|
|
10781
|
+
.${cls} .auth-value--foundational {
|
|
10782
|
+
font-size: 18px;
|
|
10783
|
+
font-weight: 700;
|
|
10784
|
+
color: var(--owt-color-primary-dark, #F07B1A);
|
|
10785
|
+
letter-spacing: 0.1px;
|
|
10518
10786
|
}
|
|
10519
10787
|
|
|
10788
|
+
/* Button is placed inside the grid (next to PSUT) */
|
|
10789
|
+
|
|
10520
10790
|
.${cls} .auth-status {
|
|
10521
10791
|
display: inline-flex;
|
|
10522
10792
|
align-items: center;
|
|
@@ -10557,8 +10827,8 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10557
10827
|
padding: 8px 24px;
|
|
10558
10828
|
line-height: 1.5;
|
|
10559
10829
|
border-radius: var(--owt-btn-border-radius, 10px);
|
|
10560
|
-
border: 1px solid
|
|
10561
|
-
background-color:
|
|
10830
|
+
border: 1px solid rgb(237, 124, 34);
|
|
10831
|
+
background-color: rgb(237, 124, 34);
|
|
10562
10832
|
color: var(--owt-color-bg, #FFFFFF);
|
|
10563
10833
|
font-family: Roboto, sans-serif;
|
|
10564
10834
|
cursor: pointer;
|
|
@@ -10579,6 +10849,63 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10579
10849
|
max-width: 100%;
|
|
10580
10850
|
}
|
|
10581
10851
|
|
|
10852
|
+
.${cls} .overlay-backdrop {
|
|
10853
|
+
position: fixed;
|
|
10854
|
+
inset: 0;
|
|
10855
|
+
background: rgba(17, 24, 39, 0.55);
|
|
10856
|
+
z-index: 9999;
|
|
10857
|
+
display: flex;
|
|
10858
|
+
align-items: center;
|
|
10859
|
+
justify-content: center;
|
|
10860
|
+
padding: 24px;
|
|
10861
|
+
}
|
|
10862
|
+
|
|
10863
|
+
.${cls} .overlay-panel {
|
|
10864
|
+
width: min(1100px, 92vw);
|
|
10865
|
+
height: min(820px, 92vh);
|
|
10866
|
+
background: var(--owt-color-bg, #FFFFFF);
|
|
10867
|
+
border-radius: 12px;
|
|
10868
|
+
box-shadow: 0 10px 30px rgba(0,0,0,0.25);
|
|
10869
|
+
overflow: hidden;
|
|
10870
|
+
display: flex;
|
|
10871
|
+
flex-direction: column;
|
|
10872
|
+
}
|
|
10873
|
+
|
|
10874
|
+
.${cls} .overlay-header {
|
|
10875
|
+
display: flex;
|
|
10876
|
+
align-items: center;
|
|
10877
|
+
justify-content: space-between;
|
|
10878
|
+
padding: 10px 14px;
|
|
10879
|
+
border-bottom: 1px solid var(--owt-color-border-light, #E4E4E4);
|
|
10880
|
+
font-family: Roboto, sans-serif;
|
|
10881
|
+
}
|
|
10882
|
+
|
|
10883
|
+
.${cls} .overlay-title {
|
|
10884
|
+
font-size: 14px;
|
|
10885
|
+
color: var(--owt-color-text, #011627);
|
|
10886
|
+
font-weight: 600;
|
|
10887
|
+
min-width: 0;
|
|
10888
|
+
overflow: hidden;
|
|
10889
|
+
text-overflow: ellipsis;
|
|
10890
|
+
white-space: nowrap;
|
|
10891
|
+
}
|
|
10892
|
+
|
|
10893
|
+
.${cls} .overlay-close {
|
|
10894
|
+
border: 1px solid var(--owt-btn-secondary-border, #C4C4C4);
|
|
10895
|
+
background: var(--owt-btn-secondary-bg, #FFFFFF);
|
|
10896
|
+
color: var(--owt-btn-secondary-color, #011627);
|
|
10897
|
+
border-radius: var(--owt-btn-border-radius, 10px);
|
|
10898
|
+
padding: 6px 10px;
|
|
10899
|
+
font-size: 12px;
|
|
10900
|
+
cursor: pointer;
|
|
10901
|
+
}
|
|
10902
|
+
|
|
10903
|
+
.${cls} .overlay-iframe {
|
|
10904
|
+
flex: 1 1 auto;
|
|
10905
|
+
width: 100%;
|
|
10906
|
+
border: none;
|
|
10907
|
+
}
|
|
10908
|
+
|
|
10582
10909
|
@media (max-width: 640px) {
|
|
10583
10910
|
.${cls} .auth-grid {
|
|
10584
10911
|
grid-template-columns: 1fr;
|
|
@@ -10593,7 +10920,15 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10593
10920
|
max-width: none;
|
|
10594
10921
|
}
|
|
10595
10922
|
}
|
|
10596
|
-
` }), jsxRuntimeExports.
|
|
10923
|
+
` }), jsxRuntimeExports.jsxs("div", { className: cls, children: [overlayUrl ? (jsxRuntimeExports.jsx("div", { className: "overlay-backdrop", role: "dialog", "aria-modal": "true", "aria-label": "Authentication", onClick: (e) => {
|
|
10924
|
+
if (e.target === e.currentTarget) {
|
|
10925
|
+
setOverlayUrl(null);
|
|
10926
|
+
emitHostEvent({ type: 'overlay_closed' });
|
|
10927
|
+
}
|
|
10928
|
+
}, children: jsxRuntimeExports.jsxs("div", { className: "overlay-panel", children: [jsxRuntimeExports.jsxs("div", { className: "overlay-header", children: [jsxRuntimeExports.jsx("div", { className: "overlay-title", children: providerName ? `Authenticate via ${providerName}` : 'Authenticate' }), jsxRuntimeExports.jsx("button", { type: "button", className: "overlay-close", onClick: () => {
|
|
10929
|
+
setOverlayUrl(null);
|
|
10930
|
+
emitHostEvent({ type: 'overlay_closed' });
|
|
10931
|
+
}, children: "Close" })] }), jsxRuntimeExports.jsx("iframe", { className: "overlay-iframe", src: overlayUrl, title: "Authentication" })] }) })) : null, jsxRuntimeExports.jsx("div", { className: "auth-content", children: jsxRuntimeExports.jsxs("div", { className: "auth-grid", children: [jsxRuntimeExports.jsxs("div", { className: "auth-cell", children: [jsxRuntimeExports.jsx("div", { className: "auth-label", children: "Foundational ID:" }), jsxRuntimeExports.jsx("div", { className: "auth-value auth-value--foundational", children: displayText(foundationalId) })] }), jsxRuntimeExports.jsxs("div", { className: "auth-cell", children: [jsxRuntimeExports.jsx("div", { className: "auth-label", children: "Last authenticated on:" }), jsxRuntimeExports.jsx("div", { className: "auth-value", children: tryFormatDateTime(lastAuthenticatedOn) })] }), jsxRuntimeExports.jsxs("div", { className: "auth-cell", children: [jsxRuntimeExports.jsx("div", { className: "auth-label", children: "Expiry date:" }), jsxRuntimeExports.jsx("div", { className: "auth-value", children: tryFormatDate(expiryDate) })] }), jsxRuntimeExports.jsxs("div", { className: "auth-cell", children: [jsxRuntimeExports.jsx("div", { className: "auth-label", children: "Last authentication status:" }), jsxRuntimeExports.jsx("div", { className: "auth-value", children: jsxRuntimeExports.jsxs("div", { className: "auth-status", "aria-label": `Authentication status: ${statusLabel}`, children: [jsxRuntimeExports.jsx("span", { className: "auth-dot" }), jsxRuntimeExports.jsx("span", { children: statusLabel })] }) })] }), jsxRuntimeExports.jsxs("div", { className: "auth-cell", children: [jsxRuntimeExports.jsx("div", { className: "auth-label", children: "Authentication token (PSUT):" }), jsxRuntimeExports.jsx("div", { className: "auth-value", children: jsxRuntimeExports.jsx("div", { className: "auth-token", children: psut ? String(psut) : '-' }) })] }), jsxRuntimeExports.jsxs("div", { className: "auth-cell auth-cell--action", children: [jsxRuntimeExports.jsx("div", { className: "auth-label", "aria-hidden": true }), jsxRuntimeExports.jsxs("div", { className: "auth-value", children: [jsxRuntimeExports.jsx("button", { type: "button", className: "auth-button", onClick: onAuthenticate, disabled: buttonDisabled, children: buttonBusy ? 'Loading…' : 'Authenticate' }), authError ? (jsxRuntimeExports.jsx("div", { className: "auth-error", style: { marginTop: 8 }, children: authError })) : null] })] })] }) })] })] }));
|
|
10597
10932
|
};
|
|
10598
10933
|
|
|
10599
10934
|
/**
|
|
@@ -10625,6 +10960,8 @@ const registerDefaultWidgets = () => {
|
|
|
10625
10960
|
widgetRegistry.register({ widget: 'simple-table', component: SimpleTableWidget });
|
|
10626
10961
|
// Table widget with record-level editing
|
|
10627
10962
|
widgetRegistry.register({ widget: 'table', component: TableWidget });
|
|
10963
|
+
// Table widget with add/edit popup dialog
|
|
10964
|
+
widgetRegistry.register({ widget: 'dialog-table', component: DialogTableWidget });
|
|
10628
10965
|
// Group widgets
|
|
10629
10966
|
widgetRegistry.register({ widget: 'array-widget', component: ArrayWidget });
|
|
10630
10967
|
widgetRegistry.register({ widget: 'iterable-accordion', component: IterableAccordionWidget });
|
|
@@ -11009,6 +11346,7 @@ exports.CheckboxWidget = CheckboxWidget;
|
|
|
11009
11346
|
exports.CurrencyInputWidget = CurrencyInputWidget;
|
|
11010
11347
|
exports.DateInputWidget = DateInputWidget;
|
|
11011
11348
|
exports.DateTimeInputWidget = DateTimeInputWidget;
|
|
11349
|
+
exports.DialogTableWidget = DialogTableWidget;
|
|
11012
11350
|
exports.DisplayWidget = DisplayWidget;
|
|
11013
11351
|
exports.FileInputWidget = FileInputWidget;
|
|
11014
11352
|
exports.HeaderSectionWidget = HeaderSectionWidget;
|