@openg2p/registry-widgets 1.1.0-dev.2 → 1.1.0-dev.3
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 +438 -103
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +438 -102
- 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() === '')
|
|
@@ -9880,6 +10161,19 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
9880
10161
|
box-shadow: 0 0 0 2px rgba(237, 124, 34, 0.15);
|
|
9881
10162
|
}
|
|
9882
10163
|
|
|
10164
|
+
.${cls} .hdr-input--error {
|
|
10165
|
+
border-color: var(--owt-color-danger, #DC2626);
|
|
10166
|
+
box-shadow: 0 0 0 2px rgba(220, 38, 38, 0.12);
|
|
10167
|
+
}
|
|
10168
|
+
|
|
10169
|
+
.${cls} .hdr-error-text {
|
|
10170
|
+
margin-left: calc(0px);
|
|
10171
|
+
color: var(--owt-color-danger, #DC2626);
|
|
10172
|
+
font-size: 0.75rem;
|
|
10173
|
+
line-height: 1.2;
|
|
10174
|
+
font-weight: 500;
|
|
10175
|
+
}
|
|
10176
|
+
|
|
9883
10177
|
@media (max-width: 768px) {
|
|
9884
10178
|
.${cls} {
|
|
9885
10179
|
flex-direction: column;
|
|
@@ -9894,7 +10188,15 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
9894
10188
|
.parentElement?.querySelector('.hdr-avatar-placeholder');
|
|
9895
10189
|
if (placeholder)
|
|
9896
10190
|
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.
|
|
10191
|
+
} })) : 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: () => {
|
|
10192
|
+
if (isReasonMissing)
|
|
10193
|
+
setShowReasonRequired(true);
|
|
10194
|
+
}, onChange: (e) => {
|
|
10195
|
+
updateFieldValue('statusReason', e.target.value);
|
|
10196
|
+
if (showReasonRequired && String(e.target.value || '').trim().length > 0) {
|
|
10197
|
+
setShowReasonRequired(false);
|
|
10198
|
+
}
|
|
10199
|
+
} }), !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.completion} of ${score.ideal} (${score.percent}%)`, title: `${score.completion} / ${score.ideal} (${score.percent}%)`, children: jsxRuntimeExports.jsx("div", { className: "hdr-score-value", children: String(score.completion) }) })) : null] }) })] })] }));
|
|
9898
10200
|
};
|
|
9899
10201
|
|
|
9900
10202
|
function getValueByPathOrKey(obj, path) {
|
|
@@ -10195,7 +10497,8 @@ function pickAuthorizationUrl(resp, explicitKey) {
|
|
|
10195
10497
|
if (v)
|
|
10196
10498
|
return v;
|
|
10197
10499
|
}
|
|
10198
|
-
return (tryKey('
|
|
10500
|
+
return (tryKey('authentication_url') ||
|
|
10501
|
+
tryKey('authorization_url') ||
|
|
10199
10502
|
tryKey('authorizationUrl') ||
|
|
10200
10503
|
tryKey('auth_url') ||
|
|
10201
10504
|
tryKey('authUrl') ||
|
|
@@ -10210,12 +10513,14 @@ function resolveValueFromSources(path, values, schemaData) {
|
|
|
10210
10513
|
return fromValues;
|
|
10211
10514
|
return getValueByPath(schemaData, path);
|
|
10212
10515
|
}
|
|
10213
|
-
|
|
10214
|
-
|
|
10215
|
-
|
|
10216
|
-
|
|
10217
|
-
|
|
10218
|
-
|
|
10516
|
+
function unwrapPayload(response) {
|
|
10517
|
+
if (response && typeof response === 'object') {
|
|
10518
|
+
if (response.response_body?.response_payload !== undefined)
|
|
10519
|
+
return response.response_body.response_payload;
|
|
10520
|
+
if (response.response_payload !== undefined)
|
|
10521
|
+
return response.response_payload;
|
|
10522
|
+
}
|
|
10523
|
+
return response;
|
|
10219
10524
|
}
|
|
10220
10525
|
const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
10221
10526
|
const { dataSourceRequestHandler, schemaData: ctxSchemaData } = useWidgetContext();
|
|
@@ -10229,6 +10534,11 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10229
10534
|
return dataPath;
|
|
10230
10535
|
}, [dataPath]);
|
|
10231
10536
|
const authConfig = config['widget-auth-config'];
|
|
10537
|
+
const registerId = resolveValueFromSources(paths.registerId, values, schemaData);
|
|
10538
|
+
const internalRecordId = resolveValueFromSources(paths.internalRecordId, values, schemaData);
|
|
10539
|
+
const initiatedByStaffId = resolveValueFromSources(paths.initiatedByStaffId, values, schemaData);
|
|
10540
|
+
const providerId = authConfig?.providerId;
|
|
10541
|
+
const providerName = authConfig?.providerName;
|
|
10232
10542
|
const foundationalId = resolveValueFromSources(paths.foundationalId, values, schemaData);
|
|
10233
10543
|
const lastAuthenticatedOn = resolveValueFromSources(paths.lastAuthenticatedOn, values, schemaData);
|
|
10234
10544
|
const lastAuthStatusRaw = resolveValueFromSources(paths.lastAuthenticationStatus, values, schemaData);
|
|
@@ -10237,11 +10547,11 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10237
10547
|
const status = React.useMemo(() => normalizeStatus(lastAuthStatusRaw), [lastAuthStatusRaw]);
|
|
10238
10548
|
/** URL from prefetch (or default); used when opening the OIDC / eSignet popup */
|
|
10239
10549
|
const [resolvedAuthUrl, setResolvedAuthUrl] = React.useState(null);
|
|
10240
|
-
const [providerLoading, setProviderLoading] = React.useState(false);
|
|
10241
10550
|
const [authActionLoading, setAuthActionLoading] = React.useState(false);
|
|
10242
10551
|
const [authError, setAuthError] = React.useState(null);
|
|
10243
10552
|
const popupRef = React.useRef(null);
|
|
10244
10553
|
const pollTimerRef = React.useRef(null);
|
|
10554
|
+
const [overlayUrl, setOverlayUrl] = React.useState(null);
|
|
10245
10555
|
const emitHostEvent = React.useCallback((detail) => {
|
|
10246
10556
|
if (typeof window === 'undefined')
|
|
10247
10557
|
return;
|
|
@@ -10270,72 +10580,16 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10270
10580
|
}
|
|
10271
10581
|
};
|
|
10272
10582
|
}, [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)
|
|
10583
|
+
// Provider details are supplied by host; clear any previous resolved URL on provider change.
|
|
10285
10584
|
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
|
-
}
|
|
10585
|
+
setResolvedAuthUrl(null);
|
|
10586
|
+
}, [providerId, providerName]);
|
|
10587
|
+
const openAuthPopup = React.useCallback((authUrl) => {
|
|
10588
|
+
if (authConfig?.useIframeOverlay !== false) {
|
|
10589
|
+
setOverlayUrl(authUrl);
|
|
10590
|
+
emitHostEvent({ type: 'overlay_opened' });
|
|
10306
10591
|
return;
|
|
10307
10592
|
}
|
|
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
10593
|
const pw = authConfig?.popupWidth ?? 1024;
|
|
10340
10594
|
const ph = authConfig?.popupHeight ?? 800;
|
|
10341
10595
|
const features = getCenteredPopupFeatures(pw, ph);
|
|
@@ -10371,20 +10625,24 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10371
10625
|
setAuthError('Missing widget-auth-config.');
|
|
10372
10626
|
return;
|
|
10373
10627
|
}
|
|
10374
|
-
const
|
|
10375
|
-
const canCallApi = Boolean(dataSourceRequestHandler && authConfig.service && authConfig.endpoint);
|
|
10628
|
+
const canCallAuthApi = Boolean(dataSourceRequestHandler && authConfig.service && authConfig.authenticateEndpoint);
|
|
10376
10629
|
let url = resolvedAuthUrl;
|
|
10377
|
-
if (!url &&
|
|
10630
|
+
if (!url && canCallAuthApi) {
|
|
10378
10631
|
setAuthActionLoading(true);
|
|
10379
10632
|
try {
|
|
10380
|
-
const
|
|
10381
|
-
|
|
10382
|
-
|
|
10383
|
-
|
|
10384
|
-
|
|
10633
|
+
const resp = await dataSourceRequestHandler(authConfig.service, authConfig.authenticateEndpoint, authConfig.authenticateMethod || 'POST', {
|
|
10634
|
+
register_id: registerId,
|
|
10635
|
+
internal_record_id: internalRecordId,
|
|
10636
|
+
provider_id: authConfig.providerId,
|
|
10637
|
+
initiated_by_staff_id: initiatedByStaffId,
|
|
10638
|
+
});
|
|
10639
|
+
const payload = unwrapPayload(resp);
|
|
10640
|
+
const authUrl = pickAuthorizationUrl(payload, authConfig.authorizationUrlKey);
|
|
10641
|
+
url = authUrl || null;
|
|
10642
|
+
if (authUrl)
|
|
10643
|
+
setResolvedAuthUrl(authUrl);
|
|
10385
10644
|
}
|
|
10386
10645
|
catch (e) {
|
|
10387
|
-
url = def || null;
|
|
10388
10646
|
if (!url) {
|
|
10389
10647
|
setAuthError(e?.message || 'Could not load provider URL.');
|
|
10390
10648
|
return;
|
|
@@ -10394,15 +10652,20 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10394
10652
|
setAuthActionLoading(false);
|
|
10395
10653
|
}
|
|
10396
10654
|
}
|
|
10397
|
-
else if (!url) {
|
|
10398
|
-
url = def || null;
|
|
10399
|
-
}
|
|
10400
10655
|
if (!url) {
|
|
10401
|
-
setAuthError('No authorization URL
|
|
10656
|
+
setAuthError('No authorization URL returned from authenticate_registrant.');
|
|
10402
10657
|
return;
|
|
10403
10658
|
}
|
|
10404
10659
|
openAuthPopup(url);
|
|
10405
|
-
}, [
|
|
10660
|
+
}, [
|
|
10661
|
+
authConfig,
|
|
10662
|
+
dataSourceRequestHandler,
|
|
10663
|
+
openAuthPopup,
|
|
10664
|
+
registerId,
|
|
10665
|
+
internalRecordId,
|
|
10666
|
+
initiatedByStaffId,
|
|
10667
|
+
resolvedAuthUrl,
|
|
10668
|
+
]);
|
|
10406
10669
|
React.useEffect(() => {
|
|
10407
10670
|
const successType = authConfig?.successMessageType || 'openg2p:oidc:success';
|
|
10408
10671
|
const handler = (event) => {
|
|
@@ -10447,8 +10710,7 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10447
10710
|
return 'var(--owt-color-warning, #D97706)';
|
|
10448
10711
|
return 'var(--owt-color-text-muted, #6B7280)';
|
|
10449
10712
|
}, [status]);
|
|
10450
|
-
const buttonBusy = authActionLoading
|
|
10451
|
-
(providerLoading && !resolvedAuthUrl && !authConfig?.defaultAuthorizationUrl);
|
|
10713
|
+
const buttonBusy = authActionLoading;
|
|
10452
10714
|
const buttonDisabled = !authConfig || buttonBusy;
|
|
10453
10715
|
return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("style", { children: `
|
|
10454
10716
|
.${cls} {
|
|
@@ -10484,6 +10746,14 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10484
10746
|
grid-column: 1 / -1;
|
|
10485
10747
|
}
|
|
10486
10748
|
|
|
10749
|
+
/* Action cell: no left label spacer, align button to column start */
|
|
10750
|
+
.${cls} .auth-cell.auth-cell--action .auth-label {
|
|
10751
|
+
display: none;
|
|
10752
|
+
}
|
|
10753
|
+
.${cls} .auth-cell.auth-cell--action .auth-value {
|
|
10754
|
+
flex: 1 1 auto;
|
|
10755
|
+
}
|
|
10756
|
+
|
|
10487
10757
|
.${cls} .auth-label {
|
|
10488
10758
|
flex: 0 0 auto;
|
|
10489
10759
|
min-width: 200px;
|
|
@@ -10506,17 +10776,15 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10506
10776
|
word-break: break-word;
|
|
10507
10777
|
}
|
|
10508
10778
|
|
|
10509
|
-
.${cls} .auth-
|
|
10510
|
-
|
|
10511
|
-
|
|
10512
|
-
|
|
10513
|
-
|
|
10514
|
-
gap: 8px;
|
|
10515
|
-
width: 100%;
|
|
10516
|
-
margin-top: 20px;
|
|
10517
|
-
margin-bottom: 0;
|
|
10779
|
+
.${cls} .auth-value--foundational {
|
|
10780
|
+
font-size: 18px;
|
|
10781
|
+
font-weight: 700;
|
|
10782
|
+
color: var(--owt-color-primary-dark, #F07B1A);
|
|
10783
|
+
letter-spacing: 0.1px;
|
|
10518
10784
|
}
|
|
10519
10785
|
|
|
10786
|
+
/* Button is placed inside the grid (next to PSUT) */
|
|
10787
|
+
|
|
10520
10788
|
.${cls} .auth-status {
|
|
10521
10789
|
display: inline-flex;
|
|
10522
10790
|
align-items: center;
|
|
@@ -10557,8 +10825,8 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10557
10825
|
padding: 8px 24px;
|
|
10558
10826
|
line-height: 1.5;
|
|
10559
10827
|
border-radius: var(--owt-btn-border-radius, 10px);
|
|
10560
|
-
border: 1px solid
|
|
10561
|
-
background-color:
|
|
10828
|
+
border: 1px solid rgb(237, 124, 34);
|
|
10829
|
+
background-color: rgb(237, 124, 34);
|
|
10562
10830
|
color: var(--owt-color-bg, #FFFFFF);
|
|
10563
10831
|
font-family: Roboto, sans-serif;
|
|
10564
10832
|
cursor: pointer;
|
|
@@ -10579,6 +10847,63 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10579
10847
|
max-width: 100%;
|
|
10580
10848
|
}
|
|
10581
10849
|
|
|
10850
|
+
.${cls} .overlay-backdrop {
|
|
10851
|
+
position: fixed;
|
|
10852
|
+
inset: 0;
|
|
10853
|
+
background: rgba(17, 24, 39, 0.55);
|
|
10854
|
+
z-index: 9999;
|
|
10855
|
+
display: flex;
|
|
10856
|
+
align-items: center;
|
|
10857
|
+
justify-content: center;
|
|
10858
|
+
padding: 24px;
|
|
10859
|
+
}
|
|
10860
|
+
|
|
10861
|
+
.${cls} .overlay-panel {
|
|
10862
|
+
width: min(1100px, 92vw);
|
|
10863
|
+
height: min(820px, 92vh);
|
|
10864
|
+
background: var(--owt-color-bg, #FFFFFF);
|
|
10865
|
+
border-radius: 12px;
|
|
10866
|
+
box-shadow: 0 10px 30px rgba(0,0,0,0.25);
|
|
10867
|
+
overflow: hidden;
|
|
10868
|
+
display: flex;
|
|
10869
|
+
flex-direction: column;
|
|
10870
|
+
}
|
|
10871
|
+
|
|
10872
|
+
.${cls} .overlay-header {
|
|
10873
|
+
display: flex;
|
|
10874
|
+
align-items: center;
|
|
10875
|
+
justify-content: space-between;
|
|
10876
|
+
padding: 10px 14px;
|
|
10877
|
+
border-bottom: 1px solid var(--owt-color-border-light, #E4E4E4);
|
|
10878
|
+
font-family: Roboto, sans-serif;
|
|
10879
|
+
}
|
|
10880
|
+
|
|
10881
|
+
.${cls} .overlay-title {
|
|
10882
|
+
font-size: 14px;
|
|
10883
|
+
color: var(--owt-color-text, #011627);
|
|
10884
|
+
font-weight: 600;
|
|
10885
|
+
min-width: 0;
|
|
10886
|
+
overflow: hidden;
|
|
10887
|
+
text-overflow: ellipsis;
|
|
10888
|
+
white-space: nowrap;
|
|
10889
|
+
}
|
|
10890
|
+
|
|
10891
|
+
.${cls} .overlay-close {
|
|
10892
|
+
border: 1px solid var(--owt-btn-secondary-border, #C4C4C4);
|
|
10893
|
+
background: var(--owt-btn-secondary-bg, #FFFFFF);
|
|
10894
|
+
color: var(--owt-btn-secondary-color, #011627);
|
|
10895
|
+
border-radius: var(--owt-btn-border-radius, 10px);
|
|
10896
|
+
padding: 6px 10px;
|
|
10897
|
+
font-size: 12px;
|
|
10898
|
+
cursor: pointer;
|
|
10899
|
+
}
|
|
10900
|
+
|
|
10901
|
+
.${cls} .overlay-iframe {
|
|
10902
|
+
flex: 1 1 auto;
|
|
10903
|
+
width: 100%;
|
|
10904
|
+
border: none;
|
|
10905
|
+
}
|
|
10906
|
+
|
|
10582
10907
|
@media (max-width: 640px) {
|
|
10583
10908
|
.${cls} .auth-grid {
|
|
10584
10909
|
grid-template-columns: 1fr;
|
|
@@ -10593,7 +10918,15 @@ const IdAuthenticationWidget = ({ config, schemaData: propSchemaData }) => {
|
|
|
10593
10918
|
max-width: none;
|
|
10594
10919
|
}
|
|
10595
10920
|
}
|
|
10596
|
-
` }), jsxRuntimeExports.
|
|
10921
|
+
` }), jsxRuntimeExports.jsxs("div", { className: cls, children: [overlayUrl ? (jsxRuntimeExports.jsx("div", { className: "overlay-backdrop", role: "dialog", "aria-modal": "true", "aria-label": "Authentication", onClick: (e) => {
|
|
10922
|
+
if (e.target === e.currentTarget) {
|
|
10923
|
+
setOverlayUrl(null);
|
|
10924
|
+
emitHostEvent({ type: 'overlay_closed' });
|
|
10925
|
+
}
|
|
10926
|
+
}, 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: () => {
|
|
10927
|
+
setOverlayUrl(null);
|
|
10928
|
+
emitHostEvent({ type: 'overlay_closed' });
|
|
10929
|
+
}, 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
10930
|
};
|
|
10598
10931
|
|
|
10599
10932
|
/**
|
|
@@ -10625,6 +10958,8 @@ const registerDefaultWidgets = () => {
|
|
|
10625
10958
|
widgetRegistry.register({ widget: 'simple-table', component: SimpleTableWidget });
|
|
10626
10959
|
// Table widget with record-level editing
|
|
10627
10960
|
widgetRegistry.register({ widget: 'table', component: TableWidget });
|
|
10961
|
+
// Table widget with add/edit popup dialog
|
|
10962
|
+
widgetRegistry.register({ widget: 'dialog-table', component: DialogTableWidget });
|
|
10628
10963
|
// Group widgets
|
|
10629
10964
|
widgetRegistry.register({ widget: 'array-widget', component: ArrayWidget });
|
|
10630
10965
|
widgetRegistry.register({ widget: 'iterable-accordion', component: IterableAccordionWidget });
|
|
@@ -11009,6 +11344,7 @@ exports.CheckboxWidget = CheckboxWidget;
|
|
|
11009
11344
|
exports.CurrencyInputWidget = CurrencyInputWidget;
|
|
11010
11345
|
exports.DateInputWidget = DateInputWidget;
|
|
11011
11346
|
exports.DateTimeInputWidget = DateTimeInputWidget;
|
|
11347
|
+
exports.DialogTableWidget = DialogTableWidget;
|
|
11012
11348
|
exports.DisplayWidget = DisplayWidget;
|
|
11013
11349
|
exports.FileInputWidget = FileInputWidget;
|
|
11014
11350
|
exports.HeaderSectionWidget = HeaderSectionWidget;
|