@openg2p/registry-widgets 1.1.2-dev.9 → 1.1.3-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -406,9 +406,8 @@ const createZodSchema = (validation, required = false) => {
406
406
  const normalizeBooleanLike = (val) => {
407
407
  if (val === true || val === 1)
408
408
  return true;
409
- if (val === false || val === 0 || val === null || val === undefined || val === '') {
409
+ if (val === false || val === 0)
410
410
  return false;
411
- }
412
411
  if (typeof val === 'string') {
413
412
  const normalized = val.trim().toLowerCase();
414
413
  return normalized === 'true' || normalized === 'yes' || normalized === '1';
@@ -423,8 +422,11 @@ const evaluateCondition = (condition, allValues) => {
423
422
  const { operator, value } = condition;
424
423
  switch (operator) {
425
424
  case 'equals':
426
- if (typeof value === 'boolean' || typeof fieldValue === 'boolean') {
427
- return normalizeBooleanLike(fieldValue) === normalizeBooleanLike(value);
425
+ if (typeof value === 'boolean') {
426
+ return typeof fieldValue === 'boolean' && fieldValue === value;
427
+ }
428
+ if (typeof fieldValue === 'boolean') {
429
+ return fieldValue === normalizeBooleanLike(value);
428
430
  }
429
431
  return fieldValue === value;
430
432
  case 'notEquals':
@@ -2814,6 +2816,8 @@ const useBaseWidget = (options) => {
2814
2816
  const apiService = dataSource?.type === 'api' ? dataSource.service : '';
2815
2817
  const apiEndpoint = dataSource?.type === 'api' ? dataSource.endpoint : '';
2816
2818
  const configKey = `${widgetId}-${isReadonly}-${dataSource?.type || 'none'}-${apiService}-${apiEndpoint}`;
2819
+ // Stable key so inline schemaData objects (e.g. dialog-table fields) don't retrigger loads every render
2820
+ const schemaDataKey = React.useMemo(() => (schemaData ? JSON.stringify(schemaData) : ''), [schemaData]);
2817
2821
  // Extract dependency value using a granular selector to prevent unnecessary re-renders
2818
2822
  // and infinite loops when other unrelated values in the state change.
2819
2823
  const dependencyValue = reactRedux.useSelector((state) => {
@@ -2931,7 +2935,7 @@ const useBaseWidget = (options) => {
2931
2935
  loadDataSource();
2932
2936
  // Use configKey and dependencyValue to ensure effect runs only when relevant state changes
2933
2937
  // eslint-disable-next-line react-hooks/exhaustive-deps
2934
- }, [configKey, dependencyValue, dataSourceRequestHandler, schemaData, widgetId, dispatch]);
2938
+ }, [configKey, dependencyValue, dataSourceRequestHandler, schemaDataKey, widgetId, dispatch]);
2935
2939
  const geoDisplayLabel = React.useMemo(() => {
2936
2940
  if (!geoConfig) {
2937
2941
  return undefined;
@@ -10087,6 +10091,56 @@ const TableWidget = ({ config }) => {
10087
10091
  };
10088
10092
 
10089
10093
  const isUnsetRowValue = (value) => value === null || value === undefined || value === '';
10094
+ const buildDialogConditionValues = (row, columns) => {
10095
+ let context = { ...row };
10096
+ columns.forEach((col) => {
10097
+ const columnKey = col['column-key'];
10098
+ if (!columnKey || row[columnKey] === undefined) {
10099
+ return;
10100
+ }
10101
+ const dataPath = col['widget-data-path'];
10102
+ if (typeof dataPath === 'string' && dataPath) {
10103
+ context = setValueByPath(context, dataPath, row[columnKey]);
10104
+ }
10105
+ });
10106
+ return context;
10107
+ };
10108
+ const buildDialogColumnSegments = (columns) => {
10109
+ const segments = [];
10110
+ let index = 0;
10111
+ while (index < columns.length) {
10112
+ const group = columns[index]['column-group'];
10113
+ if (group) {
10114
+ const groupCols = [];
10115
+ while (index < columns.length && columns[index]['column-group'] === group) {
10116
+ groupCols.push(columns[index]);
10117
+ index += 1;
10118
+ }
10119
+ segments.push({ type: 'group', group, cols: groupCols });
10120
+ }
10121
+ else {
10122
+ segments.push({ type: 'single', col: columns[index] });
10123
+ index += 1;
10124
+ }
10125
+ }
10126
+ return segments;
10127
+ };
10128
+ /** Match TableWidget cell styling for add / update / delete rows */
10129
+ const getRowCellStyle = (editAction) => {
10130
+ if (editAction === 'ADD') {
10131
+ return { color: 'var(--owt-color-success, #16A34A)' };
10132
+ }
10133
+ if (editAction === 'DELETE') {
10134
+ return {
10135
+ color: 'var(--owt-color-error, #B91C1C)',
10136
+ textDecoration: 'line-through',
10137
+ };
10138
+ }
10139
+ if (editAction === 'UPDATE') {
10140
+ return { color: 'var(--owt-color-warning, #F59E0B)' };
10141
+ }
10142
+ return {};
10143
+ };
10090
10144
  // Display select value label in view mode
10091
10145
  const SelectDisplayValue = ({ config, value }) => {
10092
10146
  const { dataSourceOptions, loading } = useBaseWidget({ config });
@@ -10097,23 +10151,29 @@ const SelectDisplayValue = ({ config, value }) => {
10097
10151
  const selectedOption = dataSourceOptions.find((option) => option.value === value || String(option.value) === String(value));
10098
10152
  return jsxRuntimeExports.jsx("span", { children: selectedOption ? selectedOption.label : String(value) });
10099
10153
  };
10154
+ /** Isolated dialog field — avoids re-running data-source effects when sibling fields update. */
10155
+ const DialogTableField = React.memo(function DialogTableField({ col, cellWidgetId, dialogConditionValues, isReadonly, }) {
10156
+ const widgetType = col.widget || 'text';
10157
+ const fieldConfig = React.useMemo(() => {
10158
+ return {
10159
+ ...col,
10160
+ widget: widgetType,
10161
+ 'widget-type': col['widget-type'] || 'input',
10162
+ 'widget-id': cellWidgetId,
10163
+ 'widget-label': col['widget-label'],
10164
+ 'widget-readonly': isReadonly || col['widget-readonly'] === true,
10165
+ 'widget-data-path': undefined,
10166
+ 'widget-data-default': col['widget-data-default'],
10167
+ 'widget-data-options': undefined,
10168
+ 'widget-required': shouldRequireWidget(col['widget-data-options'], dialogConditionValues, col['widget-required']),
10169
+ };
10170
+ }, [col, cellWidgetId, dialogConditionValues, isReadonly, widgetType]);
10171
+ return (jsxRuntimeExports.jsx("div", { className: "min-w-0", children: jsxRuntimeExports.jsx(WidgetRenderer, { config: fieldConfig }) }));
10172
+ });
10100
10173
  /**
10101
10174
  * Dialog table widget:
10102
10175
  * - Table displays a subset of columns (n out of x)
10103
10176
  * - Add/Edit happens in a modal dialog that shows ALL columns as a form
10104
- *
10105
- * Usage in schema:
10106
- * {
10107
- * "widget": "dialog-table",
10108
- * "widget-type": "table",
10109
- * "widget-label": "Household Members",
10110
- * "widget-id": "householdMembers",
10111
- * "widget-data-path": "household.members",
10112
- * "widget-data-columns": [ ...all columns... ],
10113
- * "widget-data-visible-columns": ["firstName", "lastName", "dob"], // optional override; default = by column flag
10114
- * // Per-column control (recommended): set "column-visible-in-table": false to hide it in the table
10115
- * "widget-data-operations": { "add": true, "edit": true, "remove": true }
10116
- * }
10117
10177
  */
10118
10178
  const DialogTableWidget = ({ config }) => {
10119
10179
  const { value, error, touched, isEnabled, onChange, config: widgetConfig } = useBaseWidget({ config });
@@ -10123,23 +10183,22 @@ const DialogTableWidget = ({ config }) => {
10123
10183
  const columns = widgetConfig['widget-data-columns'] || [];
10124
10184
  const operations = widgetConfig['widget-data-operations'] || {};
10125
10185
  const isReadonly = widgetConfig['widget-readonly'] || false;
10186
+ // Soft-delete (keep row, red + strikethrough) whenever remove is allowed — matches TableWidget
10187
+ const shouldSoftDeleteOnRemove = !isReadonly && !!operations.remove;
10126
10188
  const visibleColumnKeys = widgetConfig['widget-data-visible-columns'];
10127
10189
  const visibleColumns = React.useMemo(() => {
10128
- // 1) If explicit list provided, it wins
10129
10190
  if (Array.isArray(visibleColumnKeys) && visibleColumnKeys.length > 0) {
10130
10191
  const keySet = new Set(visibleColumnKeys);
10131
10192
  return columns.filter((c) => keySet.has(c['column-key']));
10132
10193
  }
10133
- // 2) Otherwise decide per column (default = visible)
10134
10194
  return columns.filter((c) => c['column-visible-in-table'] !== false);
10135
10195
  }, [columns, visibleColumnKeys]);
10136
10196
  const [dialogOpen, setDialogOpen] = React.useState(false);
10137
10197
  const [dialogMode, setDialogMode] = React.useState('add');
10138
10198
  const [activeRowIndex, setActiveRowIndex] = React.useState(null);
10139
- const [formData, setFormData] = React.useState({});
10140
- /** Unique per dialog open so Redux widget ids don't reuse stale values across rows/add sessions */
10141
10199
  const dialogSessionRef = React.useRef(0);
10142
10200
  const [dialogSessionId, setDialogSessionId] = React.useState(0);
10201
+ const membersWidgetId = widgetConfig['widget-id'];
10143
10202
  const addDialogTitle = translateConfig(widgetConfig['widget-data-dialog-title-add']) ||
10144
10203
  translate('table.addRecordDialog') ||
10145
10204
  'Add record';
@@ -10159,15 +10218,26 @@ const DialogTableWidget = ({ config }) => {
10159
10218
  });
10160
10219
  return emptyRow;
10161
10220
  }, [columns]);
10162
- const dialogFieldWidgetId = React.useCallback((columnKey) => `${widgetConfig['widget-id']}-dlg-${dialogSessionId}-${columnKey}`, [widgetConfig, dialogSessionId]);
10221
+ const dialogFieldWidgetId = React.useCallback((sessionId, columnKey) => `${membersWidgetId}-dlg-${sessionId}-${columnKey}`, [membersWidgetId]);
10163
10222
  const resetDialogWidgets = React.useCallback((sessionId) => {
10164
10223
  if (sessionId <= 0)
10165
10224
  return;
10166
10225
  columns.forEach((col) => {
10167
- const wid = `${widgetConfig['widget-id']}-dlg-${sessionId}-${col['column-key']}`;
10168
- dispatch(resetWidget(wid));
10226
+ dispatch(resetWidget(dialogFieldWidgetId(sessionId, col['column-key'])));
10169
10227
  });
10170
- }, [columns, widgetConfig, dispatch]);
10228
+ }, [columns, dialogFieldWidgetId, dispatch]);
10229
+ const seedDialogReduxValues = React.useCallback((sessionId, rowData) => {
10230
+ const seeds = {};
10231
+ columns.forEach((col) => {
10232
+ const key = col['column-key'];
10233
+ if (rowData[key] !== undefined) {
10234
+ seeds[dialogFieldWidgetId(sessionId, key)] = rowData[key];
10235
+ }
10236
+ });
10237
+ if (Object.keys(seeds).length > 0) {
10238
+ dispatch(setValues(seeds));
10239
+ }
10240
+ }, [columns, dialogFieldWidgetId, dispatch]);
10171
10241
  const beginDialogSession = React.useCallback(() => {
10172
10242
  dialogSessionRef.current += 1;
10173
10243
  const nextSession = dialogSessionRef.current;
@@ -10176,15 +10246,21 @@ const DialogTableWidget = ({ config }) => {
10176
10246
  }, []);
10177
10247
  const openAddDialog = React.useCallback(() => {
10178
10248
  resetDialogWidgets(dialogSessionId);
10179
- beginDialogSession();
10249
+ const sessionId = beginDialogSession();
10250
+ seedDialogReduxValues(sessionId, buildEmptyRow());
10180
10251
  setDialogMode('add');
10181
10252
  setActiveRowIndex(null);
10182
- setFormData(buildEmptyRow());
10183
10253
  setDialogOpen(true);
10184
- }, [buildEmptyRow, beginDialogSession, resetDialogWidgets, dialogSessionId]);
10254
+ }, [
10255
+ buildEmptyRow,
10256
+ beginDialogSession,
10257
+ resetDialogWidgets,
10258
+ dialogSessionId,
10259
+ seedDialogReduxValues,
10260
+ ]);
10185
10261
  const openEditDialog = React.useCallback((rowIndex) => {
10186
10262
  resetDialogWidgets(dialogSessionId);
10187
- beginDialogSession();
10263
+ const sessionId = beginDialogSession();
10188
10264
  const row = rows[rowIndex] || {};
10189
10265
  const nextFormData = buildEmptyRow();
10190
10266
  columns.forEach((col) => {
@@ -10192,23 +10268,26 @@ const DialogTableWidget = ({ config }) => {
10192
10268
  if (row[key] !== undefined)
10193
10269
  nextFormData[key] = row[key];
10194
10270
  });
10271
+ seedDialogReduxValues(sessionId, nextFormData);
10195
10272
  setDialogMode('edit');
10196
10273
  setActiveRowIndex(rowIndex);
10197
- setFormData(nextFormData);
10198
10274
  setDialogOpen(true);
10199
- }, [rows, columns, buildEmptyRow, resetDialogWidgets, dialogSessionId, beginDialogSession]);
10275
+ }, [
10276
+ rows,
10277
+ columns,
10278
+ buildEmptyRow,
10279
+ resetDialogWidgets,
10280
+ dialogSessionId,
10281
+ beginDialogSession,
10282
+ seedDialogReduxValues,
10283
+ ]);
10200
10284
  const closeDialog = React.useCallback(() => {
10201
10285
  const sessionToClear = dialogSessionId;
10202
10286
  setDialogOpen(false);
10203
10287
  setActiveRowIndex(null);
10204
- setFormData({});
10205
10288
  resetDialogWidgets(sessionToClear);
10206
10289
  setDialogSessionId(0);
10207
10290
  }, [dialogSessionId, resetDialogWidgets]);
10208
- const updateField = React.useCallback((columnKey, newValue) => {
10209
- setFormData((prev) => ({ ...prev, [columnKey]: newValue }));
10210
- }, []);
10211
- const membersWidgetId = widgetConfig['widget-id'];
10212
10291
  const dialogStoreValues = reactRedux.useSelector((state) => {
10213
10292
  if (dialogSessionId <= 0) {
10214
10293
  return {};
@@ -10217,30 +10296,22 @@ const DialogTableWidget = ({ config }) => {
10217
10296
  const row = {};
10218
10297
  columns.forEach((col) => {
10219
10298
  const k = col['column-key'];
10220
- const wid = `${membersWidgetId}-dlg-${dialogSessionId}-${k}`;
10299
+ const wid = dialogFieldWidgetId(dialogSessionId, k);
10221
10300
  if (values[wid] !== undefined) {
10222
10301
  row[k] = values[wid];
10223
10302
  }
10224
10303
  });
10225
10304
  return row;
10226
- }, (a, b) => JSON.stringify(a) === JSON.stringify(b));
10227
- const buildDialogRowValues = React.useCallback((storeSlice) => {
10228
- const row = { ...formData };
10229
- columns.forEach((col) => {
10230
- const k = col['column-key'];
10231
- if (storeSlice[k] !== undefined) {
10232
- row[k] = storeSlice[k];
10233
- }
10234
- });
10235
- return row;
10236
- }, [formData, columns]);
10237
- const dialogRowValues = React.useMemo(() => buildDialogRowValues(dialogStoreValues), [buildDialogRowValues, dialogStoreValues]);
10238
- const collectMergedRowPayload = React.useCallback(() => buildDialogRowValues(dialogStoreValues), [buildDialogRowValues, dialogStoreValues]);
10305
+ });
10306
+ const dialogRowValues = dialogStoreValues;
10307
+ const dialogConditionValues = React.useMemo(() => buildDialogConditionValues(dialogRowValues, columns), [dialogRowValues, columns]);
10308
+ const collectMergedRowPayload = React.useCallback(() => dialogStoreValues, [dialogStoreValues]);
10239
10309
  const finalizeDialogRowPayload = React.useCallback((raw) => {
10310
+ const conditionValues = buildDialogConditionValues(raw, columns);
10240
10311
  const result = {};
10241
10312
  columns.forEach((col) => {
10242
10313
  const key = col['column-key'];
10243
- if (!shouldShowWidget(col['widget-data-options'], raw)) {
10314
+ if (!shouldShowWidget(col['widget-data-options'], conditionValues)) {
10244
10315
  return;
10245
10316
  }
10246
10317
  const val = raw[key];
@@ -10252,17 +10323,18 @@ const DialogTableWidget = ({ config }) => {
10252
10323
  }, [columns]);
10253
10324
  const saveDialog = React.useCallback(() => {
10254
10325
  const payload = collectMergedRowPayload();
10326
+ const conditionValues = buildDialogConditionValues(payload, columns);
10255
10327
  let hasErrors = false;
10256
10328
  columns.forEach((col) => {
10257
10329
  const key = col['column-key'];
10258
- const cellWidgetId = dialogFieldWidgetId(key);
10330
+ const cellWidgetId = dialogFieldWidgetId(dialogSessionId, key);
10259
10331
  const isColReadonly = isReadonly || col['widget-readonly'] === true;
10260
10332
  if (isColReadonly)
10261
10333
  return;
10262
- if (!shouldShowWidget(col['widget-data-options'], payload))
10334
+ if (!shouldShowWidget(col['widget-data-options'], conditionValues))
10263
10335
  return;
10264
10336
  const cellValue = payload[key];
10265
- const isRequired = shouldRequireWidget(col['widget-data-options'], payload, col['widget-required']);
10337
+ const isRequired = shouldRequireWidget(col['widget-data-options'], conditionValues, col['widget-required']);
10266
10338
  const validationErrors = validateWidget(cellValue, col['widget-data-validation'], isRequired);
10267
10339
  if (validationErrors && validationErrors.length > 0) {
10268
10340
  hasErrors = true;
@@ -10299,11 +10371,32 @@ const DialogTableWidget = ({ config }) => {
10299
10371
  onChange(newRows);
10300
10372
  closeDialog();
10301
10373
  }
10302
- }, [collectMergedRowPayload, finalizeDialogRowPayload, dialogMode, onChange, rows, closeDialog, activeRowIndex, columns, dialogFieldWidgetId, isReadonly, dispatch]);
10374
+ }, [
10375
+ collectMergedRowPayload,
10376
+ finalizeDialogRowPayload,
10377
+ dialogMode,
10378
+ onChange,
10379
+ rows,
10380
+ closeDialog,
10381
+ activeRowIndex,
10382
+ columns,
10383
+ dialogSessionId,
10384
+ dialogFieldWidgetId,
10385
+ isReadonly,
10386
+ dispatch,
10387
+ ]);
10303
10388
  const deleteRow = React.useCallback((rowIndex) => {
10304
- const newRows = rows.filter((_, i) => i !== rowIndex);
10305
- onChange(newRows);
10306
- }, [rows, onChange]);
10389
+ if (shouldSoftDeleteOnRemove) {
10390
+ const newRows = [...rows];
10391
+ newRows[rowIndex] = {
10392
+ ...newRows[rowIndex],
10393
+ edit_action: 'DELETE',
10394
+ };
10395
+ onChange(newRows);
10396
+ return;
10397
+ }
10398
+ onChange(rows.filter((_, i) => i !== rowIndex));
10399
+ }, [rows, onChange, shouldSoftDeleteOnRemove]);
10307
10400
  const getDisplayValue = React.useCallback((rowIndex, column) => {
10308
10401
  const key = column['column-key'];
10309
10402
  const cellValue = rows[rowIndex]?.[key];
@@ -10311,11 +10404,33 @@ const DialogTableWidget = ({ config }) => {
10311
10404
  if (cellValue === null || cellValue === undefined || cellValue === '')
10312
10405
  return '-';
10313
10406
  if (widgetType === 'select')
10314
- return null; // handled by SelectDisplayValue
10407
+ return null;
10315
10408
  if (column['widget-data-format'])
10316
10409
  return formatValue(cellValue, column['widget-data-format'], column.widget);
10317
10410
  return String(cellValue);
10318
10411
  }, [rows]);
10412
+ const dialogColumnSegments = React.useMemo(() => {
10413
+ return buildDialogColumnSegments(columns)
10414
+ .map((segment) => {
10415
+ if (segment.type === 'single') {
10416
+ if (!shouldShowWidget(segment.col['widget-data-options'], dialogConditionValues)) {
10417
+ return null;
10418
+ }
10419
+ return segment;
10420
+ }
10421
+ const visibleCols = segment.cols.filter((col) => shouldShowWidget(col['widget-data-options'], dialogConditionValues));
10422
+ if (visibleCols.length === 0) {
10423
+ return null;
10424
+ }
10425
+ return { type: 'group', group: segment.group, cols: visibleCols };
10426
+ })
10427
+ .filter((segment) => segment !== null);
10428
+ }, [columns, dialogConditionValues]);
10429
+ const renderDialogField = (col) => {
10430
+ const key = col['column-key'];
10431
+ const cellWidgetId = dialogFieldWidgetId(dialogSessionId, key);
10432
+ return (jsxRuntimeExports.jsx(DialogTableField, { col: col, cellWidgetId: cellWidgetId, dialogConditionValues: dialogConditionValues, isReadonly: isReadonly }, `${dialogSessionId}-${key}`));
10433
+ };
10319
10434
  const tableWidgetId = `dialog-table-widget-${widgetConfig['widget-id']}`;
10320
10435
  const columnSpan = widgetConfig['widget-column-span'] || 2;
10321
10436
  const minWidth = columnSpan * 200;
@@ -10343,37 +10458,40 @@ const DialogTableWidget = ({ config }) => {
10343
10458
  }, children: translate('table.addRecord') || 'Add New Record' }) })), jsxRuntimeExports.jsx("div", { className: "overflow-x-auto border", style: {
10344
10459
  borderRadius: 'var(--owt-widget-table-border-radius, 15px)',
10345
10460
  borderColor: 'var(--owt-widget-table-border-color, #C4C4C4)',
10346
- }, 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: {
10347
- borderBottom: '1px solid var(--owt-widget-table-row-divider, #E4E4E4)',
10348
- backgroundColor: row?.edit_action === 'DELETE'
10349
- ? 'var(--owt-widget-table-deleted-row-bg, #FEE2E2)'
10350
- : undefined,
10351
- }, children: [visibleColumns.map((col) => {
10352
- const key = col['column-key'];
10353
- const widgetType = col.widget || 'text';
10354
- const displayValue = getDisplayValue(rowIndex, col);
10355
- if (widgetType === 'select' && displayValue === null) {
10356
- const displayConfig = {
10357
- ...col,
10358
- 'widget-id': `${widgetConfig['widget-id']}-view-row-${rowIndex}-col-${key}`,
10359
- 'widget-label': '',
10360
- 'widget-readonly': true,
10361
- 'widget-data-path': undefined,
10362
- };
10363
- 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));
10364
- }
10365
- return (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: jsxRuntimeExports.jsx("div", { className: "text-sm", children: displayValue }) }, key));
10366
- }), ((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: {
10367
- borderRadius: 'var(--owt-btn-border-radius, 10px)',
10368
- color: 'var(--owt-color-primary-dark, #F07B1A)',
10369
- backgroundColor: 'transparent',
10370
- border: 'none',
10371
- }, 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: {
10372
- borderRadius: 'var(--owt-btn-border-radius, 10px)',
10373
- color: 'var(--owt-color-error, #B91C1C)',
10374
- backgroundColor: 'transparent',
10375
- border: 'none',
10376
- }, 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: {
10461
+ }, 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) => {
10462
+ const cellStyle = getRowCellStyle(row?.edit_action);
10463
+ return (jsxRuntimeExports.jsxs("tr", { style: {
10464
+ borderBottom: '1px solid var(--owt-widget-table-row-divider, #E4E4E4)',
10465
+ backgroundColor: row?.edit_action === 'DELETE'
10466
+ ? 'var(--owt-widget-table-deleted-row-bg, #FEE2E2)'
10467
+ : undefined,
10468
+ }, children: [visibleColumns.map((col) => {
10469
+ const key = col['column-key'];
10470
+ const widgetType = col.widget || 'text';
10471
+ const displayValue = getDisplayValue(rowIndex, col);
10472
+ if (widgetType === 'select' && displayValue === null) {
10473
+ const displayConfig = {
10474
+ ...col,
10475
+ 'widget-id': `${widgetConfig['widget-id']}-view-row-${rowIndex}-col-${key}`,
10476
+ 'widget-label': '',
10477
+ 'widget-readonly': true,
10478
+ 'widget-data-path': undefined,
10479
+ };
10480
+ return (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: jsxRuntimeExports.jsx("div", { className: "text-sm", style: cellStyle, children: jsxRuntimeExports.jsx(SelectDisplayValue, { config: displayConfig, value: row?.[key] }) }) }, key));
10481
+ }
10482
+ return (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: jsxRuntimeExports.jsx("div", { className: "text-sm", style: cellStyle, children: displayValue }) }, key));
10483
+ }), ((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: {
10484
+ borderRadius: 'var(--owt-btn-border-radius, 10px)',
10485
+ color: 'var(--owt-color-primary-dark, #F07B1A)',
10486
+ backgroundColor: 'transparent',
10487
+ border: 'none',
10488
+ }, 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: {
10489
+ borderRadius: 'var(--owt-btn-border-radius, 10px)',
10490
+ color: 'var(--owt-color-error, #B91C1C)',
10491
+ backgroundColor: 'transparent',
10492
+ border: 'none',
10493
+ }, children: translate('common.remove') || 'Delete' }))] }) }))] }, rowIndex));
10494
+ })] })] }) }), 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: {
10377
10495
  maxWidth: '900px',
10378
10496
  backgroundColor: 'var(--owt-color-bg, #FFFFFF)',
10379
10497
  borderRadius: 'var(--owt-widget-card-border-radius, 20px)',
@@ -10384,27 +10502,11 @@ const DialogTableWidget = ({ config }) => {
10384
10502
  cursor: 'pointer',
10385
10503
  fontSize: '20px',
10386
10504
  lineHeight: 1,
10387
- }, "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) => {
10388
- const key = col['column-key'];
10389
- if (!shouldShowWidget(col['widget-data-options'], dialogRowValues)) {
10390
- return null;
10505
+ }, "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: dialogColumnSegments.map((segment) => {
10506
+ if (segment.type === 'single') {
10507
+ return renderDialogField(segment.col);
10391
10508
  }
10392
- const widgetType = col.widget || 'text';
10393
- const cellWidgetId = dialogFieldWidgetId(key);
10394
- const initialValue = formData[key] ?? col['widget-data-default'];
10395
- const fieldConfig = {
10396
- ...col,
10397
- widget: widgetType,
10398
- 'widget-type': col['widget-type'] || 'input',
10399
- 'widget-id': cellWidgetId,
10400
- 'widget-label': col['widget-label'],
10401
- 'widget-readonly': isReadonly || col['widget-readonly'] === true,
10402
- 'widget-data-path': undefined,
10403
- 'widget-data-default': initialValue,
10404
- 'widget-data-options': undefined,
10405
- 'widget-required': shouldRequireWidget(col['widget-data-options'], dialogRowValues, col['widget-required']),
10406
- };
10407
- return (jsxRuntimeExports.jsx("div", { className: "min-w-0", children: jsxRuntimeExports.jsx(WidgetRenderer, { config: fieldConfig, schemaData: { [cellWidgetId]: initialValue }, onValueChange: (_widgetId, newValue) => updateField(key, newValue) }) }, `${dialogSessionId}-${key}`));
10509
+ return (jsxRuntimeExports.jsx("div", { className: "md:col-span-2 grid grid-cols-1 md:grid-cols-2 gap-4", children: segment.cols.map((col) => renderDialogField(col)) }, `${dialogSessionId}-group-${segment.group}`));
10408
10510
  }) }, `dialog-fields-${dialogSessionId}`), jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-3 mt-6", children: [jsxRuntimeExports.jsx("button", { type: "button", onClick: closeDialog, className: "px-4 py-2 text-sm font-medium", style: {
10409
10511
  borderRadius: 'var(--owt-btn-border-radius, 10px)',
10410
10512
  border: '1px solid var(--owt-btn-secondary-border, #C4C4C4)',