@openg2p/registry-widgets 1.1.1 → 1.1.2-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/hooks/useBaseWidget.d.ts.map +1 -1
- package/dist/hooks/useGeoWidgetCascade.d.ts.map +1 -1
- package/dist/index.d.ts +33 -2
- package/dist/index.esm.js +530 -305
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +539 -304
- package/dist/index.js.map +1 -1
- package/dist/utils/dataSource.d.ts.map +1 -1
- package/dist/utils/geoHierarchy.d.ts +23 -0
- package/dist/utils/geoHierarchy.d.ts.map +1 -1
- package/dist/utils/numberInput.d.ts +1 -0
- package/dist/utils/numberInput.d.ts.map +1 -1
- package/dist/utils/pathUtils.d.ts +5 -0
- package/dist/utils/pathUtils.d.ts.map +1 -1
- package/dist/widgets/NumberInputWidget.d.ts +2 -0
- package/dist/widgets/NumberInputWidget.d.ts.map +1 -1
- package/dist/widgets/TableWidget.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -174,15 +174,33 @@ const parseDataPath = (dataPath) => {
|
|
|
174
174
|
/**
|
|
175
175
|
* Get value from widget state using data path
|
|
176
176
|
*/
|
|
177
|
+
/**
|
|
178
|
+
* Resolve a widget-id reference in Redux values.
|
|
179
|
+
* Supports namespaced ids (e.g. "rv-section-0__region_code" when ref is "region_code").
|
|
180
|
+
*/
|
|
181
|
+
const resolveWidgetIdValue = (values, ref) => {
|
|
182
|
+
if (!ref) {
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
if (ref.includes('.')) {
|
|
186
|
+
return getValueByPath(values, ref);
|
|
187
|
+
}
|
|
188
|
+
if (Object.prototype.hasOwnProperty.call(values, ref)) {
|
|
189
|
+
return values[ref];
|
|
190
|
+
}
|
|
191
|
+
const suffix = `__${ref}`;
|
|
192
|
+
for (const [key, val] of Object.entries(values)) {
|
|
193
|
+
if (key.endsWith(suffix)) {
|
|
194
|
+
return val;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return undefined;
|
|
198
|
+
};
|
|
177
199
|
const getWidgetValue = (values, dataPath, widgetId) => {
|
|
178
200
|
if (!dataPath) {
|
|
179
201
|
// Fallback to widget-id if no data path
|
|
180
202
|
return values[widgetId];
|
|
181
203
|
}
|
|
182
|
-
if (widgetId == "user-profile") {
|
|
183
|
-
console.log('values', values);
|
|
184
|
-
console.log('dataPath', dataPath);
|
|
185
|
-
}
|
|
186
204
|
if (typeof dataPath === 'string') {
|
|
187
205
|
return getValueByPath(values, dataPath);
|
|
188
206
|
}
|
|
@@ -673,6 +691,21 @@ const getFormattedNumberLength = (value, format) => {
|
|
|
673
691
|
const formatted = formatNumber(typeof value === 'string' ? parseFloat(value) : value, format);
|
|
674
692
|
return formatted.length;
|
|
675
693
|
};
|
|
694
|
+
const normalizeNumericDefault = (defaultValue, format) => {
|
|
695
|
+
if (defaultValue === undefined) {
|
|
696
|
+
return undefined;
|
|
697
|
+
}
|
|
698
|
+
if (defaultValue === null || defaultValue === '') {
|
|
699
|
+
return null;
|
|
700
|
+
}
|
|
701
|
+
const numValue = typeof defaultValue === 'number'
|
|
702
|
+
? defaultValue
|
|
703
|
+
: parseNumber(String(defaultValue), format);
|
|
704
|
+
if (numValue === null || isNaN(numValue)) {
|
|
705
|
+
return undefined;
|
|
706
|
+
}
|
|
707
|
+
return applyDecimalPrecision(numValue, format);
|
|
708
|
+
};
|
|
676
709
|
|
|
677
710
|
/**
|
|
678
711
|
* Date input utilities for parsing, formatting, and validation
|
|
@@ -1031,24 +1064,11 @@ const getApiDataSource = async (dataSource, allValues, dataSourceRequestHandler,
|
|
|
1031
1064
|
// dependsOn can be either a data path (e.g., "person.address") or a widget-id
|
|
1032
1065
|
let depValue = null;
|
|
1033
1066
|
if (dataSource.dependsOn) {
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
depValue = allValues
|
|
1039
|
-
// Smart resolution: If not found at top level, try to find the dependency in the same nested object
|
|
1040
|
-
// by looking for other keys in allValues that might contain the dependency.
|
|
1041
|
-
// We look for objects that contain both the current widget's path (if we can guess it) and the dependency.
|
|
1042
|
-
// But since we don't know the current widget's path here, we search for any object that has this dependency key.
|
|
1043
|
-
if (depValue === null || depValue === undefined || depValue === '') {
|
|
1044
|
-
for (const val of Object.values(allValues)) {
|
|
1045
|
-
if (val && typeof val === 'object' && !Array.isArray(val) && dataSource.dependsOn in val) {
|
|
1046
|
-
depValue = val[dataSource.dependsOn];
|
|
1047
|
-
if (depValue !== null && depValue !== undefined && depValue !== '')
|
|
1048
|
-
break;
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1067
|
+
if (dataSource.dependsOn.includes('.')) {
|
|
1068
|
+
depValue = getValueByPath(allValues, dataSource.dependsOn);
|
|
1069
|
+
}
|
|
1070
|
+
else {
|
|
1071
|
+
depValue = resolveWidgetIdValue(allValues, dataSource.dependsOn);
|
|
1052
1072
|
}
|
|
1053
1073
|
if (depValue === null || depValue === undefined || depValue === '') {
|
|
1054
1074
|
// If dependency is empty, return empty array
|
|
@@ -1917,6 +1937,247 @@ const WidgetProvider = ({ store, dataSourceRequestHandler, schemaData, translate
|
|
|
1917
1937
|
return content;
|
|
1918
1938
|
};
|
|
1919
1939
|
|
|
1940
|
+
/**
|
|
1941
|
+
* Geo Hierarchy Builder
|
|
1942
|
+
* Manages geo hierarchy state and builds hierarchy JSON structure
|
|
1943
|
+
*/
|
|
1944
|
+
function extractLevelValueFromStored(value, geoConfig) {
|
|
1945
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
1946
|
+
return value;
|
|
1947
|
+
}
|
|
1948
|
+
const hierarchy = value.hierarchy || value.geo_code_hierarchy_json?.hierarchy;
|
|
1949
|
+
if (Array.isArray(hierarchy)) {
|
|
1950
|
+
const levelData = hierarchy.find((l) => l.level === geoConfig.level);
|
|
1951
|
+
if (levelData) {
|
|
1952
|
+
return levelData.level_value_id;
|
|
1953
|
+
}
|
|
1954
|
+
// Level absent from hierarchy (e.g. cleared by upstream cascade) — do not use lowest-level fallback
|
|
1955
|
+
return undefined;
|
|
1956
|
+
}
|
|
1957
|
+
if ('geo_lowest_level_value_id' in value) {
|
|
1958
|
+
return value.geo_lowest_level_value_id;
|
|
1959
|
+
}
|
|
1960
|
+
if ('lowest_level_value_id' in value) {
|
|
1961
|
+
return value.lowest_level_value_id;
|
|
1962
|
+
}
|
|
1963
|
+
if (value.geo_code_hierarchy_json?.lowest_level_value_id) {
|
|
1964
|
+
return value.geo_code_hierarchy_json.lowest_level_value_id;
|
|
1965
|
+
}
|
|
1966
|
+
if (value.geo_code_hierarchy_json?.geo_lowest_level_value_id) {
|
|
1967
|
+
return value.geo_code_hierarchy_json.geo_lowest_level_value_id;
|
|
1968
|
+
}
|
|
1969
|
+
return undefined;
|
|
1970
|
+
}
|
|
1971
|
+
/**
|
|
1972
|
+
* Resolve the display value for a geo level widget.
|
|
1973
|
+
* When widgetId is explicitly set in Redux (including cleared undefined/null), do not
|
|
1974
|
+
* fall back to shared hierarchy dataPath — that stale path was keeping grandchildren visible.
|
|
1975
|
+
*/
|
|
1976
|
+
function resolveGeoWidgetLevelValue(values, widgetId, dataPath, geoConfig) {
|
|
1977
|
+
if (Object.prototype.hasOwnProperty.call(values, widgetId)) {
|
|
1978
|
+
let value = values[widgetId];
|
|
1979
|
+
if (value === undefined || value === null || value === '') {
|
|
1980
|
+
return value;
|
|
1981
|
+
}
|
|
1982
|
+
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
1983
|
+
return extractLevelValueFromStored(value, geoConfig);
|
|
1984
|
+
}
|
|
1985
|
+
return value;
|
|
1986
|
+
}
|
|
1987
|
+
if (!dataPath) {
|
|
1988
|
+
return undefined;
|
|
1989
|
+
}
|
|
1990
|
+
let value = getWidgetValue(values, dataPath, widgetId);
|
|
1991
|
+
if (value !== null && value !== undefined && typeof value === 'object' && !Array.isArray(value)) {
|
|
1992
|
+
value = extractLevelValueFromStored(value, geoConfig);
|
|
1993
|
+
}
|
|
1994
|
+
return value;
|
|
1995
|
+
}
|
|
1996
|
+
/**
|
|
1997
|
+
* Write the in-memory geo hierarchy builder state into Redux at the shared dataPath.
|
|
1998
|
+
*/
|
|
1999
|
+
function applySharedGeoHierarchyToValues(baseValues, groupId, dataPath, widgetId) {
|
|
2000
|
+
const hierarchyJson = geoHierarchyBuilder.buildHierarchyJson(groupId);
|
|
2001
|
+
if (!dataPath || typeof dataPath !== 'string') {
|
|
2002
|
+
return baseValues;
|
|
2003
|
+
}
|
|
2004
|
+
const inner = hierarchyJson?.geo_code_hierarchy_json;
|
|
2005
|
+
const lowestId = hierarchyJson?.geo_lowest_level_value_id;
|
|
2006
|
+
if (dataPath.endsWith('.geo_code_hierarchy_json')) {
|
|
2007
|
+
const prefix = dataPath.substring(0, dataPath.lastIndexOf('.'));
|
|
2008
|
+
let finalUpdatedValues = setWidgetValue(baseValues, dataPath, widgetId, inner);
|
|
2009
|
+
finalUpdatedValues = setWidgetValue(finalUpdatedValues, `${prefix}.geo_lowest_level_value_id`, widgetId, lowestId);
|
|
2010
|
+
return finalUpdatedValues;
|
|
2011
|
+
}
|
|
2012
|
+
return setWidgetValue(baseValues, dataPath, widgetId, inner);
|
|
2013
|
+
}
|
|
2014
|
+
class GeoHierarchyBuilder {
|
|
2015
|
+
constructor() {
|
|
2016
|
+
this.hierarchies = new Map();
|
|
2017
|
+
}
|
|
2018
|
+
/**
|
|
2019
|
+
* Get or create hierarchy state for a group
|
|
2020
|
+
*/
|
|
2021
|
+
getHierarchy(groupId = 'default') {
|
|
2022
|
+
if (!this.hierarchies.has(groupId)) {
|
|
2023
|
+
this.hierarchies.set(groupId, {
|
|
2024
|
+
levels: new Map(),
|
|
2025
|
+
order: [],
|
|
2026
|
+
});
|
|
2027
|
+
}
|
|
2028
|
+
return this.hierarchies.get(groupId);
|
|
2029
|
+
}
|
|
2030
|
+
/**
|
|
2031
|
+
* Add a level to the hierarchy
|
|
2032
|
+
*/
|
|
2033
|
+
addLevel(level, level_value_id, level_value_mnemonic, groupId = 'default') {
|
|
2034
|
+
const hierarchy = this.getHierarchy(groupId);
|
|
2035
|
+
// If level already exists, remove it and everything after it
|
|
2036
|
+
const existingIndex = hierarchy.order.indexOf(level);
|
|
2037
|
+
if (existingIndex >= 0) {
|
|
2038
|
+
// Remove this level and all subsequent levels
|
|
2039
|
+
const levelsToRemove = hierarchy.order.slice(existingIndex);
|
|
2040
|
+
levelsToRemove.forEach((l) => {
|
|
2041
|
+
hierarchy.levels.delete(l);
|
|
2042
|
+
hierarchy.order = hierarchy.order.filter((o) => o !== l);
|
|
2043
|
+
});
|
|
2044
|
+
}
|
|
2045
|
+
// Add new level
|
|
2046
|
+
hierarchy.levels.set(level, {
|
|
2047
|
+
level,
|
|
2048
|
+
level_value_id,
|
|
2049
|
+
level_value_mnemonic,
|
|
2050
|
+
});
|
|
2051
|
+
hierarchy.order.push(level);
|
|
2052
|
+
}
|
|
2053
|
+
/**
|
|
2054
|
+
* Remove a level and all levels below it
|
|
2055
|
+
*/
|
|
2056
|
+
removeLevelAndBelow(level, groupId = 'default') {
|
|
2057
|
+
const hierarchy = this.getHierarchy(groupId);
|
|
2058
|
+
const index = hierarchy.order.indexOf(level);
|
|
2059
|
+
if (index >= 0) {
|
|
2060
|
+
// Remove this level and all subsequent levels
|
|
2061
|
+
const levelsToRemove = hierarchy.order.slice(index);
|
|
2062
|
+
levelsToRemove.forEach((l) => {
|
|
2063
|
+
hierarchy.levels.delete(l);
|
|
2064
|
+
hierarchy.order = hierarchy.order.filter((o) => o !== l);
|
|
2065
|
+
});
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
/**
|
|
2069
|
+
* Build hierarchy JSON structure
|
|
2070
|
+
*/
|
|
2071
|
+
buildHierarchyJson(groupId = 'default') {
|
|
2072
|
+
const hierarchy = this.getHierarchy(groupId);
|
|
2073
|
+
if (hierarchy.order.length === 0) {
|
|
2074
|
+
return null;
|
|
2075
|
+
}
|
|
2076
|
+
const hierarchyArray = hierarchy.order.map((level) => {
|
|
2077
|
+
const data = hierarchy.levels.get(level);
|
|
2078
|
+
return {
|
|
2079
|
+
level: data.level,
|
|
2080
|
+
level_value_id: data.level_value_id,
|
|
2081
|
+
level_value_mnemonic: data.level_value_mnemonic,
|
|
2082
|
+
};
|
|
2083
|
+
});
|
|
2084
|
+
const lowestLevel = hierarchy.order[hierarchy.order.length - 1];
|
|
2085
|
+
const lowestLevelData = hierarchy.levels.get(lowestLevel);
|
|
2086
|
+
return {
|
|
2087
|
+
geo_lowest_level_value_id: lowestLevelData.level_value_id,
|
|
2088
|
+
geo_code_hierarchy_json: {
|
|
2089
|
+
hierarchy: hierarchyArray,
|
|
2090
|
+
lowest_level_value_id: lowestLevelData.level_value_id,
|
|
2091
|
+
},
|
|
2092
|
+
};
|
|
2093
|
+
}
|
|
2094
|
+
/**
|
|
2095
|
+
* Clear hierarchy for a group
|
|
2096
|
+
*/
|
|
2097
|
+
clear(groupId = 'default') {
|
|
2098
|
+
this.hierarchies.delete(groupId);
|
|
2099
|
+
}
|
|
2100
|
+
/**
|
|
2101
|
+
* Clear all hierarchies
|
|
2102
|
+
*/
|
|
2103
|
+
clearAll() {
|
|
2104
|
+
this.hierarchies.clear();
|
|
2105
|
+
}
|
|
2106
|
+
/**
|
|
2107
|
+
* Get current levels for a group
|
|
2108
|
+
*/
|
|
2109
|
+
getLevels(groupId = 'default') {
|
|
2110
|
+
const hierarchy = this.getHierarchy(groupId);
|
|
2111
|
+
return hierarchy.order.map((level) => hierarchy.levels.get(level));
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
// Singleton instance
|
|
2115
|
+
const geoHierarchyBuilder = new GeoHierarchyBuilder();
|
|
2116
|
+
/** Sentinel written to Redux when a geo level is cleared by cascade (distinct from "never set"). */
|
|
2117
|
+
const GEO_LEVEL_CLEARED = null;
|
|
2118
|
+
const geoWidgetParentRegistry = new Map();
|
|
2119
|
+
function registerGeoWidgetParent(widgetId, parentWidgetId) {
|
|
2120
|
+
geoWidgetParentRegistry.set(widgetId, parentWidgetId || null);
|
|
2121
|
+
}
|
|
2122
|
+
function unregisterGeoWidgetParent(widgetId) {
|
|
2123
|
+
geoWidgetParentRegistry.delete(widgetId);
|
|
2124
|
+
}
|
|
2125
|
+
/** True when changedWidgetId is any upstream geo parent of widgetId (not only immediate parent). */
|
|
2126
|
+
function isUpstreamGeoAncestor(changedWidgetId, widgetId, immediateParentWidgetId) {
|
|
2127
|
+
if (changedWidgetId === widgetId) {
|
|
2128
|
+
return false;
|
|
2129
|
+
}
|
|
2130
|
+
let cursor = immediateParentWidgetId;
|
|
2131
|
+
while (cursor) {
|
|
2132
|
+
if (cursor === changedWidgetId) {
|
|
2133
|
+
return true;
|
|
2134
|
+
}
|
|
2135
|
+
cursor = geoWidgetParentRegistry.get(cursor) ?? null;
|
|
2136
|
+
}
|
|
2137
|
+
return false;
|
|
2138
|
+
}
|
|
2139
|
+
function readStoredHierarchyLevels(values, dataPath, widgetId) {
|
|
2140
|
+
const stored = getWidgetValue(values, dataPath, widgetId);
|
|
2141
|
+
const hierarchy = stored?.hierarchy || stored?.geo_code_hierarchy_json?.hierarchy;
|
|
2142
|
+
if (!Array.isArray(hierarchy)) {
|
|
2143
|
+
return [];
|
|
2144
|
+
}
|
|
2145
|
+
return hierarchy.filter((entry) => entry?.level && entry.level_value_id);
|
|
2146
|
+
}
|
|
2147
|
+
function builderMatchesStored(groupId, storedLevels) {
|
|
2148
|
+
const builderLevels = geoHierarchyBuilder.getLevels(groupId);
|
|
2149
|
+
if (builderLevels.length !== storedLevels.length) {
|
|
2150
|
+
return false;
|
|
2151
|
+
}
|
|
2152
|
+
return storedLevels.every((stored, index) => {
|
|
2153
|
+
const built = builderLevels[index];
|
|
2154
|
+
return (built.level === stored.level &&
|
|
2155
|
+
String(built.level_value_id) === String(stored.level_value_id));
|
|
2156
|
+
});
|
|
2157
|
+
}
|
|
2158
|
+
/** Seed in-memory builder from persisted hierarchy JSON (edit-mode rehydration). */
|
|
2159
|
+
function seedGeoHierarchyFromValues(values, dataPath, widgetId, groupId) {
|
|
2160
|
+
if (!dataPath || typeof dataPath !== 'string') {
|
|
2161
|
+
return;
|
|
2162
|
+
}
|
|
2163
|
+
const storedLevels = readStoredHierarchyLevels(values, dataPath, widgetId);
|
|
2164
|
+
if (storedLevels.length === 0) {
|
|
2165
|
+
return;
|
|
2166
|
+
}
|
|
2167
|
+
if (builderMatchesStored(groupId, storedLevels)) {
|
|
2168
|
+
return;
|
|
2169
|
+
}
|
|
2170
|
+
geoHierarchyBuilder.clear(groupId);
|
|
2171
|
+
storedLevels.forEach((entry) => {
|
|
2172
|
+
geoHierarchyBuilder.addLevel(entry.level, String(entry.level_value_id), entry.level_value_mnemonic || String(entry.level_value_id), groupId);
|
|
2173
|
+
});
|
|
2174
|
+
}
|
|
2175
|
+
/** Force-clear builder for a group, then seed from Redux/schema values (e.g. after Cancel). */
|
|
2176
|
+
function resetAndSeedGeoHierarchyFromValues(values, dataPath, widgetId, groupId) {
|
|
2177
|
+
geoHierarchyBuilder.clear(groupId);
|
|
2178
|
+
seedGeoHierarchyFromValues(values, dataPath, widgetId, groupId);
|
|
2179
|
+
}
|
|
2180
|
+
|
|
1920
2181
|
// Define stable empty arrays to avoid selector reference issues
|
|
1921
2182
|
const EMPTY_ERRORS = [];
|
|
1922
2183
|
const EMPTY_DATA_SOURCE$1 = [];
|
|
@@ -2006,6 +2267,17 @@ const useBaseWidget = (options) => {
|
|
|
2006
2267
|
if (isLayoutWidget) {
|
|
2007
2268
|
return undefined; // Layout widgets don't have values
|
|
2008
2269
|
}
|
|
2270
|
+
const geoConfig = config['widget-geo-config'];
|
|
2271
|
+
if (geoConfig) {
|
|
2272
|
+
const value = resolveGeoWidgetLevelValue(values, widgetId, config['widget-data-path'], geoConfig);
|
|
2273
|
+
if (userHasSetValueRef.current) {
|
|
2274
|
+
return value;
|
|
2275
|
+
}
|
|
2276
|
+
if (value === null) {
|
|
2277
|
+
return null;
|
|
2278
|
+
}
|
|
2279
|
+
return value !== undefined ? value : config['widget-data-default'];
|
|
2280
|
+
}
|
|
2009
2281
|
// Try to get value from widgetId first (this should have the actual selected value)
|
|
2010
2282
|
// For geo widgets with dataPath, widgetId stores the actual ID, while dataPath stores the hierarchy object
|
|
2011
2283
|
let value = values[widgetId];
|
|
@@ -2215,6 +2487,14 @@ const useBaseWidget = (options) => {
|
|
|
2215
2487
|
// Track readonly state explicitly to detect changes
|
|
2216
2488
|
// Use JSON.stringify to create a stable reference for the dependency array
|
|
2217
2489
|
const isReadonly = config['widget-readonly'] ?? false;
|
|
2490
|
+
// Leaving edit mode (Cancel): allow mirror/rehydration on next Edit
|
|
2491
|
+
React.useEffect(() => {
|
|
2492
|
+
if (config['widget-readonly']) {
|
|
2493
|
+
userHasSetValueRef.current = false;
|
|
2494
|
+
lastMirroredValueRef.current = null;
|
|
2495
|
+
lastDispatchedValueRef.current = null;
|
|
2496
|
+
}
|
|
2497
|
+
}, [config['widget-readonly']]);
|
|
2218
2498
|
const dataSource = config['widget-data-source'];
|
|
2219
2499
|
const geoConfig = config['widget-geo-config'];
|
|
2220
2500
|
// Use ref to store handler to avoid stale closures
|
|
@@ -2419,113 +2699,6 @@ const useWidgetCascade = (options) => {
|
|
|
2419
2699
|
}, [cascadeConfig, eventBus, dataSource, widgetId, dispatch]);
|
|
2420
2700
|
};
|
|
2421
2701
|
|
|
2422
|
-
/**
|
|
2423
|
-
* Geo Hierarchy Builder
|
|
2424
|
-
* Manages geo hierarchy state and builds hierarchy JSON structure
|
|
2425
|
-
*/
|
|
2426
|
-
class GeoHierarchyBuilder {
|
|
2427
|
-
constructor() {
|
|
2428
|
-
this.hierarchies = new Map();
|
|
2429
|
-
}
|
|
2430
|
-
/**
|
|
2431
|
-
* Get or create hierarchy state for a group
|
|
2432
|
-
*/
|
|
2433
|
-
getHierarchy(groupId = 'default') {
|
|
2434
|
-
if (!this.hierarchies.has(groupId)) {
|
|
2435
|
-
this.hierarchies.set(groupId, {
|
|
2436
|
-
levels: new Map(),
|
|
2437
|
-
order: [],
|
|
2438
|
-
});
|
|
2439
|
-
}
|
|
2440
|
-
return this.hierarchies.get(groupId);
|
|
2441
|
-
}
|
|
2442
|
-
/**
|
|
2443
|
-
* Add a level to the hierarchy
|
|
2444
|
-
*/
|
|
2445
|
-
addLevel(level, level_value_id, level_value_mnemonic, groupId = 'default') {
|
|
2446
|
-
const hierarchy = this.getHierarchy(groupId);
|
|
2447
|
-
// If level already exists, remove it and everything after it
|
|
2448
|
-
const existingIndex = hierarchy.order.indexOf(level);
|
|
2449
|
-
if (existingIndex >= 0) {
|
|
2450
|
-
// Remove this level and all subsequent levels
|
|
2451
|
-
const levelsToRemove = hierarchy.order.slice(existingIndex);
|
|
2452
|
-
levelsToRemove.forEach((l) => {
|
|
2453
|
-
hierarchy.levels.delete(l);
|
|
2454
|
-
hierarchy.order = hierarchy.order.filter((o) => o !== l);
|
|
2455
|
-
});
|
|
2456
|
-
}
|
|
2457
|
-
// Add new level
|
|
2458
|
-
hierarchy.levels.set(level, {
|
|
2459
|
-
level,
|
|
2460
|
-
level_value_id,
|
|
2461
|
-
level_value_mnemonic,
|
|
2462
|
-
});
|
|
2463
|
-
hierarchy.order.push(level);
|
|
2464
|
-
}
|
|
2465
|
-
/**
|
|
2466
|
-
* Remove a level and all levels below it
|
|
2467
|
-
*/
|
|
2468
|
-
removeLevelAndBelow(level, groupId = 'default') {
|
|
2469
|
-
const hierarchy = this.getHierarchy(groupId);
|
|
2470
|
-
const index = hierarchy.order.indexOf(level);
|
|
2471
|
-
if (index >= 0) {
|
|
2472
|
-
// Remove this level and all subsequent levels
|
|
2473
|
-
const levelsToRemove = hierarchy.order.slice(index);
|
|
2474
|
-
levelsToRemove.forEach((l) => {
|
|
2475
|
-
hierarchy.levels.delete(l);
|
|
2476
|
-
hierarchy.order = hierarchy.order.filter((o) => o !== l);
|
|
2477
|
-
});
|
|
2478
|
-
}
|
|
2479
|
-
}
|
|
2480
|
-
/**
|
|
2481
|
-
* Build hierarchy JSON structure
|
|
2482
|
-
*/
|
|
2483
|
-
buildHierarchyJson(groupId = 'default') {
|
|
2484
|
-
const hierarchy = this.getHierarchy(groupId);
|
|
2485
|
-
if (hierarchy.order.length === 0) {
|
|
2486
|
-
return null;
|
|
2487
|
-
}
|
|
2488
|
-
const hierarchyArray = hierarchy.order.map((level) => {
|
|
2489
|
-
const data = hierarchy.levels.get(level);
|
|
2490
|
-
return {
|
|
2491
|
-
level: data.level,
|
|
2492
|
-
level_value_id: data.level_value_id,
|
|
2493
|
-
level_value_mnemonic: data.level_value_mnemonic,
|
|
2494
|
-
};
|
|
2495
|
-
});
|
|
2496
|
-
const lowestLevel = hierarchy.order[hierarchy.order.length - 1];
|
|
2497
|
-
const lowestLevelData = hierarchy.levels.get(lowestLevel);
|
|
2498
|
-
return {
|
|
2499
|
-
geo_lowest_level_value_id: lowestLevelData.level_value_id,
|
|
2500
|
-
geo_code_hierarchy_json: {
|
|
2501
|
-
hierarchy: hierarchyArray,
|
|
2502
|
-
lowest_level_value_id: lowestLevelData.level_value_id,
|
|
2503
|
-
},
|
|
2504
|
-
};
|
|
2505
|
-
}
|
|
2506
|
-
/**
|
|
2507
|
-
* Clear hierarchy for a group
|
|
2508
|
-
*/
|
|
2509
|
-
clear(groupId = 'default') {
|
|
2510
|
-
this.hierarchies.delete(groupId);
|
|
2511
|
-
}
|
|
2512
|
-
/**
|
|
2513
|
-
* Clear all hierarchies
|
|
2514
|
-
*/
|
|
2515
|
-
clearAll() {
|
|
2516
|
-
this.hierarchies.clear();
|
|
2517
|
-
}
|
|
2518
|
-
/**
|
|
2519
|
-
* Get current levels for a group
|
|
2520
|
-
*/
|
|
2521
|
-
getLevels(groupId = 'default') {
|
|
2522
|
-
const hierarchy = this.getHierarchy(groupId);
|
|
2523
|
-
return hierarchy.order.map((level) => hierarchy.levels.get(level));
|
|
2524
|
-
}
|
|
2525
|
-
}
|
|
2526
|
-
// Singleton instance
|
|
2527
|
-
const geoHierarchyBuilder = new GeoHierarchyBuilder();
|
|
2528
|
-
|
|
2529
2702
|
// Define stable empty array to avoid selector reference issues
|
|
2530
2703
|
const EMPTY_DATA_SOURCE = [];
|
|
2531
2704
|
/**
|
|
@@ -2545,138 +2718,108 @@ const useGeoWidgetCascade = (options) => {
|
|
|
2545
2718
|
: 'default';
|
|
2546
2719
|
const valuesRef = React.useRef(values);
|
|
2547
2720
|
const handlerRef = React.useRef(dataSourceRequestHandler);
|
|
2721
|
+
const lastCascadePublishRef = React.useRef(undefined);
|
|
2548
2722
|
// Keep refs updated
|
|
2549
2723
|
React.useEffect(() => {
|
|
2550
2724
|
valuesRef.current = values;
|
|
2551
2725
|
handlerRef.current = dataSourceRequestHandler;
|
|
2552
2726
|
}, [values, dataSourceRequestHandler]);
|
|
2553
2727
|
// Get current value and data source options
|
|
2554
|
-
const currentValue = reactRedux.useSelector((state) =>
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
// If not found in widgetId, try dataPath
|
|
2558
|
-
if (value === undefined && dataPath) {
|
|
2559
|
-
value = getWidgetValue(state.widget.values, dataPath, widgetId);
|
|
2560
|
-
}
|
|
2561
|
-
// Extract value if it's a geo hierarchy object
|
|
2562
|
-
if (value && typeof value === 'object' && !Array.isArray(value) && geoConfig) {
|
|
2563
|
-
const hierarchy = value.hierarchy || value.geo_code_hierarchy_json?.hierarchy;
|
|
2564
|
-
if (Array.isArray(hierarchy)) {
|
|
2565
|
-
const levelData = hierarchy.find((l) => l.level === geoConfig.level);
|
|
2566
|
-
if (levelData) {
|
|
2567
|
-
return levelData.level_value_id;
|
|
2568
|
-
}
|
|
2569
|
-
}
|
|
2570
|
-
// Extended fallbacks (matching useBaseWidget)
|
|
2571
|
-
if ('geo_lowest_level_value_id' in value) {
|
|
2572
|
-
return value.geo_lowest_level_value_id;
|
|
2573
|
-
}
|
|
2574
|
-
if ('lowest_level_value_id' in value) {
|
|
2575
|
-
return value.lowest_level_value_id;
|
|
2576
|
-
}
|
|
2577
|
-
if (value.geo_code_hierarchy_json?.lowest_level_value_id) {
|
|
2578
|
-
return value.geo_code_hierarchy_json.lowest_level_value_id;
|
|
2579
|
-
}
|
|
2580
|
-
if (value.geo_code_hierarchy_json?.geo_lowest_level_value_id) {
|
|
2581
|
-
return value.geo_code_hierarchy_json.geo_lowest_level_value_id;
|
|
2582
|
-
}
|
|
2583
|
-
}
|
|
2584
|
-
return value;
|
|
2585
|
-
});
|
|
2728
|
+
const currentValue = reactRedux.useSelector((state) => geoConfig
|
|
2729
|
+
? resolveGeoWidgetLevelValue(state.widget.values, widgetId, dataPath, geoConfig)
|
|
2730
|
+
: state.widget.values[widgetId]);
|
|
2586
2731
|
// Memoize selector to avoid returning new array reference
|
|
2587
2732
|
const dataSourceOptions = reactRedux.useSelector((state) => state.widget.dataSources[widgetId] ?? EMPTY_DATA_SOURCE);
|
|
2733
|
+
// Register parent chain for upstream-ancestor detection (grandparent → grandchild reset)
|
|
2734
|
+
React.useEffect(() => {
|
|
2735
|
+
if (!geoConfig) {
|
|
2736
|
+
return;
|
|
2737
|
+
}
|
|
2738
|
+
registerGeoWidgetParent(widgetId, geoConfig.parentWidgetId);
|
|
2739
|
+
return () => unregisterGeoWidgetParent(widgetId);
|
|
2740
|
+
}, [widgetId, geoConfig]);
|
|
2741
|
+
// Keep in-memory builder in sync with persisted hierarchy (reload, cancel→re-edit, etc.)
|
|
2742
|
+
React.useEffect(() => {
|
|
2743
|
+
if (!geoConfig || typeof dataPath !== 'string') {
|
|
2744
|
+
return;
|
|
2745
|
+
}
|
|
2746
|
+
seedGeoHierarchyFromValues(values, dataPath, widgetId, groupId);
|
|
2747
|
+
}, [geoConfig, dataPath, widgetId, groupId, values]);
|
|
2588
2748
|
React.useEffect(() => {
|
|
2589
2749
|
if (!geoConfig || !eventBus || !dataSource || dataSource.type !== 'api') {
|
|
2590
2750
|
return;
|
|
2591
2751
|
}
|
|
2592
|
-
const { level, isLastLevel, parentWidgetId } = geoConfig;
|
|
2593
|
-
|
|
2594
|
-
if (parentWidgetId) {
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
// This ensures we don't accidentally overwrite the parent widget's value
|
|
2637
|
-
dispatch(setValue({ widgetId, value: undefined }));
|
|
2638
|
-
}
|
|
2639
|
-
}
|
|
2640
|
-
}
|
|
2641
|
-
else {
|
|
2642
|
-
dispatch(setValue({ widgetId, value: undefined }));
|
|
2752
|
+
const { level, isLastLevel, parentWidgetId: rawParentWidgetId } = geoConfig;
|
|
2753
|
+
const parentWidgetId = rawParentWidgetId || null;
|
|
2754
|
+
if (!parentWidgetId) {
|
|
2755
|
+
return;
|
|
2756
|
+
}
|
|
2757
|
+
const clearThisLevel = (baseValues) => {
|
|
2758
|
+
geoHierarchyBuilder.removeLevelAndBelow(level, groupId);
|
|
2759
|
+
if (dataPath) {
|
|
2760
|
+
dispatch(setValues(applySharedGeoHierarchyToValues(baseValues, groupId, dataPath, widgetId)));
|
|
2761
|
+
}
|
|
2762
|
+
dispatch(setValue({ widgetId, value: GEO_LEVEL_CLEARED }));
|
|
2763
|
+
if (!isLastLevel) {
|
|
2764
|
+
eventBus.publish({
|
|
2765
|
+
type: 'widget:change',
|
|
2766
|
+
widgetId,
|
|
2767
|
+
value: GEO_LEVEL_CLEARED,
|
|
2768
|
+
timestamp: Date.now(),
|
|
2769
|
+
});
|
|
2770
|
+
}
|
|
2771
|
+
dispatch(setDataSource({ widgetId, data: [] }));
|
|
2772
|
+
};
|
|
2773
|
+
const handleParentChange = async (event) => {
|
|
2774
|
+
const isDirectParent = event.widgetId === parentWidgetId;
|
|
2775
|
+
const isAncestor = isUpstreamGeoAncestor(event.widgetId, widgetId, parentWidgetId);
|
|
2776
|
+
if (!isDirectParent && !isAncestor) {
|
|
2777
|
+
return;
|
|
2778
|
+
}
|
|
2779
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
2780
|
+
const currentValues = valuesRef.current;
|
|
2781
|
+
const currentHandler = handlerRef.current;
|
|
2782
|
+
// Grandparent (or higher) changed: clear this level; only immediate parent drives reload
|
|
2783
|
+
if (isAncestor && !isDirectParent) {
|
|
2784
|
+
clearThisLevel(currentValues);
|
|
2785
|
+
return;
|
|
2786
|
+
}
|
|
2787
|
+
const parentCleared = event.value === undefined ||
|
|
2788
|
+
event.value === null ||
|
|
2789
|
+
event.value === '' ||
|
|
2790
|
+
event.value === GEO_LEVEL_CLEARED;
|
|
2791
|
+
let parentValue = event.value;
|
|
2792
|
+
if (!parentCleared && (parentValue === undefined || parentValue === null)) {
|
|
2793
|
+
parentValue = currentValues[parentWidgetId];
|
|
2794
|
+
if (parentValue === undefined && dataSource.dependsOn) {
|
|
2795
|
+
parentValue = getWidgetValue(currentValues, dataSource.dependsOn, '');
|
|
2643
2796
|
}
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
const valueKey = dataSource.valueKey || 'level_value_id';
|
|
2659
|
-
const labelKey = dataSource.labelKey || 'level_value_mnemonic';
|
|
2660
|
-
const transformed = transformDataSourceOptions(data, valueKey, labelKey);
|
|
2661
|
-
dispatch(setDataSource({ widgetId, data: transformed }));
|
|
2662
|
-
}
|
|
2663
|
-
catch (error) {
|
|
2664
|
-
console.error('Error reloading geo data source:', error);
|
|
2665
|
-
dispatch(setDataSource({ widgetId, data: [] }));
|
|
2666
|
-
}
|
|
2797
|
+
}
|
|
2798
|
+
clearThisLevel(currentValues);
|
|
2799
|
+
if (currentHandler && parentValue !== null && parentValue !== undefined && parentValue !== '') {
|
|
2800
|
+
try {
|
|
2801
|
+
const updatedValues = {
|
|
2802
|
+
...currentValues,
|
|
2803
|
+
[parentWidgetId]: parentValue,
|
|
2804
|
+
};
|
|
2805
|
+
const levelId = geoConfig.level;
|
|
2806
|
+
const data = await getApiDataSource(dataSource, updatedValues, currentHandler, levelId);
|
|
2807
|
+
const valueKey = dataSource.valueKey || 'level_value_id';
|
|
2808
|
+
const labelKey = dataSource.labelKey || 'level_value_mnemonic';
|
|
2809
|
+
const transformed = transformDataSourceOptions(data, valueKey, labelKey);
|
|
2810
|
+
dispatch(setDataSource({ widgetId, data: transformed }));
|
|
2667
2811
|
}
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
geoHierarchyBuilder.removeLevelAndBelow(level, groupId);
|
|
2812
|
+
catch (error) {
|
|
2813
|
+
console.error('Error reloading geo data source:', error);
|
|
2671
2814
|
dispatch(setDataSource({ widgetId, data: [] }));
|
|
2672
2815
|
}
|
|
2673
|
-
}
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
}
|
|
2679
|
-
}, [geoConfig, eventBus, dataSource, widgetId, dataPath, dispatch]);
|
|
2816
|
+
}
|
|
2817
|
+
};
|
|
2818
|
+
const unsubscribe = eventBus.subscribe('widget:change', handleParentChange);
|
|
2819
|
+
return () => {
|
|
2820
|
+
unsubscribe();
|
|
2821
|
+
};
|
|
2822
|
+
}, [geoConfig, eventBus, dataSource, widgetId, dataPath, dispatch, groupId]);
|
|
2680
2823
|
// Handle value changes to build hierarchy
|
|
2681
2824
|
React.useEffect(() => {
|
|
2682
2825
|
if (!geoConfig) {
|
|
@@ -2685,22 +2828,20 @@ const useGeoWidgetCascade = (options) => {
|
|
|
2685
2828
|
// Skip if value is undefined (it might still be loading or rehydrating)
|
|
2686
2829
|
// ONLY clear hierarchy if the value is explicitly null or empty string (user action)
|
|
2687
2830
|
if (currentValue === null || currentValue === '') {
|
|
2688
|
-
const { level } = geoConfig;
|
|
2831
|
+
const { level, isLastLevel } = geoConfig;
|
|
2689
2832
|
geoHierarchyBuilder.removeLevelAndBelow(level, groupId);
|
|
2690
2833
|
// If we have a dataPath, we need to update Redux with the cleared hierarchy
|
|
2691
2834
|
if (dataPath) {
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
}
|
|
2703
|
-
dispatch(setValues(finalUpdatedValues));
|
|
2835
|
+
dispatch(setValues(applySharedGeoHierarchyToValues(valuesRef.current, groupId, dataPath, widgetId)));
|
|
2836
|
+
}
|
|
2837
|
+
if (!isLastLevel && eventBus && lastCascadePublishRef.current !== GEO_LEVEL_CLEARED) {
|
|
2838
|
+
lastCascadePublishRef.current = GEO_LEVEL_CLEARED;
|
|
2839
|
+
eventBus.publish({
|
|
2840
|
+
type: 'widget:change',
|
|
2841
|
+
widgetId,
|
|
2842
|
+
value: GEO_LEVEL_CLEARED,
|
|
2843
|
+
timestamp: Date.now(),
|
|
2844
|
+
});
|
|
2704
2845
|
}
|
|
2705
2846
|
return;
|
|
2706
2847
|
}
|
|
@@ -2751,30 +2892,20 @@ const useGeoWidgetCascade = (options) => {
|
|
|
2751
2892
|
// Add level to hierarchy
|
|
2752
2893
|
geoHierarchyBuilder.addLevel(level, level_value_id, level_value_mnemonic, groupId);
|
|
2753
2894
|
// Build and store hierarchy JSON on every change
|
|
2754
|
-
if (dataPath) {
|
|
2755
|
-
|
|
2756
|
-
if (hierarchyJson) {
|
|
2757
|
-
// Fix: Avoid double nesting of geo_code_hierarchy_json
|
|
2758
|
-
// If dataPath ends with .geo_code_hierarchy_json, we want to save the content directly to it
|
|
2759
|
-
// and save the lowest level ID as a sibling
|
|
2760
|
-
let finalUpdatedValues = valuesRef.current;
|
|
2761
|
-
if (typeof dataPath === 'string' && dataPath.endsWith('.geo_code_hierarchy_json')) {
|
|
2762
|
-
const prefix = dataPath.substring(0, dataPath.lastIndexOf('.'));
|
|
2763
|
-
// Save hierarchy JSON content directly to dataPath (avoiding double nesting)
|
|
2764
|
-
finalUpdatedValues = setWidgetValue(finalUpdatedValues, dataPath, widgetId, hierarchyJson.geo_code_hierarchy_json);
|
|
2765
|
-
// Save lowest level ID as sibling
|
|
2766
|
-
finalUpdatedValues = setWidgetValue(finalUpdatedValues, `${prefix}.geo_lowest_level_value_id`, widgetId, hierarchyJson.geo_lowest_level_value_id);
|
|
2767
|
-
}
|
|
2768
|
-
else {
|
|
2769
|
-
// Fallback if path doesn't follow the naming convention
|
|
2770
|
-
finalUpdatedValues = setWidgetValue(finalUpdatedValues, dataPath, widgetId, hierarchyJson.geo_code_hierarchy_json);
|
|
2771
|
-
}
|
|
2772
|
-
// CRITICAL: Use setValues for deep merge instead of replacing root keys with setValue
|
|
2773
|
-
// setWidgetValue returns the complete updated state object with all keys preserved
|
|
2774
|
-
dispatch(setValues(finalUpdatedValues));
|
|
2775
|
-
}
|
|
2895
|
+
if (dataPath && geoHierarchyBuilder.buildHierarchyJson(groupId)) {
|
|
2896
|
+
dispatch(setValues(applySharedGeoHierarchyToValues(valuesRef.current, groupId, dataPath, widgetId)));
|
|
2776
2897
|
}
|
|
2777
|
-
|
|
2898
|
+
// Notify descendants when this level changes via hierarchy/rehydration (handleChange may not run).
|
|
2899
|
+
if (!isLastLevel && eventBus && lastCascadePublishRef.current !== level_value_id) {
|
|
2900
|
+
lastCascadePublishRef.current = level_value_id;
|
|
2901
|
+
eventBus.publish({
|
|
2902
|
+
type: 'widget:change',
|
|
2903
|
+
widgetId,
|
|
2904
|
+
value: level_value_id,
|
|
2905
|
+
timestamp: Date.now(),
|
|
2906
|
+
});
|
|
2907
|
+
}
|
|
2908
|
+
}, [geoConfig, currentValue, widgetId, dataPath, dispatch, dataSourceOptions, eventBus, groupId]);
|
|
2778
2909
|
};
|
|
2779
2910
|
|
|
2780
2911
|
class WidgetRegistry {
|
|
@@ -7447,7 +7578,18 @@ const TextInputWidget = ({ config }) => {
|
|
|
7447
7578
|
};
|
|
7448
7579
|
|
|
7449
7580
|
const NumberInputWidget = ({ config }) => {
|
|
7450
|
-
const
|
|
7581
|
+
const resolvedConfig = React.useMemo(() => {
|
|
7582
|
+
const rawDefault = config['widget-data-default'];
|
|
7583
|
+
if (rawDefault === undefined) {
|
|
7584
|
+
return config;
|
|
7585
|
+
}
|
|
7586
|
+
const normalizedDefault = normalizeNumericDefault(rawDefault, config['widget-data-format']);
|
|
7587
|
+
if (normalizedDefault === undefined || normalizedDefault === rawDefault) {
|
|
7588
|
+
return config;
|
|
7589
|
+
}
|
|
7590
|
+
return { ...config, 'widget-data-default': normalizedDefault };
|
|
7591
|
+
}, [config]);
|
|
7592
|
+
const { value, formattedValue, error, touched, isEnabled, onChange, onBlur, config: widgetConfig, } = useBaseWidget({ config: resolvedConfig });
|
|
7451
7593
|
const { translate, translateConfig } = useWidgetTranslation();
|
|
7452
7594
|
const formatConfig = widgetConfig['widget-data-format'];
|
|
7453
7595
|
const validationConfig = widgetConfig['widget-data-validation'];
|
|
@@ -8762,16 +8904,65 @@ const DisplayWidget = ({ config }) => {
|
|
|
8762
8904
|
return (jsxRuntimeExports.jsxs("div", { className: "mb-[10px] DisplayFieldWidget flex flex-col sm:flex-row sm:items-start", children: [jsxRuntimeExports.jsxs("div", { className: "text-base text-gray-600 font-medium md:min-w-[120px] sm:pr-4 mb-1 sm:mb-0", style: { fontFamily: 'Roboto, sans-serif' }, title: label, children: [label, ":"] }), jsxRuntimeExports.jsx("div", { className: "flex-1 min-w-0", children: jsxRuntimeExports.jsx("div", { className: "text-base text-gray-900 font-medium", title: String(displayValue ?? ''), children: displayValue }) })] }));
|
|
8763
8905
|
};
|
|
8764
8906
|
|
|
8907
|
+
const getDateColumnConstraintError = (column, cellValue, rowValues, translateConfig) => {
|
|
8908
|
+
const displayValue = cellValue && typeof cellValue === 'string' ? cellValue.split('T')[0] : '';
|
|
8909
|
+
if (!displayValue) {
|
|
8910
|
+
return null;
|
|
8911
|
+
}
|
|
8912
|
+
const optionsConfig = column['widget-data-options'];
|
|
8913
|
+
const formatConfig = column['widget-data-format'];
|
|
8914
|
+
const dateConstraint = formatConfig?.dateConstraint || 'any';
|
|
8915
|
+
const minDate = optionsConfig?.minDate;
|
|
8916
|
+
const maxDate = optionsConfig?.maxDate;
|
|
8917
|
+
const minDateField = optionsConfig?.minDateField;
|
|
8918
|
+
const maxDateField = optionsConfig?.maxDateField;
|
|
8919
|
+
const minDateMessage = optionsConfig?.minDateMessage
|
|
8920
|
+
? translateConfig(optionsConfig.minDateMessage)
|
|
8921
|
+
: undefined;
|
|
8922
|
+
const maxDateMessage = optionsConfig?.maxDateMessage
|
|
8923
|
+
? translateConfig(optionsConfig.maxDateMessage)
|
|
8924
|
+
: undefined;
|
|
8925
|
+
const resolveSiblingDate = (fieldRef) => {
|
|
8926
|
+
if (!fieldRef) {
|
|
8927
|
+
return undefined;
|
|
8928
|
+
}
|
|
8929
|
+
const raw = getValueByPath(rowValues, fieldRef) ?? rowValues[fieldRef];
|
|
8930
|
+
return resolveDateBoundFromFieldValue(raw);
|
|
8931
|
+
};
|
|
8932
|
+
const effectiveMinDate = mergeMinDateBounds(getMinDate(dateConstraint, minDate), resolveSiblingDate(minDateField));
|
|
8933
|
+
const effectiveMaxDate = mergeMaxDateBounds(getMaxDate(dateConstraint, maxDate), resolveSiblingDate(maxDateField));
|
|
8934
|
+
return validateDateConstraints(displayValue, effectiveMinDate, effectiveMaxDate, dateConstraint, { minDateMessage, maxDateMessage });
|
|
8935
|
+
};
|
|
8936
|
+
const isTableRowDataValid = (rowData, columns, tableReadonly, translateConfig) => {
|
|
8937
|
+
for (const col of columns) {
|
|
8938
|
+
if (tableReadonly || col['widget-readonly'] === true) {
|
|
8939
|
+
continue;
|
|
8940
|
+
}
|
|
8941
|
+
const columnKey = col['column-key'];
|
|
8942
|
+
const cellValue = rowData[columnKey];
|
|
8943
|
+
const widgetErrors = validateWidget(cellValue, col['widget-data-validation'], col['widget-required']);
|
|
8944
|
+
if (widgetErrors.length > 0) {
|
|
8945
|
+
return false;
|
|
8946
|
+
}
|
|
8947
|
+
if ((col.widget || 'text') === 'date') {
|
|
8948
|
+
const dateError = getDateColumnConstraintError(col, cellValue, rowData, translateConfig);
|
|
8949
|
+
if (dateError) {
|
|
8950
|
+
return false;
|
|
8951
|
+
}
|
|
8952
|
+
}
|
|
8953
|
+
}
|
|
8954
|
+
return true;
|
|
8955
|
+
};
|
|
8765
8956
|
const TableCellSelect = ({ config, value, onValueChange }) => {
|
|
8766
8957
|
const { translate } = useWidgetTranslation();
|
|
8767
8958
|
// Use useBaseWidget to get data source options (it handles loading)
|
|
8768
8959
|
const { dataSourceOptions, loading, config: widgetConfig, } = useBaseWidget({ config });
|
|
8769
8960
|
const isReadonly = config['widget-readonly'] || false;
|
|
8770
|
-
return (jsxRuntimeExports.jsxs("select", { value: value || '', onChange: (e) => onValueChange(e.target.value), disabled: isReadonly || loading, className: `w-full h-[28px] px-2 text-sm border focus:outline-none ${isReadonly || loading ? 'cursor-not-allowed' : ''} table-cell-input`, style: {
|
|
8771
|
-
|
|
8772
|
-
|
|
8773
|
-
|
|
8774
|
-
|
|
8961
|
+
return (jsxRuntimeExports.jsxs("div", { className: "table-cell-field w-full", children: [jsxRuntimeExports.jsxs("select", { value: value || '', onChange: (e) => onValueChange(e.target.value), disabled: isReadonly || loading, className: `w-full h-[28px] px-2 text-sm border focus:outline-none ${isReadonly || loading ? 'cursor-not-allowed' : ''} table-cell-input`, style: {
|
|
8962
|
+
borderRadius: '10px',
|
|
8963
|
+
borderColor: 'var(--owt-widget-input-border, #C4C4C4)',
|
|
8964
|
+
backgroundColor: isReadonly || loading ? 'var(--owt-color-bg-alt, #F6F6F6)' : 'var(--owt-color-bg, #FFFFFF)',
|
|
8965
|
+
}, children: [jsxRuntimeExports.jsx("option", { value: "", children: translate('common.select') || 'Select' }), dataSourceOptions.map((option) => (jsxRuntimeExports.jsx("option", { value: option.value, children: option.label }, option.value)))] }), jsxRuntimeExports.jsx("p", { className: "table-cell-field-error", "aria-hidden": "true", children: '\u00a0' })] }));
|
|
8775
8966
|
};
|
|
8776
8967
|
const SelectDisplayValue$1 = ({ config, value }) => {
|
|
8777
8968
|
const { dataSourceOptions, loading } = useBaseWidget({ config });
|
|
@@ -8790,11 +8981,11 @@ const TableCellText = ({ config, value, onValueChange }) => {
|
|
|
8790
8981
|
config['widget-data-format'];
|
|
8791
8982
|
const maxLength = config['widget-data-validation']?.maxLength;
|
|
8792
8983
|
const displayValue = value !== null && value !== undefined ? String(value) : '';
|
|
8793
|
-
return (jsxRuntimeExports.jsx("input", { type: "text", value: displayValue, onChange: (e) => onValueChange(e.target.value), disabled: isReadonly, placeholder: placeholder, maxLength: maxLength, className: `w-full h-[28px] px-2 text-sm border focus:outline-none ${isReadonly ? 'cursor-not-allowed' : ''} table-cell-input`, style: {
|
|
8794
|
-
|
|
8795
|
-
|
|
8796
|
-
|
|
8797
|
-
|
|
8984
|
+
return (jsxRuntimeExports.jsxs("div", { className: "table-cell-field w-full", children: [jsxRuntimeExports.jsx("input", { type: "text", value: displayValue, onChange: (e) => onValueChange(e.target.value), disabled: isReadonly, placeholder: placeholder, maxLength: maxLength, className: `w-full h-[28px] px-2 text-sm border focus:outline-none ${isReadonly ? 'cursor-not-allowed' : ''} table-cell-input`, style: {
|
|
8985
|
+
borderRadius: '10px',
|
|
8986
|
+
borderColor: 'var(--owt-widget-input-border, #C4C4C4)',
|
|
8987
|
+
backgroundColor: isReadonly ? 'var(--owt-color-bg-alt, #F6F6F6)' : 'var(--owt-color-bg, #FFFFFF)',
|
|
8988
|
+
} }), jsxRuntimeExports.jsx("p", { className: "table-cell-field-error", "aria-hidden": "true", children: '\u00a0' })] }));
|
|
8798
8989
|
};
|
|
8799
8990
|
const TableCellNumber = ({ config, value, onValueChange }) => {
|
|
8800
8991
|
const isReadonly = config['widget-readonly'] || false;
|
|
@@ -8817,11 +9008,11 @@ const TableCellNumber = ({ config, value, onValueChange }) => {
|
|
|
8817
9008
|
onValueChange(inputValue);
|
|
8818
9009
|
}
|
|
8819
9010
|
};
|
|
8820
|
-
return (jsxRuntimeExports.jsx("input", { type: "number", value: displayValue, onChange: handleChange, disabled: isReadonly, placeholder: placeholder, min: validationConfig?.min, max: validationConfig?.max, step: formatConfig?.decimalPlaces ? Math.pow(0.1, formatConfig.decimalPlaces) : undefined, className: `w-full h-[28px] px-2 text-sm border focus:outline-none text-right ${isReadonly ? 'cursor-not-allowed' : ''} table-cell-input`, style: {
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
|
|
8824
|
-
|
|
9011
|
+
return (jsxRuntimeExports.jsxs("div", { className: "table-cell-field w-full", children: [jsxRuntimeExports.jsx("input", { type: "number", value: displayValue, onChange: handleChange, disabled: isReadonly, placeholder: placeholder, min: validationConfig?.min, max: validationConfig?.max, step: formatConfig?.decimalPlaces ? Math.pow(0.1, formatConfig.decimalPlaces) : undefined, className: `w-full h-[28px] px-2 text-sm border focus:outline-none text-right ${isReadonly ? 'cursor-not-allowed' : ''} table-cell-input`, style: {
|
|
9012
|
+
borderRadius: '10px',
|
|
9013
|
+
borderColor: 'var(--owt-widget-input-border, #C4C4C4)',
|
|
9014
|
+
backgroundColor: isReadonly ? 'var(--owt-color-bg-alt, #F6F6F6)' : 'var(--owt-color-bg, #FFFFFF)',
|
|
9015
|
+
} }), jsxRuntimeExports.jsx("p", { className: "table-cell-field-error", "aria-hidden": "true", children: '\u00a0' })] }));
|
|
8825
9016
|
};
|
|
8826
9017
|
const TableCellDate = ({ config, value, rowValues, onValueChange }) => {
|
|
8827
9018
|
const { translateConfig } = useWidgetTranslation();
|
|
@@ -8880,13 +9071,15 @@ const TableCellDate = ({ config, value, rowValues, onValueChange }) => {
|
|
|
8880
9071
|
setConstraintError(error);
|
|
8881
9072
|
};
|
|
8882
9073
|
const hasError = Boolean(constraintError);
|
|
8883
|
-
return (jsxRuntimeExports.jsxs("div", { className: "w-full", children: [jsxRuntimeExports.jsx("input", { type: "date", value: displayValue, onChange: handleChange, disabled: isReadonly, placeholder: placeholder, min: effectiveMinDate, max: effectiveMaxDate, title: constraintError || translateConfig(config['widget-data-tooltip']), className: `w-full h-[28px] px-2 text-sm border focus:outline-none ${isReadonly ? 'cursor-not-allowed' : ''}
|
|
9074
|
+
return (jsxRuntimeExports.jsxs("div", { className: "table-cell-field w-full", children: [jsxRuntimeExports.jsx("input", { type: "date", value: displayValue, onChange: handleChange, disabled: isReadonly, placeholder: placeholder, min: effectiveMinDate, max: effectiveMaxDate, title: constraintError || translateConfig(config['widget-data-tooltip']), className: `w-full h-[28px] px-2 text-sm border focus:outline-none ${isReadonly ? 'cursor-not-allowed' : ''} table-cell-input`, style: {
|
|
8884
9075
|
borderRadius: '10px',
|
|
8885
9076
|
borderColor: hasError
|
|
8886
9077
|
? 'var(--owt-color-error, #B91C1C)'
|
|
8887
9078
|
: 'var(--owt-widget-input-border, #C4C4C4)',
|
|
8888
9079
|
backgroundColor: isReadonly ? 'var(--owt-color-bg-alt, #F6F6F6)' : 'var(--owt-color-bg, #FFFFFF)',
|
|
8889
|
-
} }),
|
|
9080
|
+
} }), jsxRuntimeExports.jsx("p", { className: "table-cell-field-error text-xs mt-0.5 leading-tight", style: {
|
|
9081
|
+
color: hasError ? 'var(--owt-color-error, #B91C1C)' : 'transparent',
|
|
9082
|
+
}, "aria-live": "polite", children: constraintError ?? '\u00a0' })] }));
|
|
8890
9083
|
};
|
|
8891
9084
|
const TableWidget = ({ config }) => {
|
|
8892
9085
|
const { value, error, touched, isEnabled, onChange, config: widgetConfig, } = useBaseWidget({ config });
|
|
@@ -8912,6 +9105,18 @@ const TableWidget = ({ config }) => {
|
|
|
8912
9105
|
const isSectionEditMode = !isReadonly && operations.edit;
|
|
8913
9106
|
// Check if any row is being edited (either manually or via section edit mode)
|
|
8914
9107
|
const isAnyRowEditing = editingState !== null || isAdding;
|
|
9108
|
+
const canSaveEditingRow = React.useMemo(() => {
|
|
9109
|
+
if (!editingState) {
|
|
9110
|
+
return false;
|
|
9111
|
+
}
|
|
9112
|
+
return isTableRowDataValid(editingState.currentValue, columns, isReadonly, translateConfig);
|
|
9113
|
+
}, [editingState, columns, isReadonly, translateConfig]);
|
|
9114
|
+
const canSaveNewRow = React.useMemo(() => {
|
|
9115
|
+
if (!isAdding || !newRowData) {
|
|
9116
|
+
return false;
|
|
9117
|
+
}
|
|
9118
|
+
return isTableRowDataValid(newRowData, columns, isReadonly, translateConfig);
|
|
9119
|
+
}, [isAdding, newRowData, columns, isReadonly, translateConfig]);
|
|
8915
9120
|
// Show confirmation dialog
|
|
8916
9121
|
const showConfirmation = React.useCallback((message, onConfirm, onCancel) => {
|
|
8917
9122
|
setConfirmationState({
|
|
@@ -9001,6 +9206,8 @@ const TableWidget = ({ config }) => {
|
|
|
9001
9206
|
const saveEdit = React.useCallback(async () => {
|
|
9002
9207
|
if (!editingState)
|
|
9003
9208
|
return;
|
|
9209
|
+
if (!canSaveEditingRow)
|
|
9210
|
+
return;
|
|
9004
9211
|
const rowData = editingState.currentValue;
|
|
9005
9212
|
const rowIndex = editingState.rowIndex;
|
|
9006
9213
|
setLoadingRowIndex(rowIndex);
|
|
@@ -9072,7 +9279,7 @@ const TableWidget = ({ config }) => {
|
|
|
9072
9279
|
finally {
|
|
9073
9280
|
setLoadingRowIndex(null);
|
|
9074
9281
|
}
|
|
9075
|
-
}, [editingState, rows, onChange, dataSourceRequestHandler, apiConfig, translate, isSectionEditMode, originalRows, columns, widgetConfig, dispatch]);
|
|
9282
|
+
}, [editingState, canSaveEditingRow, rows, onChange, dataSourceRequestHandler, apiConfig, translate, isSectionEditMode, originalRows, columns, widgetConfig, dispatch]);
|
|
9076
9283
|
// Add new row
|
|
9077
9284
|
const startAdd = React.useCallback(() => {
|
|
9078
9285
|
// If there's an unsaved edit, cancel it first (no confirmation needed)
|
|
@@ -9090,6 +9297,8 @@ const TableWidget = ({ config }) => {
|
|
|
9090
9297
|
const saveAdd = React.useCallback(async () => {
|
|
9091
9298
|
if (!isAdding || !newRowData)
|
|
9092
9299
|
return;
|
|
9300
|
+
if (!canSaveNewRow)
|
|
9301
|
+
return;
|
|
9093
9302
|
setLoadingRowIndex(-1); // Use -1 to indicate new row
|
|
9094
9303
|
try {
|
|
9095
9304
|
let savedRow = { ...newRowData };
|
|
@@ -9120,7 +9329,7 @@ const TableWidget = ({ config }) => {
|
|
|
9120
9329
|
finally {
|
|
9121
9330
|
setLoadingRowIndex(null);
|
|
9122
9331
|
}
|
|
9123
|
-
}, [isAdding, newRowData, rows, onChange, dataSourceRequestHandler, apiConfig, translate, isSectionEditMode]);
|
|
9332
|
+
}, [isAdding, newRowData, canSaveNewRow, rows, onChange, dataSourceRequestHandler, apiConfig, translate, isSectionEditMode]);
|
|
9124
9333
|
// Delete row
|
|
9125
9334
|
const deleteRow = React.useCallback(async (rowIndex) => {
|
|
9126
9335
|
if (isAnyRowEditing) {
|
|
@@ -9398,6 +9607,22 @@ const TableWidget = ({ config }) => {
|
|
|
9398
9607
|
box-shadow: 0 0 0 1px var(--owt-widget-input-focus-border, #F07B1A);
|
|
9399
9608
|
border-color: var(--owt-widget-input-focus-border, #F07B1A);
|
|
9400
9609
|
}
|
|
9610
|
+
|
|
9611
|
+
/* Keep inputs and action buttons top-aligned when a cell shows validation text */
|
|
9612
|
+
.${tableWidgetId} tr.table-row-editing td {
|
|
9613
|
+
vertical-align: top;
|
|
9614
|
+
}
|
|
9615
|
+
|
|
9616
|
+
.${tableWidgetId} .table-cell-field-error {
|
|
9617
|
+
min-height: 1.125rem;
|
|
9618
|
+
}
|
|
9619
|
+
|
|
9620
|
+
.${tableWidgetId} .table-cell-actions {
|
|
9621
|
+
display: flex;
|
|
9622
|
+
flex-direction: row;
|
|
9623
|
+
gap: 0.5rem;
|
|
9624
|
+
align-items: flex-start;
|
|
9625
|
+
}
|
|
9401
9626
|
` }), jsxRuntimeExports.jsxs("div", { className: `table-widget-container ${tableWidgetId}`, children: [confirmationState?.show && (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 max-w-md w-full mx-4", style: { backgroundColor: 'var(--owt-color-bg, #FFFFFF)' }, children: [jsxRuntimeExports.jsx("h3", { className: "text-lg font-semibold mb-4", style: { color: 'var(--owt-color-text, #011627)' }, children: translate('table.confirm') || 'Confirm Action' }), jsxRuntimeExports.jsx("p", { className: "mb-6", style: { color: 'var(--owt-color-text, #011627)' }, children: confirmationState.message }), jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-3", children: [jsxRuntimeExports.jsx("button", { onClick: confirmationState.onCancel, className: "px-4 py-2 text-sm font-medium", style: {
|
|
9402
9627
|
borderRadius: 'var(--owt-btn-border-radius, 10px)',
|
|
9403
9628
|
border: '1px solid var(--owt-btn-secondary-border, #C4C4C4)',
|
|
@@ -9416,7 +9641,7 @@ const TableWidget = ({ config }) => {
|
|
|
9416
9641
|
}, children: translate('table.addRecord') || 'Add New Record' }) })), jsxRuntimeExports.jsx("div", { className: "overflow-x-auto border", style: { borderRadius: 'var(--owt-widget-table-border-radius, 15px)', borderColor: 'var(--owt-widget-table-border-color, #C4C4C4)' }, 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: [columns.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) || isAnyRowEditing || isSectionEditMode ? (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' })) : null] }) }), jsxRuntimeExports.jsxs("tbody", { style: { backgroundColor: 'var(--owt-widget-table-body-bg, #FFFFFF)' }, children: [rows.length === 0 && !isAdding && (jsxRuntimeExports.jsx("tr", { children: jsxRuntimeExports.jsxs("td", { colSpan: columns.length + (((operations.edit || operations.remove) && !isReadonly) || isSectionEditMode ? 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) => {
|
|
9417
9642
|
const isEditing = isRowEditing(rowIndex);
|
|
9418
9643
|
const isLoading = loadingRowIndex === rowIndex;
|
|
9419
|
-
return (jsxRuntimeExports.jsxs("tr", { className: isLoading ? 'opacity-50' : ''
|
|
9644
|
+
return (jsxRuntimeExports.jsxs("tr", { className: `${isLoading ? 'opacity-50' : ''}${isEditing ? ' table-row-editing' : ''}`, style: {
|
|
9420
9645
|
borderBottom: '1px solid var(--owt-widget-table-row-divider, #E4E4E4)',
|
|
9421
9646
|
backgroundColor: isEditing
|
|
9422
9647
|
? 'var(--owt-widget-table-editing-row-bg, #FBE6AA)'
|
|
@@ -9427,7 +9652,7 @@ const TableWidget = ({ config }) => {
|
|
|
9427
9652
|
return (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: renderCell(rowIndex, col, row) }, col['column-key']));
|
|
9428
9653
|
}), ((operations.edit || operations.remove) && !isReadonly) || isEditing || isSectionEditMode ? (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", style: { minWidth: '120px' }, children: isEditing ? (
|
|
9429
9654
|
// Show OK (Save)/Cancel buttons when row is being edited (works in both section edit mode and normal mode)
|
|
9430
|
-
jsxRuntimeExports.jsxs("div", { className: "
|
|
9655
|
+
jsxRuntimeExports.jsxs("div", { className: "table-cell-actions", style: { width: '100%' }, children: [jsxRuntimeExports.jsx("button", { type: "button", onClick: saveEdit, disabled: isLoading || !canSaveEditingRow, className: "px-3 py-1 text-xs font-medium disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap flex-shrink-0", style: {
|
|
9431
9656
|
display: 'inline-block',
|
|
9432
9657
|
minWidth: '60px',
|
|
9433
9658
|
backgroundColor: 'var(--owt-color-success, #16A34A)',
|
|
@@ -9454,7 +9679,7 @@ const TableWidget = ({ config }) => {
|
|
|
9454
9679
|
backgroundColor: 'transparent',
|
|
9455
9680
|
border: 'none',
|
|
9456
9681
|
}, children: translate('common.remove') || 'Delete' }))] })) })) : null] }, rowIndex));
|
|
9457
|
-
}), isAdding && newRowData && (jsxRuntimeExports.jsxs("tr", { style: { backgroundColor: 'var(--owt-widget-table-editing-row-bg, #FBE6AA)' }, children: [columns.map((col) => (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: renderCell(rows.length, col, { ...newRowData, edit_action: 'ADD' }) }, col['column-key']))), jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: jsxRuntimeExports.jsxs("div", { className: "
|
|
9682
|
+
}), isAdding && newRowData && (jsxRuntimeExports.jsxs("tr", { className: "table-row-editing", style: { backgroundColor: 'var(--owt-widget-table-editing-row-bg, #FBE6AA)' }, children: [columns.map((col) => (jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: renderCell(rows.length, col, { ...newRowData, edit_action: 'ADD' }) }, col['column-key']))), jsxRuntimeExports.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: jsxRuntimeExports.jsxs("div", { className: "table-cell-actions", children: [jsxRuntimeExports.jsx("button", { type: "button", onClick: saveAdd, disabled: loadingRowIndex === -1 || !canSaveNewRow, className: "px-3 py-1 text-xs disabled:opacity-50 disabled:cursor-not-allowed", style: {
|
|
9458
9683
|
borderRadius: 'var(--owt-btn-border-radius, 10px)',
|
|
9459
9684
|
backgroundColor: 'var(--owt-color-success, #16A34A)',
|
|
9460
9685
|
color: 'var(--owt-color-bg, #FFFFFF)',
|
|
@@ -11752,6 +11977,7 @@ exports.DateTimeInputWidget = DateTimeInputWidget;
|
|
|
11752
11977
|
exports.DialogTableWidget = DialogTableWidget;
|
|
11753
11978
|
exports.DisplayWidget = DisplayWidget;
|
|
11754
11979
|
exports.FileInputWidget = FileInputWidget;
|
|
11980
|
+
exports.GEO_LEVEL_CLEARED = GEO_LEVEL_CLEARED;
|
|
11755
11981
|
exports.HeaderSectionWidget = HeaderSectionWidget;
|
|
11756
11982
|
exports.IdAuthenticationWidget = IdAuthenticationWidget;
|
|
11757
11983
|
exports.IterableAccordionWidget = IterableAccordionWidget;
|
|
@@ -11779,6 +12005,7 @@ exports.WidgetRenderer = WidgetRenderer;
|
|
|
11779
12005
|
exports.applyCaseControl = applyCaseControl;
|
|
11780
12006
|
exports.applyDecimalPrecision = applyDecimalPrecision;
|
|
11781
12007
|
exports.applyMask = applyMask;
|
|
12008
|
+
exports.applySharedGeoHierarchyToValues = applySharedGeoHierarchyToValues;
|
|
11782
12009
|
exports.createWidgetStore = createWidgetStore;
|
|
11783
12010
|
exports.createZodSchema = createZodSchema;
|
|
11784
12011
|
exports.defaultTheme = defaultTheme;
|
|
@@ -11798,13 +12025,20 @@ exports.getValueByPath = getValueByPath;
|
|
|
11798
12025
|
exports.getWidgetValue = getWidgetValue;
|
|
11799
12026
|
exports.initI18n = initI18n;
|
|
11800
12027
|
exports.isAllowedKey = isAllowedKey;
|
|
12028
|
+
exports.isUpstreamGeoAncestor = isUpstreamGeoAncestor;
|
|
12029
|
+
exports.normalizeNumericDefault = normalizeNumericDefault;
|
|
11801
12030
|
exports.parseDataPath = parseDataPath;
|
|
11802
12031
|
exports.parseNumber = parseNumber;
|
|
11803
12032
|
exports.registerDefaultWidgets = registerDefaultWidgets;
|
|
12033
|
+
exports.registerGeoWidgetParent = registerGeoWidgetParent;
|
|
11804
12034
|
exports.removeMask = removeMask;
|
|
11805
12035
|
exports.resetAll = resetAll;
|
|
12036
|
+
exports.resetAndSeedGeoHierarchyFromValues = resetAndSeedGeoHierarchyFromValues;
|
|
11806
12037
|
exports.resetWidget = resetWidget;
|
|
12038
|
+
exports.resolveGeoWidgetLevelValue = resolveGeoWidgetLevelValue;
|
|
11807
12039
|
exports.resolveTheme = resolveTheme;
|
|
12040
|
+
exports.resolveWidgetIdValue = resolveWidgetIdValue;
|
|
12041
|
+
exports.seedGeoHierarchyFromValues = seedGeoHierarchyFromValues;
|
|
11808
12042
|
exports.setDataSource = setDataSource;
|
|
11809
12043
|
exports.setError = setError;
|
|
11810
12044
|
exports.setLoading = setLoading;
|
|
@@ -11819,6 +12053,7 @@ exports.transformDataSourceOptions = transformDataSourceOptions;
|
|
|
11819
12053
|
exports.translatePanelConfig = translatePanelConfig;
|
|
11820
12054
|
exports.translateUISchema = translateUISchema;
|
|
11821
12055
|
exports.translateWidgetConfig = translateWidgetConfig;
|
|
12056
|
+
exports.unregisterGeoWidgetParent = unregisterGeoWidgetParent;
|
|
11822
12057
|
exports.useBaseWidget = useBaseWidget;
|
|
11823
12058
|
exports.useGeoWidgetCascade = useGeoWidgetCascade;
|
|
11824
12059
|
exports.useWidgetCascade = useWidgetCascade;
|