@openg2p/registry-widgets 1.1.2-dev.8 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/SectionRenderer.d.ts.map +1 -1
- package/dist/hooks/useBaseWidget.d.ts.map +1 -1
- package/dist/hooks/useGeoWidgetCascade.d.ts.map +1 -1
- package/dist/index.d.ts +35 -15
- package/dist/index.esm.js +313 -172
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +319 -170
- package/dist/index.js.map +1 -1
- package/dist/utils/geoHierarchy.d.ts +33 -0
- package/dist/utils/geoHierarchy.d.ts.map +1 -1
- package/dist/widgets/DialogTableWidget.d.ts +0 -13
- package/dist/widgets/DialogTableWidget.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2244,12 +2244,145 @@ const geoHierarchyBuilder = new GeoHierarchyBuilder();
|
|
|
2244
2244
|
/** Sentinel written to Redux when a geo level is cleared by cascade (distinct from "never set"). */
|
|
2245
2245
|
const GEO_LEVEL_CLEARED = null;
|
|
2246
2246
|
const geoWidgetParentRegistry = new Map();
|
|
2247
|
+
const geoWidgetConfigRegistry = new Map();
|
|
2247
2248
|
function registerGeoWidgetParent(widgetId, parentWidgetId) {
|
|
2248
2249
|
geoWidgetParentRegistry.set(widgetId, parentWidgetId || null);
|
|
2249
2250
|
}
|
|
2250
2251
|
function unregisterGeoWidgetParent(widgetId) {
|
|
2251
2252
|
geoWidgetParentRegistry.delete(widgetId);
|
|
2252
2253
|
}
|
|
2254
|
+
function registerGeoWidget(widgetId, geoConfig, dataPath) {
|
|
2255
|
+
if (typeof dataPath !== 'string') {
|
|
2256
|
+
return;
|
|
2257
|
+
}
|
|
2258
|
+
const parentWidgetId = geoConfig.parentWidgetId?.trim() ? geoConfig.parentWidgetId : null;
|
|
2259
|
+
registerGeoWidgetParent(widgetId, parentWidgetId);
|
|
2260
|
+
geoWidgetConfigRegistry.set(widgetId, {
|
|
2261
|
+
widgetId,
|
|
2262
|
+
parentWidgetId,
|
|
2263
|
+
level: geoConfig.level,
|
|
2264
|
+
geoConfig,
|
|
2265
|
+
dataPath,
|
|
2266
|
+
groupId: getGeoGroupId(dataPath),
|
|
2267
|
+
});
|
|
2268
|
+
}
|
|
2269
|
+
function unregisterGeoWidget(widgetId) {
|
|
2270
|
+
unregisterGeoWidgetParent(widgetId);
|
|
2271
|
+
geoWidgetConfigRegistry.delete(widgetId);
|
|
2272
|
+
}
|
|
2273
|
+
function orderGeoWidgetRegistrations(registrations) {
|
|
2274
|
+
if (registrations.length <= 1) {
|
|
2275
|
+
return registrations;
|
|
2276
|
+
}
|
|
2277
|
+
const roots = registrations.filter((entry) => !entry.parentWidgetId);
|
|
2278
|
+
if (roots.length === 0) {
|
|
2279
|
+
return registrations;
|
|
2280
|
+
}
|
|
2281
|
+
const ordered = [];
|
|
2282
|
+
let current = roots[0];
|
|
2283
|
+
const visited = new Set();
|
|
2284
|
+
while (current && !visited.has(current.widgetId)) {
|
|
2285
|
+
visited.add(current.widgetId);
|
|
2286
|
+
ordered.push(current);
|
|
2287
|
+
current = registrations.find((entry) => entry.parentWidgetId === current.widgetId);
|
|
2288
|
+
}
|
|
2289
|
+
return ordered.length > 0 ? ordered : registrations;
|
|
2290
|
+
}
|
|
2291
|
+
function resolveLevelValueId(rawValue) {
|
|
2292
|
+
if (rawValue === null || rawValue === undefined || rawValue === '') {
|
|
2293
|
+
return null;
|
|
2294
|
+
}
|
|
2295
|
+
if (typeof rawValue === 'string' || typeof rawValue === 'number') {
|
|
2296
|
+
return String(rawValue);
|
|
2297
|
+
}
|
|
2298
|
+
if (typeof rawValue === 'object') {
|
|
2299
|
+
const id = rawValue.level_value_id || rawValue.id || rawValue.value;
|
|
2300
|
+
return id != null && id !== '' ? String(id) : null;
|
|
2301
|
+
}
|
|
2302
|
+
return null;
|
|
2303
|
+
}
|
|
2304
|
+
function resolveStoredMnemonic(values, registration, valueId) {
|
|
2305
|
+
const stored = getWidgetValue(values, registration.dataPath, registration.widgetId);
|
|
2306
|
+
const hierarchy = stored?.hierarchy || stored?.geo_code_hierarchy_json?.hierarchy;
|
|
2307
|
+
if (!Array.isArray(hierarchy)) {
|
|
2308
|
+
return undefined;
|
|
2309
|
+
}
|
|
2310
|
+
const levelData = hierarchy.find((entry) => entry.level === registration.level);
|
|
2311
|
+
if (levelData && String(levelData.level_value_id) === String(valueId)) {
|
|
2312
|
+
return levelData.level_value_mnemonic ? String(levelData.level_value_mnemonic) : undefined;
|
|
2313
|
+
}
|
|
2314
|
+
return undefined;
|
|
2315
|
+
}
|
|
2316
|
+
/** Resolve display mnemonic from cached dropdown options, then stored hierarchy. */
|
|
2317
|
+
function createGeoLevelMnemonicResolver(values, dataSources) {
|
|
2318
|
+
return (registration, valueId) => {
|
|
2319
|
+
const options = dataSources[registration.widgetId];
|
|
2320
|
+
const option = options?.find((entry) => String(entry.value) === String(valueId));
|
|
2321
|
+
if (option?.label) {
|
|
2322
|
+
return option.label;
|
|
2323
|
+
}
|
|
2324
|
+
return resolveStoredMnemonic(values, registration, valueId);
|
|
2325
|
+
};
|
|
2326
|
+
}
|
|
2327
|
+
/** Rebuild group hierarchy from widget values in parent→child order; stop at first missing level. */
|
|
2328
|
+
function rebuildGeoHierarchyFromRegistrations(groupId, values, registrations, resolveMnemonic) {
|
|
2329
|
+
const ordered = orderGeoWidgetRegistrations(registrations.filter((entry) => entry.groupId === groupId));
|
|
2330
|
+
geoHierarchyBuilder.clear(groupId);
|
|
2331
|
+
for (const registration of ordered) {
|
|
2332
|
+
const rawValue = resolveGeoWidgetLevelValue(values, registration.widgetId, registration.dataPath, registration.geoConfig);
|
|
2333
|
+
const valueId = resolveLevelValueId(rawValue);
|
|
2334
|
+
if (!valueId) {
|
|
2335
|
+
break;
|
|
2336
|
+
}
|
|
2337
|
+
const mnemonic = resolveMnemonic?.(registration, valueId) ??
|
|
2338
|
+
resolveStoredMnemonic(values, registration, valueId) ??
|
|
2339
|
+
valueId;
|
|
2340
|
+
geoHierarchyBuilder.addLevel(registration.level, valueId, mnemonic, groupId);
|
|
2341
|
+
}
|
|
2342
|
+
return geoHierarchyBuilder.buildHierarchyJson(groupId) !== null;
|
|
2343
|
+
}
|
|
2344
|
+
function collectGeoWidgetRegistrationsFromWidgets(widgets, namespace) {
|
|
2345
|
+
return widgets
|
|
2346
|
+
.filter((widget) => widget['widget-geo-config'] && typeof widget['widget-data-path'] === 'string')
|
|
2347
|
+
.map((widget) => {
|
|
2348
|
+
const originalWidgetId = widget['widget-id'];
|
|
2349
|
+
const originalDataPath = widget['widget-data-path'];
|
|
2350
|
+
const geoConfig = widget['widget-geo-config'];
|
|
2351
|
+
const widgetId = namespace ? `${namespace}__${originalWidgetId}` : originalWidgetId;
|
|
2352
|
+
const parentWidgetId = geoConfig.parentWidgetId?.trim()
|
|
2353
|
+
? (namespace ? `${namespace}__${geoConfig.parentWidgetId}` : geoConfig.parentWidgetId)
|
|
2354
|
+
: null;
|
|
2355
|
+
const dataPath = namespace ? `${namespace}.${originalDataPath}` : originalDataPath;
|
|
2356
|
+
return {
|
|
2357
|
+
widgetId,
|
|
2358
|
+
parentWidgetId,
|
|
2359
|
+
level: geoConfig.level,
|
|
2360
|
+
geoConfig,
|
|
2361
|
+
dataPath,
|
|
2362
|
+
groupId: getGeoGroupId(dataPath),
|
|
2363
|
+
};
|
|
2364
|
+
});
|
|
2365
|
+
}
|
|
2366
|
+
/** Reconcile all geo groups in section values before save. */
|
|
2367
|
+
function reconcileGeoHierarchiesInValues(values, registrations, dataSources = {}) {
|
|
2368
|
+
const groupIds = [...new Set(registrations.map((entry) => entry.groupId))];
|
|
2369
|
+
let updatedValues = values;
|
|
2370
|
+
const resolveMnemonic = createGeoLevelMnemonicResolver(updatedValues, dataSources);
|
|
2371
|
+
for (const groupId of groupIds) {
|
|
2372
|
+
const groupRegistrations = registrations.filter((entry) => entry.groupId === groupId);
|
|
2373
|
+
const dataPath = groupRegistrations[0]?.dataPath;
|
|
2374
|
+
const widgetId = groupRegistrations[0]?.widgetId;
|
|
2375
|
+
if (!dataPath || !widgetId) {
|
|
2376
|
+
continue;
|
|
2377
|
+
}
|
|
2378
|
+
rebuildGeoHierarchyFromRegistrations(groupId, updatedValues, groupRegistrations, resolveMnemonic);
|
|
2379
|
+
updatedValues = applySharedGeoHierarchyToValues(updatedValues, groupId, dataPath, widgetId);
|
|
2380
|
+
}
|
|
2381
|
+
return updatedValues;
|
|
2382
|
+
}
|
|
2383
|
+
function getGeoWidgetRegistrationsInGroup(groupId) {
|
|
2384
|
+
return orderGeoWidgetRegistrations([...geoWidgetConfigRegistry.values()].filter((entry) => entry.groupId === groupId));
|
|
2385
|
+
}
|
|
2253
2386
|
/** True when changedWidgetId is any upstream geo parent of widgetId (not only immediate parent). */
|
|
2254
2387
|
function isUpstreamGeoAncestor(changedWidgetId, widgetId, immediateParentWidgetId) {
|
|
2255
2388
|
if (changedWidgetId === widgetId) {
|
|
@@ -2344,7 +2477,7 @@ function resetAndSeedGeoHierarchyFromValues(values, dataPath, widgetId, groupId)
|
|
|
2344
2477
|
|
|
2345
2478
|
// Define stable empty arrays to avoid selector reference issues
|
|
2346
2479
|
const EMPTY_ERRORS = [];
|
|
2347
|
-
const EMPTY_DATA_SOURCE
|
|
2480
|
+
const EMPTY_DATA_SOURCE = [];
|
|
2348
2481
|
const useBaseWidget = (options) => {
|
|
2349
2482
|
const { config, dataSourceRequestHandler: propHandler, schemaData, onValueChange } = options;
|
|
2350
2483
|
const dispatch = reactRedux.useDispatch();
|
|
@@ -2359,7 +2492,7 @@ const useBaseWidget = (options) => {
|
|
|
2359
2492
|
const errors = reactRedux.useSelector((state) => state.widget.errors[widgetId] ?? EMPTY_ERRORS);
|
|
2360
2493
|
const touched = reactRedux.useSelector((state) => state.widget.touched[widgetId] || false);
|
|
2361
2494
|
const loading = reactRedux.useSelector((state) => state.widget.loading[widgetId] || false);
|
|
2362
|
-
const dataSourceOptions = reactRedux.useSelector((state) => state.widget.dataSources[widgetId] ?? EMPTY_DATA_SOURCE
|
|
2495
|
+
const dataSourceOptions = reactRedux.useSelector((state) => state.widget.dataSources[widgetId] ?? EMPTY_DATA_SOURCE);
|
|
2363
2496
|
// Skip value handling for layout widgets (they don't store data values)
|
|
2364
2497
|
// Infer layout from widget-type
|
|
2365
2498
|
const isLayoutWidget = config['widget-type'] === 'layout';
|
|
@@ -2681,6 +2814,8 @@ const useBaseWidget = (options) => {
|
|
|
2681
2814
|
const apiService = dataSource?.type === 'api' ? dataSource.service : '';
|
|
2682
2815
|
const apiEndpoint = dataSource?.type === 'api' ? dataSource.endpoint : '';
|
|
2683
2816
|
const configKey = `${widgetId}-${isReadonly}-${dataSource?.type || 'none'}-${apiService}-${apiEndpoint}`;
|
|
2817
|
+
// Stable key so inline schemaData objects (e.g. dialog-table fields) don't retrigger loads every render
|
|
2818
|
+
const schemaDataKey = React.useMemo(() => (schemaData ? JSON.stringify(schemaData) : ''), [schemaData]);
|
|
2684
2819
|
// Extract dependency value using a granular selector to prevent unnecessary re-renders
|
|
2685
2820
|
// and infinite loops when other unrelated values in the state change.
|
|
2686
2821
|
const dependencyValue = reactRedux.useSelector((state) => {
|
|
@@ -2798,7 +2933,7 @@ const useBaseWidget = (options) => {
|
|
|
2798
2933
|
loadDataSource();
|
|
2799
2934
|
// Use configKey and dependencyValue to ensure effect runs only when relevant state changes
|
|
2800
2935
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2801
|
-
}, [configKey, dependencyValue, dataSourceRequestHandler,
|
|
2936
|
+
}, [configKey, dependencyValue, dataSourceRequestHandler, schemaDataKey, widgetId, dispatch]);
|
|
2802
2937
|
const geoDisplayLabel = React.useMemo(() => {
|
|
2803
2938
|
if (!geoConfig) {
|
|
2804
2939
|
return undefined;
|
|
@@ -2887,8 +3022,6 @@ const useWidgetCascade = (options) => {
|
|
|
2887
3022
|
}, [cascadeConfig, eventBus, dataSource, widgetId, dispatch]);
|
|
2888
3023
|
};
|
|
2889
3024
|
|
|
2890
|
-
// Define stable empty array to avoid selector reference issues
|
|
2891
|
-
const EMPTY_DATA_SOURCE = [];
|
|
2892
3025
|
/**
|
|
2893
3026
|
* Hook for geo widget cascade functionality
|
|
2894
3027
|
* Handles geo hierarchy building and cascade behavior
|
|
@@ -2918,15 +3051,15 @@ const useGeoWidgetCascade = (options) => {
|
|
|
2918
3051
|
? resolveGeoWidgetLevelValue(state.widget.values, widgetId, dataPath, geoConfig)
|
|
2919
3052
|
: state.widget.values[widgetId]);
|
|
2920
3053
|
// Memoize selector to avoid returning new array reference
|
|
2921
|
-
const
|
|
3054
|
+
const allDataSources = reactRedux.useSelector((state) => state.widget.dataSources);
|
|
2922
3055
|
// Register parent chain for upstream-ancestor detection (grandparent → grandchild reset)
|
|
2923
3056
|
React.useEffect(() => {
|
|
2924
|
-
if (!geoConfig) {
|
|
3057
|
+
if (!geoConfig || typeof dataPath !== 'string') {
|
|
2925
3058
|
return;
|
|
2926
3059
|
}
|
|
2927
|
-
|
|
2928
|
-
return () =>
|
|
2929
|
-
}, [widgetId, geoConfig]);
|
|
3060
|
+
registerGeoWidget(widgetId, geoConfig, dataPath);
|
|
3061
|
+
return () => unregisterGeoWidget(widgetId);
|
|
3062
|
+
}, [widgetId, geoConfig, dataPath]);
|
|
2930
3063
|
// Keep in-memory builder in sync with persisted hierarchy (reload, cancel→re-edit, etc.)
|
|
2931
3064
|
React.useEffect(() => {
|
|
2932
3065
|
if (!geoConfig || typeof dataPath !== 'string') {
|
|
@@ -3018,18 +3151,20 @@ const useGeoWidgetCascade = (options) => {
|
|
|
3018
3151
|
}, [geoConfig, eventBus, dataSource, widgetId, dataPath, dispatch, groupId]);
|
|
3019
3152
|
// Handle value changes to build hierarchy
|
|
3020
3153
|
React.useEffect(() => {
|
|
3021
|
-
if (!geoConfig) {
|
|
3154
|
+
if (!geoConfig || typeof dataPath !== 'string') {
|
|
3022
3155
|
return;
|
|
3023
3156
|
}
|
|
3024
|
-
|
|
3157
|
+
const { level, isLastLevel } = geoConfig;
|
|
3158
|
+
const groupRegistrations = getGeoWidgetRegistrationsInGroup(groupId);
|
|
3159
|
+
const applyGroupRebuild = () => {
|
|
3160
|
+
const resolveMnemonic = createGeoLevelMnemonicResolver(valuesRef.current, allDataSources);
|
|
3161
|
+
rebuildGeoHierarchyFromRegistrations(groupId, valuesRef.current, groupRegistrations, resolveMnemonic);
|
|
3162
|
+
dispatch(setValues(applySharedGeoHierarchyToValues(valuesRef.current, groupId, dataPath, widgetId)));
|
|
3163
|
+
};
|
|
3025
3164
|
// ONLY clear hierarchy if the value is explicitly null or empty string (user action)
|
|
3026
3165
|
if (currentValue === null || currentValue === '') {
|
|
3027
|
-
const { level, isLastLevel } = geoConfig;
|
|
3028
3166
|
geoHierarchyBuilder.removeLevelAndBelow(level, groupId);
|
|
3029
|
-
|
|
3030
|
-
if (dataPath) {
|
|
3031
|
-
dispatch(setValues(applySharedGeoHierarchyToValues(valuesRef.current, groupId, dataPath, widgetId)));
|
|
3032
|
-
}
|
|
3167
|
+
applyGroupRebuild();
|
|
3033
3168
|
if (!isLastLevel && eventBus && lastCascadePublishRef.current !== GEO_LEVEL_CLEARED) {
|
|
3034
3169
|
lastCascadePublishRef.current = GEO_LEVEL_CLEARED;
|
|
3035
3170
|
eventBus.publish({
|
|
@@ -3042,56 +3177,13 @@ const useGeoWidgetCascade = (options) => {
|
|
|
3042
3177
|
return;
|
|
3043
3178
|
}
|
|
3044
3179
|
if (currentValue === undefined) {
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
// Check if hierarchy is already built to prevent endless loops
|
|
3049
|
-
if (dataPath) {
|
|
3050
|
-
const currentHierarchy = getWidgetValue(valuesRef.current, dataPath, widgetId);
|
|
3051
|
-
// If hierarchy JSON is already set and matches current value, skip rebuilding
|
|
3052
|
-
if (currentHierarchy && typeof currentHierarchy === 'object') {
|
|
3053
|
-
// Check if this specific level's value matches the hierarchy
|
|
3054
|
-
const hierarchyArray = currentHierarchy.hierarchy || currentHierarchy.geo_code_hierarchy_json?.hierarchy;
|
|
3055
|
-
if (Array.isArray(hierarchyArray)) {
|
|
3056
|
-
const currentLevelValue = typeof currentValue === 'object'
|
|
3057
|
-
? (currentValue.level_value_id || currentValue.id || currentValue.value)
|
|
3058
|
-
: currentValue;
|
|
3059
|
-
const levelData = hierarchyArray.find((l) => l.level === geoConfig.level);
|
|
3060
|
-
// If this level is already correctly represented in the hierarchy, skip rebuilding
|
|
3061
|
-
// String conversion ensures comparison works for mixed types
|
|
3062
|
-
if (levelData && String(levelData.level_value_id) === String(currentLevelValue)) {
|
|
3063
|
-
return;
|
|
3064
|
-
}
|
|
3065
|
-
}
|
|
3180
|
+
const hasOwnValue = Object.prototype.hasOwnProperty.call(valuesRef.current, widgetId);
|
|
3181
|
+
if (!hasOwnValue) {
|
|
3182
|
+
return;
|
|
3066
3183
|
}
|
|
3067
3184
|
}
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
let level_value_id;
|
|
3071
|
-
let level_value_mnemonic;
|
|
3072
|
-
if (typeof currentValue === 'string' || typeof currentValue === 'number') {
|
|
3073
|
-
// Value is just the ID, need to find mnemonic from data source
|
|
3074
|
-
level_value_id = String(currentValue);
|
|
3075
|
-
// Try to get mnemonic from data source options
|
|
3076
|
-
const option = dataSourceOptions.find((opt) => opt.value === currentValue);
|
|
3077
|
-
level_value_mnemonic = option?.label || String(currentValue);
|
|
3078
|
-
}
|
|
3079
|
-
else if (currentValue && typeof currentValue === 'object') {
|
|
3080
|
-
level_value_id = currentValue.level_value_id || currentValue.id || currentValue.value;
|
|
3081
|
-
level_value_mnemonic = currentValue.level_value_mnemonic || currentValue.name || currentValue.label;
|
|
3082
|
-
}
|
|
3083
|
-
else {
|
|
3084
|
-
return;
|
|
3085
|
-
}
|
|
3086
|
-
// When a widget's own value changes, remove this level and all below from hierarchy first
|
|
3087
|
-
geoHierarchyBuilder.removeLevelAndBelow(level, groupId);
|
|
3088
|
-
// Add level to hierarchy
|
|
3089
|
-
geoHierarchyBuilder.addLevel(level, level_value_id, level_value_mnemonic, groupId);
|
|
3090
|
-
// Build and store hierarchy JSON on every change
|
|
3091
|
-
if (dataPath && geoHierarchyBuilder.buildHierarchyJson(groupId)) {
|
|
3092
|
-
dispatch(setValues(applySharedGeoHierarchyToValues(valuesRef.current, groupId, dataPath, widgetId)));
|
|
3093
|
-
}
|
|
3094
|
-
}, [geoConfig, currentValue, widgetId, dataPath, dispatch, dataSourceOptions, groupId]);
|
|
3185
|
+
applyGroupRebuild();
|
|
3186
|
+
}, [geoConfig, currentValue, widgetId, dataPath, dispatch, allDataSources, groupId, eventBus]);
|
|
3095
3187
|
};
|
|
3096
3188
|
|
|
3097
3189
|
class WidgetRegistry {
|
|
@@ -4993,7 +5085,12 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
|
|
|
4993
5085
|
// This ensures we use the original widget IDs and data paths
|
|
4994
5086
|
const sectionWidgets = collectWidgets(originalSection.panels);
|
|
4995
5087
|
const currentState = store.getState().widget;
|
|
4996
|
-
|
|
5088
|
+
let currentSchemaData = currentState.values || {};
|
|
5089
|
+
const geoRegistrations = collectGeoWidgetRegistrationsFromWidgets(sectionWidgets, namespace);
|
|
5090
|
+
if (geoRegistrations.length > 0) {
|
|
5091
|
+
currentSchemaData = reconcileGeoHierarchiesInValues(currentSchemaData, geoRegistrations, currentState.dataSources || {});
|
|
5092
|
+
dispatch(setValues(currentSchemaData));
|
|
5093
|
+
}
|
|
4997
5094
|
const isSectionValid = sectionValidate(originalSection, currentSchemaData, dispatch, true);
|
|
4998
5095
|
if (!isSectionValid) {
|
|
4999
5096
|
return;
|
|
@@ -5059,7 +5156,12 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
|
|
|
5059
5156
|
if (isDraft !== false && store && onSectionSave) {
|
|
5060
5157
|
const sectionWidgets = collectWidgets(originalSection.panels);
|
|
5061
5158
|
const currentState = store.getState().widget;
|
|
5062
|
-
|
|
5159
|
+
let currentSchemaData = currentState.values || {};
|
|
5160
|
+
const geoRegistrations = collectGeoWidgetRegistrationsFromWidgets(sectionWidgets, namespace);
|
|
5161
|
+
if (geoRegistrations.length > 0) {
|
|
5162
|
+
currentSchemaData = reconcileGeoHierarchiesInValues(currentSchemaData, geoRegistrations, currentState.dataSources || {});
|
|
5163
|
+
dispatch(setValues(currentSchemaData));
|
|
5164
|
+
}
|
|
5063
5165
|
const isSectionValid = sectionValidate(originalSection, currentSchemaData, dispatch, true);
|
|
5064
5166
|
if (!isSectionValid)
|
|
5065
5167
|
return;
|
|
@@ -9987,6 +10089,22 @@ const TableWidget = ({ config }) => {
|
|
|
9987
10089
|
};
|
|
9988
10090
|
|
|
9989
10091
|
const isUnsetRowValue = (value) => value === null || value === undefined || value === '';
|
|
10092
|
+
/** Match TableWidget cell styling for add / update / delete rows */
|
|
10093
|
+
const getRowCellStyle = (editAction) => {
|
|
10094
|
+
if (editAction === 'ADD') {
|
|
10095
|
+
return { color: 'var(--owt-color-success, #16A34A)' };
|
|
10096
|
+
}
|
|
10097
|
+
if (editAction === 'DELETE') {
|
|
10098
|
+
return {
|
|
10099
|
+
color: 'var(--owt-color-error, #B91C1C)',
|
|
10100
|
+
textDecoration: 'line-through',
|
|
10101
|
+
};
|
|
10102
|
+
}
|
|
10103
|
+
if (editAction === 'UPDATE') {
|
|
10104
|
+
return { color: 'var(--owt-color-warning, #F59E0B)' };
|
|
10105
|
+
}
|
|
10106
|
+
return {};
|
|
10107
|
+
};
|
|
9990
10108
|
// Display select value label in view mode
|
|
9991
10109
|
const SelectDisplayValue = ({ config, value }) => {
|
|
9992
10110
|
const { dataSourceOptions, loading } = useBaseWidget({ config });
|
|
@@ -9997,23 +10115,29 @@ const SelectDisplayValue = ({ config, value }) => {
|
|
|
9997
10115
|
const selectedOption = dataSourceOptions.find((option) => option.value === value || String(option.value) === String(value));
|
|
9998
10116
|
return jsxRuntimeExports.jsx("span", { children: selectedOption ? selectedOption.label : String(value) });
|
|
9999
10117
|
};
|
|
10118
|
+
/** Isolated dialog field — avoids re-running data-source effects when sibling fields update. */
|
|
10119
|
+
const DialogTableField = React.memo(function DialogTableField({ col, cellWidgetId, dialogRowValues, isReadonly, }) {
|
|
10120
|
+
const widgetType = col.widget || 'text';
|
|
10121
|
+
const fieldConfig = React.useMemo(() => {
|
|
10122
|
+
return {
|
|
10123
|
+
...col,
|
|
10124
|
+
widget: widgetType,
|
|
10125
|
+
'widget-type': col['widget-type'] || 'input',
|
|
10126
|
+
'widget-id': cellWidgetId,
|
|
10127
|
+
'widget-label': col['widget-label'],
|
|
10128
|
+
'widget-readonly': isReadonly || col['widget-readonly'] === true,
|
|
10129
|
+
'widget-data-path': undefined,
|
|
10130
|
+
'widget-data-default': col['widget-data-default'],
|
|
10131
|
+
'widget-data-options': undefined,
|
|
10132
|
+
'widget-required': shouldRequireWidget(col['widget-data-options'], dialogRowValues, col['widget-required']),
|
|
10133
|
+
};
|
|
10134
|
+
}, [col, cellWidgetId, dialogRowValues, isReadonly, widgetType]);
|
|
10135
|
+
return (jsxRuntimeExports.jsx("div", { className: "min-w-0", children: jsxRuntimeExports.jsx(WidgetRenderer, { config: fieldConfig }) }));
|
|
10136
|
+
});
|
|
10000
10137
|
/**
|
|
10001
10138
|
* Dialog table widget:
|
|
10002
10139
|
* - Table displays a subset of columns (n out of x)
|
|
10003
10140
|
* - Add/Edit happens in a modal dialog that shows ALL columns as a form
|
|
10004
|
-
*
|
|
10005
|
-
* Usage in schema:
|
|
10006
|
-
* {
|
|
10007
|
-
* "widget": "dialog-table",
|
|
10008
|
-
* "widget-type": "table",
|
|
10009
|
-
* "widget-label": "Household Members",
|
|
10010
|
-
* "widget-id": "householdMembers",
|
|
10011
|
-
* "widget-data-path": "household.members",
|
|
10012
|
-
* "widget-data-columns": [ ...all columns... ],
|
|
10013
|
-
* "widget-data-visible-columns": ["firstName", "lastName", "dob"], // optional override; default = by column flag
|
|
10014
|
-
* // Per-column control (recommended): set "column-visible-in-table": false to hide it in the table
|
|
10015
|
-
* "widget-data-operations": { "add": true, "edit": true, "remove": true }
|
|
10016
|
-
* }
|
|
10017
10141
|
*/
|
|
10018
10142
|
const DialogTableWidget = ({ config }) => {
|
|
10019
10143
|
const { value, error, touched, isEnabled, onChange, config: widgetConfig } = useBaseWidget({ config });
|
|
@@ -10023,23 +10147,22 @@ const DialogTableWidget = ({ config }) => {
|
|
|
10023
10147
|
const columns = widgetConfig['widget-data-columns'] || [];
|
|
10024
10148
|
const operations = widgetConfig['widget-data-operations'] || {};
|
|
10025
10149
|
const isReadonly = widgetConfig['widget-readonly'] || false;
|
|
10150
|
+
// Soft-delete (keep row, red + strikethrough) whenever remove is allowed — matches TableWidget
|
|
10151
|
+
const shouldSoftDeleteOnRemove = !isReadonly && !!operations.remove;
|
|
10026
10152
|
const visibleColumnKeys = widgetConfig['widget-data-visible-columns'];
|
|
10027
10153
|
const visibleColumns = React.useMemo(() => {
|
|
10028
|
-
// 1) If explicit list provided, it wins
|
|
10029
10154
|
if (Array.isArray(visibleColumnKeys) && visibleColumnKeys.length > 0) {
|
|
10030
10155
|
const keySet = new Set(visibleColumnKeys);
|
|
10031
10156
|
return columns.filter((c) => keySet.has(c['column-key']));
|
|
10032
10157
|
}
|
|
10033
|
-
// 2) Otherwise decide per column (default = visible)
|
|
10034
10158
|
return columns.filter((c) => c['column-visible-in-table'] !== false);
|
|
10035
10159
|
}, [columns, visibleColumnKeys]);
|
|
10036
10160
|
const [dialogOpen, setDialogOpen] = React.useState(false);
|
|
10037
10161
|
const [dialogMode, setDialogMode] = React.useState('add');
|
|
10038
10162
|
const [activeRowIndex, setActiveRowIndex] = React.useState(null);
|
|
10039
|
-
const [formData, setFormData] = React.useState({});
|
|
10040
|
-
/** Unique per dialog open so Redux widget ids don't reuse stale values across rows/add sessions */
|
|
10041
10163
|
const dialogSessionRef = React.useRef(0);
|
|
10042
10164
|
const [dialogSessionId, setDialogSessionId] = React.useState(0);
|
|
10165
|
+
const membersWidgetId = widgetConfig['widget-id'];
|
|
10043
10166
|
const addDialogTitle = translateConfig(widgetConfig['widget-data-dialog-title-add']) ||
|
|
10044
10167
|
translate('table.addRecordDialog') ||
|
|
10045
10168
|
'Add record';
|
|
@@ -10059,15 +10182,26 @@ const DialogTableWidget = ({ config }) => {
|
|
|
10059
10182
|
});
|
|
10060
10183
|
return emptyRow;
|
|
10061
10184
|
}, [columns]);
|
|
10062
|
-
const dialogFieldWidgetId = React.useCallback((columnKey) => `${
|
|
10185
|
+
const dialogFieldWidgetId = React.useCallback((sessionId, columnKey) => `${membersWidgetId}-dlg-${sessionId}-${columnKey}`, [membersWidgetId]);
|
|
10063
10186
|
const resetDialogWidgets = React.useCallback((sessionId) => {
|
|
10064
10187
|
if (sessionId <= 0)
|
|
10065
10188
|
return;
|
|
10066
10189
|
columns.forEach((col) => {
|
|
10067
|
-
|
|
10068
|
-
|
|
10190
|
+
dispatch(resetWidget(dialogFieldWidgetId(sessionId, col['column-key'])));
|
|
10191
|
+
});
|
|
10192
|
+
}, [columns, dialogFieldWidgetId, dispatch]);
|
|
10193
|
+
const seedDialogReduxValues = React.useCallback((sessionId, rowData) => {
|
|
10194
|
+
const seeds = {};
|
|
10195
|
+
columns.forEach((col) => {
|
|
10196
|
+
const key = col['column-key'];
|
|
10197
|
+
if (rowData[key] !== undefined) {
|
|
10198
|
+
seeds[dialogFieldWidgetId(sessionId, key)] = rowData[key];
|
|
10199
|
+
}
|
|
10069
10200
|
});
|
|
10070
|
-
|
|
10201
|
+
if (Object.keys(seeds).length > 0) {
|
|
10202
|
+
dispatch(setValues(seeds));
|
|
10203
|
+
}
|
|
10204
|
+
}, [columns, dialogFieldWidgetId, dispatch]);
|
|
10071
10205
|
const beginDialogSession = React.useCallback(() => {
|
|
10072
10206
|
dialogSessionRef.current += 1;
|
|
10073
10207
|
const nextSession = dialogSessionRef.current;
|
|
@@ -10076,15 +10210,21 @@ const DialogTableWidget = ({ config }) => {
|
|
|
10076
10210
|
}, []);
|
|
10077
10211
|
const openAddDialog = React.useCallback(() => {
|
|
10078
10212
|
resetDialogWidgets(dialogSessionId);
|
|
10079
|
-
beginDialogSession();
|
|
10213
|
+
const sessionId = beginDialogSession();
|
|
10214
|
+
seedDialogReduxValues(sessionId, buildEmptyRow());
|
|
10080
10215
|
setDialogMode('add');
|
|
10081
10216
|
setActiveRowIndex(null);
|
|
10082
|
-
setFormData(buildEmptyRow());
|
|
10083
10217
|
setDialogOpen(true);
|
|
10084
|
-
}, [
|
|
10218
|
+
}, [
|
|
10219
|
+
buildEmptyRow,
|
|
10220
|
+
beginDialogSession,
|
|
10221
|
+
resetDialogWidgets,
|
|
10222
|
+
dialogSessionId,
|
|
10223
|
+
seedDialogReduxValues,
|
|
10224
|
+
]);
|
|
10085
10225
|
const openEditDialog = React.useCallback((rowIndex) => {
|
|
10086
10226
|
resetDialogWidgets(dialogSessionId);
|
|
10087
|
-
beginDialogSession();
|
|
10227
|
+
const sessionId = beginDialogSession();
|
|
10088
10228
|
const row = rows[rowIndex] || {};
|
|
10089
10229
|
const nextFormData = buildEmptyRow();
|
|
10090
10230
|
columns.forEach((col) => {
|
|
@@ -10092,23 +10232,26 @@ const DialogTableWidget = ({ config }) => {
|
|
|
10092
10232
|
if (row[key] !== undefined)
|
|
10093
10233
|
nextFormData[key] = row[key];
|
|
10094
10234
|
});
|
|
10235
|
+
seedDialogReduxValues(sessionId, nextFormData);
|
|
10095
10236
|
setDialogMode('edit');
|
|
10096
10237
|
setActiveRowIndex(rowIndex);
|
|
10097
|
-
setFormData(nextFormData);
|
|
10098
10238
|
setDialogOpen(true);
|
|
10099
|
-
}, [
|
|
10239
|
+
}, [
|
|
10240
|
+
rows,
|
|
10241
|
+
columns,
|
|
10242
|
+
buildEmptyRow,
|
|
10243
|
+
resetDialogWidgets,
|
|
10244
|
+
dialogSessionId,
|
|
10245
|
+
beginDialogSession,
|
|
10246
|
+
seedDialogReduxValues,
|
|
10247
|
+
]);
|
|
10100
10248
|
const closeDialog = React.useCallback(() => {
|
|
10101
10249
|
const sessionToClear = dialogSessionId;
|
|
10102
10250
|
setDialogOpen(false);
|
|
10103
10251
|
setActiveRowIndex(null);
|
|
10104
|
-
setFormData({});
|
|
10105
10252
|
resetDialogWidgets(sessionToClear);
|
|
10106
10253
|
setDialogSessionId(0);
|
|
10107
10254
|
}, [dialogSessionId, resetDialogWidgets]);
|
|
10108
|
-
const updateField = React.useCallback((columnKey, newValue) => {
|
|
10109
|
-
setFormData((prev) => ({ ...prev, [columnKey]: newValue }));
|
|
10110
|
-
}, []);
|
|
10111
|
-
const membersWidgetId = widgetConfig['widget-id'];
|
|
10112
10255
|
const dialogStoreValues = reactRedux.useSelector((state) => {
|
|
10113
10256
|
if (dialogSessionId <= 0) {
|
|
10114
10257
|
return {};
|
|
@@ -10117,25 +10260,15 @@ const DialogTableWidget = ({ config }) => {
|
|
|
10117
10260
|
const row = {};
|
|
10118
10261
|
columns.forEach((col) => {
|
|
10119
10262
|
const k = col['column-key'];
|
|
10120
|
-
const wid =
|
|
10263
|
+
const wid = dialogFieldWidgetId(dialogSessionId, k);
|
|
10121
10264
|
if (values[wid] !== undefined) {
|
|
10122
10265
|
row[k] = values[wid];
|
|
10123
10266
|
}
|
|
10124
10267
|
});
|
|
10125
10268
|
return row;
|
|
10126
|
-
}
|
|
10127
|
-
const
|
|
10128
|
-
|
|
10129
|
-
columns.forEach((col) => {
|
|
10130
|
-
const k = col['column-key'];
|
|
10131
|
-
if (storeSlice[k] !== undefined) {
|
|
10132
|
-
row[k] = storeSlice[k];
|
|
10133
|
-
}
|
|
10134
|
-
});
|
|
10135
|
-
return row;
|
|
10136
|
-
}, [formData, columns]);
|
|
10137
|
-
const dialogRowValues = React.useMemo(() => buildDialogRowValues(dialogStoreValues), [buildDialogRowValues, dialogStoreValues]);
|
|
10138
|
-
const collectMergedRowPayload = React.useCallback(() => buildDialogRowValues(dialogStoreValues), [buildDialogRowValues, dialogStoreValues]);
|
|
10269
|
+
});
|
|
10270
|
+
const dialogRowValues = dialogStoreValues;
|
|
10271
|
+
const collectMergedRowPayload = React.useCallback(() => dialogStoreValues, [dialogStoreValues]);
|
|
10139
10272
|
const finalizeDialogRowPayload = React.useCallback((raw) => {
|
|
10140
10273
|
const result = {};
|
|
10141
10274
|
columns.forEach((col) => {
|
|
@@ -10155,7 +10288,7 @@ const DialogTableWidget = ({ config }) => {
|
|
|
10155
10288
|
let hasErrors = false;
|
|
10156
10289
|
columns.forEach((col) => {
|
|
10157
10290
|
const key = col['column-key'];
|
|
10158
|
-
const cellWidgetId = dialogFieldWidgetId(key);
|
|
10291
|
+
const cellWidgetId = dialogFieldWidgetId(dialogSessionId, key);
|
|
10159
10292
|
const isColReadonly = isReadonly || col['widget-readonly'] === true;
|
|
10160
10293
|
if (isColReadonly)
|
|
10161
10294
|
return;
|
|
@@ -10199,11 +10332,32 @@ const DialogTableWidget = ({ config }) => {
|
|
|
10199
10332
|
onChange(newRows);
|
|
10200
10333
|
closeDialog();
|
|
10201
10334
|
}
|
|
10202
|
-
}, [
|
|
10335
|
+
}, [
|
|
10336
|
+
collectMergedRowPayload,
|
|
10337
|
+
finalizeDialogRowPayload,
|
|
10338
|
+
dialogMode,
|
|
10339
|
+
onChange,
|
|
10340
|
+
rows,
|
|
10341
|
+
closeDialog,
|
|
10342
|
+
activeRowIndex,
|
|
10343
|
+
columns,
|
|
10344
|
+
dialogSessionId,
|
|
10345
|
+
dialogFieldWidgetId,
|
|
10346
|
+
isReadonly,
|
|
10347
|
+
dispatch,
|
|
10348
|
+
]);
|
|
10203
10349
|
const deleteRow = React.useCallback((rowIndex) => {
|
|
10204
|
-
|
|
10205
|
-
|
|
10206
|
-
|
|
10350
|
+
if (shouldSoftDeleteOnRemove) {
|
|
10351
|
+
const newRows = [...rows];
|
|
10352
|
+
newRows[rowIndex] = {
|
|
10353
|
+
...newRows[rowIndex],
|
|
10354
|
+
edit_action: 'DELETE',
|
|
10355
|
+
};
|
|
10356
|
+
onChange(newRows);
|
|
10357
|
+
return;
|
|
10358
|
+
}
|
|
10359
|
+
onChange(rows.filter((_, i) => i !== rowIndex));
|
|
10360
|
+
}, [rows, onChange, shouldSoftDeleteOnRemove]);
|
|
10207
10361
|
const getDisplayValue = React.useCallback((rowIndex, column) => {
|
|
10208
10362
|
const key = column['column-key'];
|
|
10209
10363
|
const cellValue = rows[rowIndex]?.[key];
|
|
@@ -10211,11 +10365,12 @@ const DialogTableWidget = ({ config }) => {
|
|
|
10211
10365
|
if (cellValue === null || cellValue === undefined || cellValue === '')
|
|
10212
10366
|
return '-';
|
|
10213
10367
|
if (widgetType === 'select')
|
|
10214
|
-
return null;
|
|
10368
|
+
return null;
|
|
10215
10369
|
if (column['widget-data-format'])
|
|
10216
10370
|
return formatValue(cellValue, column['widget-data-format'], column.widget);
|
|
10217
10371
|
return String(cellValue);
|
|
10218
10372
|
}, [rows]);
|
|
10373
|
+
const visibleDialogColumns = React.useMemo(() => columns.filter((col) => shouldShowWidget(col['widget-data-options'], dialogRowValues)), [columns, dialogRowValues]);
|
|
10219
10374
|
const tableWidgetId = `dialog-table-widget-${widgetConfig['widget-id']}`;
|
|
10220
10375
|
const columnSpan = widgetConfig['widget-column-span'] || 2;
|
|
10221
10376
|
const minWidth = columnSpan * 200;
|
|
@@ -10243,37 +10398,40 @@ const DialogTableWidget = ({ config }) => {
|
|
|
10243
10398
|
}, children: translate('table.addRecord') || 'Add New Record' }) })), jsxRuntimeExports.jsx("div", { className: "overflow-x-auto border", style: {
|
|
10244
10399
|
borderRadius: 'var(--owt-widget-table-border-radius, 15px)',
|
|
10245
10400
|
borderColor: 'var(--owt-widget-table-border-color, #C4C4C4)',
|
|
10246
|
-
}, 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) =>
|
|
10247
|
-
|
|
10248
|
-
|
|
10249
|
-
|
|
10250
|
-
:
|
|
10251
|
-
|
|
10252
|
-
|
|
10253
|
-
|
|
10254
|
-
|
|
10255
|
-
|
|
10256
|
-
const
|
|
10257
|
-
|
|
10258
|
-
|
|
10259
|
-
|
|
10260
|
-
|
|
10261
|
-
|
|
10262
|
-
|
|
10263
|
-
|
|
10264
|
-
|
|
10265
|
-
|
|
10266
|
-
|
|
10267
|
-
|
|
10268
|
-
|
|
10269
|
-
|
|
10270
|
-
|
|
10271
|
-
|
|
10272
|
-
|
|
10273
|
-
|
|
10274
|
-
|
|
10275
|
-
|
|
10276
|
-
|
|
10401
|
+
}, 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) => {
|
|
10402
|
+
const cellStyle = getRowCellStyle(row?.edit_action);
|
|
10403
|
+
return (jsxRuntimeExports.jsxs("tr", { style: {
|
|
10404
|
+
borderBottom: '1px solid var(--owt-widget-table-row-divider, #E4E4E4)',
|
|
10405
|
+
backgroundColor: row?.edit_action === 'DELETE'
|
|
10406
|
+
? 'var(--owt-widget-table-deleted-row-bg, #FEE2E2)'
|
|
10407
|
+
: undefined,
|
|
10408
|
+
}, children: [visibleColumns.map((col) => {
|
|
10409
|
+
const key = col['column-key'];
|
|
10410
|
+
const widgetType = col.widget || 'text';
|
|
10411
|
+
const displayValue = getDisplayValue(rowIndex, col);
|
|
10412
|
+
if (widgetType === 'select' && displayValue === null) {
|
|
10413
|
+
const displayConfig = {
|
|
10414
|
+
...col,
|
|
10415
|
+
'widget-id': `${widgetConfig['widget-id']}-view-row-${rowIndex}-col-${key}`,
|
|
10416
|
+
'widget-label': '',
|
|
10417
|
+
'widget-readonly': true,
|
|
10418
|
+
'widget-data-path': undefined,
|
|
10419
|
+
};
|
|
10420
|
+
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));
|
|
10421
|
+
}
|
|
10422
|
+
return (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: jsxRuntimeExports.jsx("div", { className: "text-sm", style: cellStyle, children: displayValue }) }, key));
|
|
10423
|
+
}), ((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: {
|
|
10424
|
+
borderRadius: 'var(--owt-btn-border-radius, 10px)',
|
|
10425
|
+
color: 'var(--owt-color-primary-dark, #F07B1A)',
|
|
10426
|
+
backgroundColor: 'transparent',
|
|
10427
|
+
border: 'none',
|
|
10428
|
+
}, 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: {
|
|
10429
|
+
borderRadius: 'var(--owt-btn-border-radius, 10px)',
|
|
10430
|
+
color: 'var(--owt-color-error, #B91C1C)',
|
|
10431
|
+
backgroundColor: 'transparent',
|
|
10432
|
+
border: 'none',
|
|
10433
|
+
}, children: translate('common.remove') || 'Delete' }))] }) }))] }, rowIndex));
|
|
10434
|
+
})] })] }) }), 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: {
|
|
10277
10435
|
maxWidth: '900px',
|
|
10278
10436
|
backgroundColor: 'var(--owt-color-bg, #FFFFFF)',
|
|
10279
10437
|
borderRadius: 'var(--owt-widget-card-border-radius, 20px)',
|
|
@@ -10284,27 +10442,10 @@ const DialogTableWidget = ({ config }) => {
|
|
|
10284
10442
|
cursor: 'pointer',
|
|
10285
10443
|
fontSize: '20px',
|
|
10286
10444
|
lineHeight: 1,
|
|
10287
|
-
}, "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:
|
|
10445
|
+
}, "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: visibleDialogColumns.map((col) => {
|
|
10288
10446
|
const key = col['column-key'];
|
|
10289
|
-
|
|
10290
|
-
|
|
10291
|
-
}
|
|
10292
|
-
const widgetType = col.widget || 'text';
|
|
10293
|
-
const cellWidgetId = dialogFieldWidgetId(key);
|
|
10294
|
-
const initialValue = formData[key] ?? col['widget-data-default'];
|
|
10295
|
-
const fieldConfig = {
|
|
10296
|
-
...col,
|
|
10297
|
-
widget: widgetType,
|
|
10298
|
-
'widget-type': col['widget-type'] || 'input',
|
|
10299
|
-
'widget-id': cellWidgetId,
|
|
10300
|
-
'widget-label': col['widget-label'],
|
|
10301
|
-
'widget-readonly': isReadonly || col['widget-readonly'] === true,
|
|
10302
|
-
'widget-data-path': undefined,
|
|
10303
|
-
'widget-data-default': initialValue,
|
|
10304
|
-
'widget-data-options': undefined,
|
|
10305
|
-
'widget-required': shouldRequireWidget(col['widget-data-options'], dialogRowValues, col['widget-required']),
|
|
10306
|
-
};
|
|
10307
|
-
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}`));
|
|
10447
|
+
const cellWidgetId = dialogFieldWidgetId(dialogSessionId, key);
|
|
10448
|
+
return (jsxRuntimeExports.jsx(DialogTableField, { col: col, cellWidgetId: cellWidgetId, dialogRowValues: dialogRowValues, isReadonly: isReadonly }, `${dialogSessionId}-${key}`));
|
|
10308
10449
|
}) }, `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: {
|
|
10309
10450
|
borderRadius: 'var(--owt-btn-border-radius, 10px)',
|
|
10310
10451
|
border: '1px solid var(--owt-btn-secondary-border, #C4C4C4)',
|
|
@@ -12988,6 +13129,8 @@ exports.applyCaseControl = applyCaseControl;
|
|
|
12988
13129
|
exports.applyDecimalPrecision = applyDecimalPrecision;
|
|
12989
13130
|
exports.applyMask = applyMask;
|
|
12990
13131
|
exports.applySharedGeoHierarchyToValues = applySharedGeoHierarchyToValues;
|
|
13132
|
+
exports.collectGeoWidgetRegistrationsFromWidgets = collectGeoWidgetRegistrationsFromWidgets;
|
|
13133
|
+
exports.createGeoLevelMnemonicResolver = createGeoLevelMnemonicResolver;
|
|
12991
13134
|
exports.createWidgetStore = createWidgetStore;
|
|
12992
13135
|
exports.createZodSchema = createZodSchema;
|
|
12993
13136
|
exports.defaultTheme = defaultTheme;
|
|
@@ -13005,6 +13148,7 @@ exports.getCachedApiDataSource = getCachedApiDataSource;
|
|
|
13005
13148
|
exports.getFormattedNumberLength = getFormattedNumberLength;
|
|
13006
13149
|
exports.getGeoDescendantWidgetIds = getGeoDescendantWidgetIds;
|
|
13007
13150
|
exports.getGeoGroupId = getGeoGroupId;
|
|
13151
|
+
exports.getGeoWidgetRegistrationsInGroup = getGeoWidgetRegistrationsInGroup;
|
|
13008
13152
|
exports.getSchemaDataSource = getSchemaDataSource;
|
|
13009
13153
|
exports.getStaticDataSource = getStaticDataSource;
|
|
13010
13154
|
exports.getValueByPath = getValueByPath;
|
|
@@ -13015,9 +13159,13 @@ exports.isAllowedKey = isAllowedKey;
|
|
|
13015
13159
|
exports.isUpstreamGeoAncestor = isUpstreamGeoAncestor;
|
|
13016
13160
|
exports.normalizeNumericDefault = normalizeNumericDefault;
|
|
13017
13161
|
exports.normalizeOptionRules = normalizeOptionRules;
|
|
13162
|
+
exports.orderGeoWidgetRegistrations = orderGeoWidgetRegistrations;
|
|
13018
13163
|
exports.parseDataPath = parseDataPath;
|
|
13019
13164
|
exports.parseNumber = parseNumber;
|
|
13165
|
+
exports.rebuildGeoHierarchyFromRegistrations = rebuildGeoHierarchyFromRegistrations;
|
|
13166
|
+
exports.reconcileGeoHierarchiesInValues = reconcileGeoHierarchiesInValues;
|
|
13020
13167
|
exports.registerDefaultWidgets = registerDefaultWidgets;
|
|
13168
|
+
exports.registerGeoWidget = registerGeoWidget;
|
|
13021
13169
|
exports.registerGeoWidgetParent = registerGeoWidgetParent;
|
|
13022
13170
|
exports.removeMask = removeMask;
|
|
13023
13171
|
exports.resetAll = resetAll;
|
|
@@ -13043,6 +13191,7 @@ exports.transformDataSourceOptions = transformDataSourceOptions;
|
|
|
13043
13191
|
exports.translatePanelConfig = translatePanelConfig;
|
|
13044
13192
|
exports.translateUISchema = translateUISchema;
|
|
13045
13193
|
exports.translateWidgetConfig = translateWidgetConfig;
|
|
13194
|
+
exports.unregisterGeoWidget = unregisterGeoWidget;
|
|
13046
13195
|
exports.unregisterGeoWidgetParent = unregisterGeoWidgetParent;
|
|
13047
13196
|
exports.useBaseWidget = useBaseWidget;
|
|
13048
13197
|
exports.useGeoWidgetCascade = useGeoWidgetCascade;
|