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