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