@syncfusion/ej2-react-form-builder 0.1.0-beta
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/Common/CheckboxGroup.d.ts +13 -0
- package/Common/CheckboxGroup.js +50 -0
- package/Common/ConditionalRuleEngine.d.ts +296 -0
- package/Common/ConditionalRuleEngine.js +566 -0
- package/Common/CustomTabComponent.d.ts +17 -0
- package/Common/CustomTabComponent.js +30 -0
- package/Common/CustomValidationEngine.d.ts +58 -0
- package/Common/CustomValidationEngine.js +146 -0
- package/Common/DataGridComponent.d.ts +20 -0
- package/Common/DataGridComponent.js +273 -0
- package/Common/FormValidator.d.ts +485 -0
- package/Common/FormValidator.js +575 -0
- package/Common/MinMaxRuleEngine.d.ts +105 -0
- package/Common/MinMaxRuleEngine.js +365 -0
- package/Common/StaticHtmlRenderer.d.ts +14 -0
- package/Common/StaticHtmlRenderer.js +24 -0
- package/Common/expressions/DependencyTracker.d.ts +30 -0
- package/Common/expressions/DependencyTracker.js +128 -0
- package/Common/expressions/ExpressionEngine.d.ts +95 -0
- package/Common/expressions/ExpressionEngine.js +506 -0
- package/Common/expressions/ExpressionParser.d.ts +41 -0
- package/Common/expressions/ExpressionParser.js +269 -0
- package/Common/expressions/useGridExpressions.d.ts +12 -0
- package/Common/expressions/useGridExpressions.js +71 -0
- package/Common/globalFormId.d.ts +26 -0
- package/Common/globalFormId.js +45 -0
- package/Common/json-converter.d.ts +444 -0
- package/Common/json-converter.js +1184 -0
- package/Common/parser.d.ts +98 -0
- package/Common/parser.js +753 -0
- package/Common/utils.d.ts +130 -0
- package/Common/utils.js +574 -0
- package/README.md +53 -0
- package/index.d.ts +6 -0
- package/index.js +6 -0
- package/license +13 -0
- package/package.json +54 -0
- package/src/FormBuilder.d.ts +211 -0
- package/src/FormBuilder.js +1299 -0
- package/src/components/Database/ConnectionForm.d.ts +8 -0
- package/src/components/Database/ConnectionForm.js +28 -0
- package/src/components/TopBar.d.ts +10 -0
- package/src/components/TopBar.js +7 -0
- package/src/components/icons/ComponentIcons.d.ts +44 -0
- package/src/components/icons/ComponentIcons.js +40 -0
- package/src/components/layout/FormFieldWrapper.d.ts +41 -0
- package/src/components/layout/FormFieldWrapper.js +112 -0
- package/src/components/layout/LeftPane.d.ts +23 -0
- package/src/components/layout/LeftPane.js +310 -0
- package/src/components/layout/ListBoxPane.d.ts +24 -0
- package/src/components/layout/ListBoxPane.js +94 -0
- package/src/components/layout/MainSection.d.ts +39 -0
- package/src/components/layout/MainSection.js +1766 -0
- package/src/components/layout/Preview.d.ts +12 -0
- package/src/components/layout/Preview.js +337 -0
- package/src/components/layout/RightPane.d.ts +22 -0
- package/src/components/layout/RightPane.js +370 -0
- package/src/components/theme/ThemeSwitcher.d.ts +14 -0
- package/src/components/theme/ThemeSwitcher.js +24 -0
- package/src/components/theme/theme-constant.d.ts +37 -0
- package/src/components/theme/theme-constant.js +23 -0
- package/src/config/component-properties.json +4929 -0
- package/src/config/form-setting.json +56 -0
- package/src/config/locale.d.ts +449 -0
- package/src/config/locale.js +449 -0
- package/src/context/FormSchemaContext.d.ts +32 -0
- package/src/context/FormSchemaContext.js +155 -0
- package/src/context/LocalizationContext.d.ts +27 -0
- package/src/context/LocalizationContext.js +43 -0
- package/src/context/ThemeContext.d.ts +23 -0
- package/src/context/ThemeContext.js +161 -0
- package/src/context/contexts.d.ts +6 -0
- package/src/context/contexts.js +6 -0
- package/src/context/defaultFormSchema.d.ts +6 -0
- package/src/context/defaultFormSchema.js +20 -0
- package/src/defaultPalette.d.ts +9 -0
- package/src/defaultPalette.js +45 -0
- package/src/defaultTemplate.d.ts +3 -0
- package/src/defaultTemplate.js +185 -0
- package/src/import/schemaImportUtils.d.ts +24 -0
- package/src/import/schemaImportUtils.js +121 -0
- package/src/index.d.ts +16 -0
- package/src/index.js +6 -0
- package/src/types/ActionButtons.d.ts +44 -0
- package/src/types/ActionButtons.js +27 -0
- package/src/types/ComponentProperties.d.ts +33 -0
- package/src/types/ComponentProperties.js +2 -0
- package/src/types/FormSchema.d.ts +585 -0
- package/src/types/FormSchema.js +147 -0
- package/src/types/connection.d.ts +19 -0
- package/src/types/connection.js +9 -0
- package/src/utils/AttributesEditor.d.ts +13 -0
- package/src/utils/AttributesEditor.js +117 -0
- package/src/utils/ButtonGroupEditor.d.ts +15 -0
- package/src/utils/ButtonGroupEditor.js +141 -0
- package/src/utils/ChoiceBasedFieldEditor.d.ts +16 -0
- package/src/utils/ChoiceBasedFieldEditor.js +87 -0
- package/src/utils/ClipboardHelper.d.ts +26 -0
- package/src/utils/ClipboardHelper.js +83 -0
- package/src/utils/ColumnBuilder.d.ts +11 -0
- package/src/utils/ColumnBuilder.js +153 -0
- package/src/utils/ColumnSpanEditor.d.ts +8 -0
- package/src/utils/ColumnSpanEditor.js +98 -0
- package/src/utils/ConditionDataEditor.d.ts +29 -0
- package/src/utils/ConditionDataEditor.js +177 -0
- package/src/utils/ConditionalEditorUtils.d.ts +27 -0
- package/src/utils/ConditionalEditorUtils.js +310 -0
- package/src/utils/ConditionsEditor.d.ts +20 -0
- package/src/utils/ConditionsEditor.js +571 -0
- package/src/utils/CustomAccordion.d.ts +13 -0
- package/src/utils/CustomAccordion.js +38 -0
- package/src/utils/CustomValidationEditor.d.ts +11 -0
- package/src/utils/CustomValidationEditor.js +208 -0
- package/src/utils/DataSourceCollector.d.ts +3 -0
- package/src/utils/DataSourceCollector.js +252 -0
- package/src/utils/ExpressionEditor.d.ts +13 -0
- package/src/utils/ExpressionEditor.js +99 -0
- package/src/utils/FormSettingsPanel.d.ts +9 -0
- package/src/utils/FormSettingsPanel.js +60 -0
- package/src/utils/LookupConfig.d.ts +11 -0
- package/src/utils/LookupConfig.js +159 -0
- package/src/utils/MinMaxValueEditor.d.ts +25 -0
- package/src/utils/MinMaxValueEditor.js +188 -0
- package/src/utils/OptionsEditor.d.ts +8 -0
- package/src/utils/OptionsEditor.js +79 -0
- package/src/utils/PropertyRenderer.d.ts +22 -0
- package/src/utils/PropertyRenderer.js +210 -0
- package/src/utils/ValueRenderer.d.ts +2 -0
- package/src/utils/ValueRenderer.js +91 -0
- package/src/utils/ej2DbAdaptor.d.ts +6 -0
- package/src/utils/ej2DbAdaptor.js +38 -0
- package/src/utils/mappingHeuristics.d.ts +10 -0
- package/src/utils/mappingHeuristics.js +33 -0
- package/src/utils/renderComponent.d.ts +18 -0
- package/src/utils/renderComponent.js +300 -0
- package/styles/tailwind3.css +67 -0
- package/styles/themes/action-buttons.css +110 -0
- package/styles/themes/datagrid.css +380 -0
- package/styles/themes/drag-reorder.css +248 -0
- package/styles/themes/import-dialog.css +292 -0
- package/styles/themes/index.css +658 -0
- package/styles/themes/left-pane.css +253 -0
- package/styles/themes/options-editor.css +63 -0
- package/styles/themes/preview.css +702 -0
- package/styles/themes/property-dialog.css +371 -0
|
@@ -0,0 +1,571 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useEffect, useState, useCallback } from 'react';
|
|
3
|
+
import { QueryBuilderComponent } from '@syncfusion/ej2-react-querybuilder';
|
|
4
|
+
import { getComponent } from '@syncfusion/ej2-base';
|
|
5
|
+
import { DataManager, Query } from '@syncfusion/ej2-data';
|
|
6
|
+
import { useLocalization } from '../context/LocalizationContext';
|
|
7
|
+
import ValueRenderer from './ValueRenderer';
|
|
8
|
+
import { extractDataFromPath, getAdaptorInstance } from '../../Common/utils';
|
|
9
|
+
import { ConditionDataEditor } from './ConditionDataEditor';
|
|
10
|
+
import { ChoiceBasedFieldEditor } from './ChoiceBasedFieldEditor';
|
|
11
|
+
import { inferFieldType, isArrayField, hasSelectableOptions, createColumnTemplate } from './ConditionalEditorUtils';
|
|
12
|
+
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
|
|
13
|
+
import { DialogComponent } from '@syncfusion/ej2-react-popups';
|
|
14
|
+
import { ListBoxComponent } from '@syncfusion/ej2-react-dropdowns';
|
|
15
|
+
export const ConditionsEditor = ({ componentFields, componentForEdit, excludeFieldId, excludeChildIds = [], existingConditions, onChange, builderMode, supportedConditions: supportedConditionsProp = ['visibleWhen', 'hideWhen', 'readOnlyWhen', 'disabledWhen', 'requiredWhen', 'setValueWhen', 'choiceBasedField'] }) => {
|
|
16
|
+
// In Simple builder mode, only allow a subset of condition types
|
|
17
|
+
const supportedConditions = builderMode === 'Simple'
|
|
18
|
+
? supportedConditionsProp.filter(c => c === 'visibleWhen' || c === 'disabledWhen' || c === 'readOnlyWhen')
|
|
19
|
+
: supportedConditionsProp;
|
|
20
|
+
// Use ref instead of state to avoid re-renders on condition updates
|
|
21
|
+
// Only notify parent when conditions change via onChange callback
|
|
22
|
+
const conditionsRef = useRef({
|
|
23
|
+
visibleWhen: existingConditions?.visibleWhen,
|
|
24
|
+
hideWhen: existingConditions?.hideWhen,
|
|
25
|
+
readOnlyWhen: existingConditions?.readOnlyWhen,
|
|
26
|
+
disabledWhen: existingConditions?.disabledWhen,
|
|
27
|
+
requiredWhen: existingConditions?.requiredWhen,
|
|
28
|
+
setValueWhen: existingConditions?.setValueWhen,
|
|
29
|
+
choiceBasedField: existingConditions?.choiceBasedField
|
|
30
|
+
});
|
|
31
|
+
const { l10n } = useLocalization();
|
|
32
|
+
// Track fetched options for components with URL-based options
|
|
33
|
+
const [fetchedOptions, setFetchedOptions] = useState({});
|
|
34
|
+
const fetchAbortControllers = useRef({});
|
|
35
|
+
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
36
|
+
const [activeConditionType, setActiveConditionType] = useState('visibleWhen');
|
|
37
|
+
const [savedConditions, setSavedConditions] = useState([]);
|
|
38
|
+
const [showStyles, setShowStyles] = useState(false);
|
|
39
|
+
// Initialize savedConditions based on existingConditions
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
const conditions = [];
|
|
42
|
+
if (existingConditions?.visibleWhen)
|
|
43
|
+
conditions.push('visibleWhen');
|
|
44
|
+
if (existingConditions?.hideWhen)
|
|
45
|
+
conditions.push('hideWhen');
|
|
46
|
+
if (existingConditions?.readOnlyWhen)
|
|
47
|
+
conditions.push('readOnlyWhen');
|
|
48
|
+
if (existingConditions?.disabledWhen)
|
|
49
|
+
conditions.push('disabledWhen');
|
|
50
|
+
if (existingConditions?.requiredWhen)
|
|
51
|
+
conditions.push('requiredWhen');
|
|
52
|
+
if (existingConditions?.setValueWhen)
|
|
53
|
+
conditions.push('setValueWhen');
|
|
54
|
+
if (existingConditions?.choiceBasedField)
|
|
55
|
+
conditions.push('choiceBasedField');
|
|
56
|
+
if (existingConditions?.conditionalData)
|
|
57
|
+
conditions.push('conditionalData');
|
|
58
|
+
setSavedConditions(conditions);
|
|
59
|
+
}, [existingConditions]);
|
|
60
|
+
// Fetch options for components that have URL-based options
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
const newFetchedOptions = {};
|
|
63
|
+
const newAbortControllers = {};
|
|
64
|
+
componentFields.forEach(component => {
|
|
65
|
+
if (component.options && typeof component.options === 'object' && !Array.isArray(component.options)) {
|
|
66
|
+
const options = component.options;
|
|
67
|
+
if (options.type === 'url' && options.url) {
|
|
68
|
+
newAbortControllers[component.id] = new AbortController();
|
|
69
|
+
try {
|
|
70
|
+
const headers = {};
|
|
71
|
+
if (options.headers && Array.isArray(options.headers)) {
|
|
72
|
+
options.headers.forEach((h) => {
|
|
73
|
+
if (h.key?.trim()) {
|
|
74
|
+
headers[h.key] = h.value;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
const dataManager = new DataManager({
|
|
79
|
+
url: options.url,
|
|
80
|
+
adaptor: getAdaptorInstance(options.adaptorType),
|
|
81
|
+
headers: Object.keys(headers).length ? headers : undefined
|
|
82
|
+
});
|
|
83
|
+
let query = new Query();
|
|
84
|
+
// Apply search query
|
|
85
|
+
if (options.search && options.search.enabled && options.search.fields && options.search.fields.length > 0) {
|
|
86
|
+
const searchKey = options.search.key || 'search';
|
|
87
|
+
// Add search as a query parameter (will need search term at runtime or use generic placeholder)
|
|
88
|
+
query = query.addParams(searchKey, '*');
|
|
89
|
+
}
|
|
90
|
+
// Apply sort query
|
|
91
|
+
if (options.sort && options.sort.enabled && options.sort.field) {
|
|
92
|
+
const sortDirection = options.sort.direction === 'descending' ? 'descending' : 'ascending';
|
|
93
|
+
query = query.sortBy(options.sort.field, sortDirection);
|
|
94
|
+
}
|
|
95
|
+
// Apply filter queries
|
|
96
|
+
if (options.filters && Array.isArray(options.filters) && options.filters.length > 0) {
|
|
97
|
+
options.filters.forEach((f) => {
|
|
98
|
+
if (f.field && f.operator && f.value) {
|
|
99
|
+
query = query.where(f.field, f.operator, f.value);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
// Apply query params (kept for backward compatibility)
|
|
104
|
+
if (options.queryParams) {
|
|
105
|
+
Object.keys(options.queryParams).forEach(key => {
|
|
106
|
+
query = query.addParams(key, options.queryParams[key]);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
// Example: paging
|
|
110
|
+
if (options.skip)
|
|
111
|
+
query = query.skip(options.skip);
|
|
112
|
+
if (options.take)
|
|
113
|
+
query = query.take(options.take);
|
|
114
|
+
dataManager.executeQuery(query).then((res) => {
|
|
115
|
+
let data = res.result;
|
|
116
|
+
if (options.dataPath) {
|
|
117
|
+
data = extractDataFromPath(data, options.dataPath);
|
|
118
|
+
}
|
|
119
|
+
if (Array.isArray(data)) {
|
|
120
|
+
newFetchedOptions[component.id] = data;
|
|
121
|
+
}
|
|
122
|
+
else if (typeof data === 'string') {
|
|
123
|
+
newFetchedOptions[component.id] = [data];
|
|
124
|
+
}
|
|
125
|
+
setFetchedOptions(prev => ({ ...prev, [component.id]: newFetchedOptions[component.id] }));
|
|
126
|
+
// Refresh any existing dropdowns with this component ID
|
|
127
|
+
refreshComponentDropdowns(component.id, data);
|
|
128
|
+
}).catch((err) => {
|
|
129
|
+
console.error(`DataManager fetch error for ${component.id}:`, err);
|
|
130
|
+
newFetchedOptions[component.id] = [];
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
console.error(`Setup error for ${component.id}:`, err);
|
|
135
|
+
newFetchedOptions[component.id] = [];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
fetchAbortControllers.current = newAbortControllers;
|
|
141
|
+
// Cleanup on unmount
|
|
142
|
+
return () => {
|
|
143
|
+
Object.values(newAbortControllers).forEach(controller => controller.abort());
|
|
144
|
+
};
|
|
145
|
+
}, [componentFields]);
|
|
146
|
+
// Helper function to refresh dropdowns when data is fetched
|
|
147
|
+
const refreshComponentDropdowns = (componentId, data) => {
|
|
148
|
+
setTimeout(() => {
|
|
149
|
+
// Find all dropdown instances with this component ID
|
|
150
|
+
const dropdownElements = document.querySelectorAll(`input[data-component-id="${componentId}"]`);
|
|
151
|
+
dropdownElements.forEach(element => {
|
|
152
|
+
const dropdown = getComponent(element, 'dropdownlist');
|
|
153
|
+
if (dropdown) {
|
|
154
|
+
try {
|
|
155
|
+
const transformedData = (Array.isArray(data) ? data : [data]).map(opt => {
|
|
156
|
+
if (typeof opt === 'string') {
|
|
157
|
+
return { text: opt, value: opt };
|
|
158
|
+
}
|
|
159
|
+
else if (opt && typeof opt === 'object' && 'value' in opt) {
|
|
160
|
+
return {
|
|
161
|
+
text: opt.label || opt.text || opt.value,
|
|
162
|
+
value: opt.value
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
return { text: String(opt), value: String(opt) };
|
|
166
|
+
});
|
|
167
|
+
dropdown.dataSource = transformedData;
|
|
168
|
+
dropdown.refresh();
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
console.error(`Error refreshing dropdown for ${componentId}:`, err);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}, 0);
|
|
176
|
+
};
|
|
177
|
+
const qbRefs = {
|
|
178
|
+
visible: useRef(null),
|
|
179
|
+
hidden: useRef(null),
|
|
180
|
+
readOnly: useRef(null),
|
|
181
|
+
disabled: useRef(null),
|
|
182
|
+
required: useRef(null),
|
|
183
|
+
setValue: useRef(null)
|
|
184
|
+
};
|
|
185
|
+
const buildColumnsForQueryBuilder = (qbRef) => {
|
|
186
|
+
return componentFields
|
|
187
|
+
.filter(c => {
|
|
188
|
+
// Exclude current component to prevent self-reference
|
|
189
|
+
if (excludeFieldId && c.id === excludeFieldId) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
// Exclude child components to prevent circular dependencies
|
|
193
|
+
if (excludeChildIds.includes(c.id)) {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
// Exclude non-data component types (layout, display-only, action components)
|
|
197
|
+
const excludedTypes = [
|
|
198
|
+
'imageeditor',
|
|
199
|
+
'richtexteditor',
|
|
200
|
+
'datagrid',
|
|
201
|
+
'splitbutton',
|
|
202
|
+
'button',
|
|
203
|
+
'message',
|
|
204
|
+
'panel',
|
|
205
|
+
'table',
|
|
206
|
+
'tabs',
|
|
207
|
+
'card',
|
|
208
|
+
'statichtml',
|
|
209
|
+
'signature',
|
|
210
|
+
'fileupload'
|
|
211
|
+
];
|
|
212
|
+
// Case-insensitive comparison
|
|
213
|
+
return !excludedTypes.includes(c.type.toLowerCase());
|
|
214
|
+
})
|
|
215
|
+
.map((component) => {
|
|
216
|
+
const fieldType = inferFieldType(component);
|
|
217
|
+
const isArray = isArrayField(component);
|
|
218
|
+
// Define operators based on field type
|
|
219
|
+
let operators = [];
|
|
220
|
+
// Special handling for array-like fields (multiselect, checkboxGroup)
|
|
221
|
+
if (isArray) {
|
|
222
|
+
operators = [
|
|
223
|
+
{ key: 'Is Empty', value: 'isempty' },
|
|
224
|
+
{ key: 'Is Not Empty', value: 'isnotempty' },
|
|
225
|
+
{ key: 'Contains', value: 'contains' },
|
|
226
|
+
{ key: 'Not Contains', value: 'notcontains' }
|
|
227
|
+
];
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
// Standard operators for non-array fields
|
|
231
|
+
switch (fieldType) {
|
|
232
|
+
case 'number':
|
|
233
|
+
operators = [
|
|
234
|
+
{ key: 'Equal', value: 'equal' },
|
|
235
|
+
{ key: 'Not Equal', value: 'notequal' },
|
|
236
|
+
{ key: 'Greater than', value: 'greaterthan' },
|
|
237
|
+
{ key: 'Less than', value: 'lessthan' },
|
|
238
|
+
{ key: 'Greater than or equal', value: 'greaterthanorequal' },
|
|
239
|
+
{ key: 'Less than or equal', value: 'lessthanorequal' }
|
|
240
|
+
];
|
|
241
|
+
break;
|
|
242
|
+
case 'date':
|
|
243
|
+
operators = [
|
|
244
|
+
{ key: 'Is Empty', value: 'isempty' },
|
|
245
|
+
{ key: 'Is Not Empty', value: 'isnotempty' },
|
|
246
|
+
{ key: 'Equal', value: 'equal' },
|
|
247
|
+
{ key: 'Not Equal', value: 'notequal' },
|
|
248
|
+
{ key: 'Greater than', value: 'dategreaterthan' },
|
|
249
|
+
{ key: 'Less than', value: 'datelessthan' }
|
|
250
|
+
];
|
|
251
|
+
break;
|
|
252
|
+
case 'boolean':
|
|
253
|
+
operators = [
|
|
254
|
+
{ key: 'Equal', value: 'equal' },
|
|
255
|
+
{ key: 'Not Equal', value: 'notequal' }
|
|
256
|
+
];
|
|
257
|
+
break;
|
|
258
|
+
default: // 'string'
|
|
259
|
+
if (component.type === 'time') {
|
|
260
|
+
operators = [
|
|
261
|
+
{ key: 'Is Empty', value: 'isempty' },
|
|
262
|
+
{ key: 'Is Not Empty', value: 'isnotempty' },
|
|
263
|
+
{ key: 'Equal', value: 'equal' },
|
|
264
|
+
{ key: 'Not Equal', value: 'notequal' },
|
|
265
|
+
{ key: 'Greater than', value: 'timegreaterthan' },
|
|
266
|
+
{ key: 'Less than', value: 'timelessthan' }
|
|
267
|
+
];
|
|
268
|
+
}
|
|
269
|
+
else if (component.type === 'dateTime') {
|
|
270
|
+
operators = [
|
|
271
|
+
{ key: 'Is Empty', value: 'isempty' },
|
|
272
|
+
{ key: 'Is Not Empty', value: 'isnotempty' },
|
|
273
|
+
{ key: 'Equal', value: 'equal' },
|
|
274
|
+
{ key: 'Not Equal', value: 'notequal' },
|
|
275
|
+
{ key: 'Greater than', value: 'datetimegreaterthan' },
|
|
276
|
+
{ key: 'Less than', value: 'datetimelessthan' }
|
|
277
|
+
];
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
// Standard string operators
|
|
281
|
+
operators = [
|
|
282
|
+
{ key: 'Is Empty', value: 'isempty' },
|
|
283
|
+
{ key: 'Is Not Empty', value: 'isnotempty' },
|
|
284
|
+
{ key: 'Equal', value: 'equal' },
|
|
285
|
+
{ key: 'Not Equal', value: 'notequal' },
|
|
286
|
+
{ key: 'Starts With', value: 'startswith' },
|
|
287
|
+
{ key: 'Not Starts With', value: 'doesnotstartswith' },
|
|
288
|
+
{ key: 'Contains', value: 'contains' },
|
|
289
|
+
{ key: 'Not Contains', value: 'notcontains' },
|
|
290
|
+
];
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// Build column configuration
|
|
295
|
+
const column = {
|
|
296
|
+
field: component.id,
|
|
297
|
+
label: component.label || component.id,
|
|
298
|
+
type: fieldType,
|
|
299
|
+
format: fieldType === 'date' ? 'MM/dd/yyyy' : undefined,
|
|
300
|
+
operators
|
|
301
|
+
};
|
|
302
|
+
// Determine if component should use column template
|
|
303
|
+
const usesTemplate = hasSelectableOptions(component)
|
|
304
|
+
|| component.type === 'date'
|
|
305
|
+
|| component.type === 'time'
|
|
306
|
+
|| component.type === 'dateTime'
|
|
307
|
+
|| component.type === 'dateRange';
|
|
308
|
+
// For fields with options or date/time types, add column template for custom input widget
|
|
309
|
+
if (usesTemplate) {
|
|
310
|
+
column.template = createColumnTemplate(component, qbRef, fetchedOptions);
|
|
311
|
+
}
|
|
312
|
+
// For array fields with options not using template, provide values for dropdown selection
|
|
313
|
+
else if (isArray && component.options && Array.isArray(component.options)) {
|
|
314
|
+
// Transform options to format QueryBuilder expects
|
|
315
|
+
const values = component.options.map(opt => {
|
|
316
|
+
if (typeof opt === 'string') {
|
|
317
|
+
return opt;
|
|
318
|
+
}
|
|
319
|
+
else if (opt && typeof opt === 'object' && 'value' in opt) {
|
|
320
|
+
return opt.value;
|
|
321
|
+
}
|
|
322
|
+
return String(opt);
|
|
323
|
+
});
|
|
324
|
+
column.values = values;
|
|
325
|
+
}
|
|
326
|
+
return column;
|
|
327
|
+
});
|
|
328
|
+
};
|
|
329
|
+
const handleAddRule = () => {
|
|
330
|
+
setActiveConditionType('visibleWhen');
|
|
331
|
+
setIsDialogOpen(true);
|
|
332
|
+
};
|
|
333
|
+
const handleDialogClose = () => {
|
|
334
|
+
setIsDialogOpen(false);
|
|
335
|
+
};
|
|
336
|
+
const handleSaveConditions = () => {
|
|
337
|
+
const updatedConditions = [];
|
|
338
|
+
const state = conditionsRef.current;
|
|
339
|
+
if (state.visibleWhen?.rules?.length > 0)
|
|
340
|
+
updatedConditions.push('visibleWhen');
|
|
341
|
+
if (state.hideWhen?.rules?.length > 0)
|
|
342
|
+
updatedConditions.push('hideWhen');
|
|
343
|
+
if (state.readOnlyWhen?.rules?.length > 0)
|
|
344
|
+
updatedConditions.push('readOnlyWhen');
|
|
345
|
+
if (state.disabledWhen?.rules?.length > 0)
|
|
346
|
+
updatedConditions.push('disabledWhen');
|
|
347
|
+
if (state.requiredWhen?.rules?.length > 0)
|
|
348
|
+
updatedConditions.push('requiredWhen');
|
|
349
|
+
if (state.setValueWhen?.condition?.rules?.length > 0)
|
|
350
|
+
updatedConditions.push('setValueWhen');
|
|
351
|
+
if (state.choiceBasedField)
|
|
352
|
+
updatedConditions.push('choiceBasedField');
|
|
353
|
+
if (state.conditionalData && Array.isArray(state.conditionalData) && state.conditionalData.length > 0)
|
|
354
|
+
updatedConditions.push('conditionalData');
|
|
355
|
+
setSavedConditions(updatedConditions);
|
|
356
|
+
setIsDialogOpen(false);
|
|
357
|
+
notifyParent(conditionsRef.current);
|
|
358
|
+
};
|
|
359
|
+
const handleEditCondition = (conditionType) => {
|
|
360
|
+
setActiveConditionType(conditionType);
|
|
361
|
+
setIsDialogOpen(true);
|
|
362
|
+
};
|
|
363
|
+
const handleDeleteCondition = (conditionType) => {
|
|
364
|
+
const type = conditionType;
|
|
365
|
+
updateCondition(type, type === 'setValueWhen' ? { value: undefined } : undefined);
|
|
366
|
+
setSavedConditions(savedConditions.filter(c => c !== conditionType));
|
|
367
|
+
handleSaveConditions();
|
|
368
|
+
};
|
|
369
|
+
const getConditionLabel = (type) => {
|
|
370
|
+
const labels = {
|
|
371
|
+
visibleWhen: l10n.getConstant('conditionalVisibility') || 'Conditional Visibility',
|
|
372
|
+
hideWhen: l10n.getConstant('conditionalHide') || 'Conditional Hide',
|
|
373
|
+
readOnlyWhen: l10n.getConstant('conditionalReadOnly') || 'Conditional Read-Only',
|
|
374
|
+
disabledWhen: l10n.getConstant('conditionalDisable') || 'Conditional Disable',
|
|
375
|
+
requiredWhen: l10n.getConstant('conditionalRequired') || 'Conditional Required',
|
|
376
|
+
setValueWhen: l10n.getConstant('conditionalSetValue') || 'Set Value When',
|
|
377
|
+
choiceBasedField: l10n.getConstant('choiceBasedField') || 'Choice-Based Field',
|
|
378
|
+
conditionalData: l10n.getConstant('conditionalData') || 'Conditional Data'
|
|
379
|
+
};
|
|
380
|
+
return labels[type] || type;
|
|
381
|
+
};
|
|
382
|
+
const conditionListData = supportedConditions
|
|
383
|
+
.filter(c => {
|
|
384
|
+
if (c === 'conditionalData') {
|
|
385
|
+
return componentForEdit?.type === 'dataGrid';
|
|
386
|
+
}
|
|
387
|
+
return true;
|
|
388
|
+
})
|
|
389
|
+
.map(type => ({
|
|
390
|
+
text: getConditionLabel(type),
|
|
391
|
+
id: type
|
|
392
|
+
}));
|
|
393
|
+
const handleVisibilityRuleChange = (_args) => {
|
|
394
|
+
if (qbRefs.visible.current) {
|
|
395
|
+
const rule = qbRefs.visible.current.getValidRules(qbRefs.visible.current.rule);
|
|
396
|
+
updateCondition('visibleWhen', rule);
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
const handleHideRuleChange = (_args) => {
|
|
400
|
+
if (qbRefs.hidden.current) {
|
|
401
|
+
const rule = qbRefs.hidden.current.getValidRules(qbRefs.hidden.current.rule);
|
|
402
|
+
updateCondition('hideWhen', rule);
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
const handleReadOnlyRuleChange = (_args) => {
|
|
406
|
+
if (qbRefs.readOnly.current) {
|
|
407
|
+
const rule = qbRefs.readOnly.current.getValidRules(qbRefs.readOnly.current.rule);
|
|
408
|
+
updateCondition('readOnlyWhen', rule);
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
const handleDisabledRuleChange = (_args) => {
|
|
412
|
+
if (qbRefs.disabled.current) {
|
|
413
|
+
const rule = qbRefs.disabled.current.getValidRules(qbRefs.disabled.current.rule);
|
|
414
|
+
updateCondition('disabledWhen', rule);
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
const handleRequiredRuleChange = (_args) => {
|
|
418
|
+
if (qbRefs.required.current) {
|
|
419
|
+
const rule = qbRefs.required.current.getValidRules(qbRefs.required.current.rule);
|
|
420
|
+
updateCondition('requiredWhen', rule);
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
const handleSetValueRuleChange = (_args) => {
|
|
424
|
+
if (qbRefs.setValue.current) {
|
|
425
|
+
const rule = qbRefs.setValue.current.getValidRules(qbRefs.setValue.current.rule);
|
|
426
|
+
updateCondition('setValueWhen', { ...conditionsRef.current.setValueWhen, condition: rule });
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
const handleSetValueValueChange = (e) => {
|
|
430
|
+
// Handle Syncfusion component events (which pass value via event object)
|
|
431
|
+
const newValue = e.target?.value !== undefined ? e.target.value : (e.value !== undefined ? e.value : '');
|
|
432
|
+
updateCondition('setValueWhen', { ...conditionsRef.current.setValueWhen, value: newValue });
|
|
433
|
+
};
|
|
434
|
+
const handleChoiceBasedFieldChange = (rule) => {
|
|
435
|
+
updateCondition('choiceBasedField', rule);
|
|
436
|
+
};
|
|
437
|
+
const updateCondition = (type, rule) => {
|
|
438
|
+
conditionsRef.current = { ...conditionsRef.current, [type]: rule };
|
|
439
|
+
};
|
|
440
|
+
const notifyParent = (cond) => {
|
|
441
|
+
const finalConditions = {};
|
|
442
|
+
// Only include supported conditions that have rules defined
|
|
443
|
+
if (supportedConditions.includes('visibleWhen') &&
|
|
444
|
+
cond.visibleWhen && cond.visibleWhen.rules && cond.visibleWhen.rules.length > 0) {
|
|
445
|
+
finalConditions.visibleWhen = cond.visibleWhen;
|
|
446
|
+
}
|
|
447
|
+
if (supportedConditions.includes('hideWhen') &&
|
|
448
|
+
cond.hideWhen && cond.hideWhen.rules && cond.hideWhen.rules.length > 0) {
|
|
449
|
+
finalConditions.hideWhen = cond.hideWhen;
|
|
450
|
+
}
|
|
451
|
+
if (supportedConditions.includes('readOnlyWhen') &&
|
|
452
|
+
cond.readOnlyWhen && cond.readOnlyWhen.rules && cond.readOnlyWhen.rules.length > 0) {
|
|
453
|
+
finalConditions.readOnlyWhen = cond.readOnlyWhen;
|
|
454
|
+
}
|
|
455
|
+
if (supportedConditions.includes('disabledWhen') &&
|
|
456
|
+
cond.disabledWhen && cond.disabledWhen.rules && cond.disabledWhen.rules.length > 0) {
|
|
457
|
+
finalConditions.disabledWhen = cond.disabledWhen;
|
|
458
|
+
}
|
|
459
|
+
if (supportedConditions.includes('requiredWhen') &&
|
|
460
|
+
cond.requiredWhen && cond.requiredWhen.rules && cond.requiredWhen.rules.length > 0) {
|
|
461
|
+
finalConditions.requiredWhen = cond.requiredWhen;
|
|
462
|
+
}
|
|
463
|
+
if (supportedConditions.includes('setValueWhen') &&
|
|
464
|
+
cond.setValueWhen && cond.setValueWhen.condition && cond.setValueWhen.condition.rules && cond.setValueWhen.condition.rules.length > 0 && cond.setValueWhen.value !== undefined && cond.setValueWhen.value !== '') {
|
|
465
|
+
finalConditions.setValueWhen = {
|
|
466
|
+
condition: cond.setValueWhen.condition,
|
|
467
|
+
value: cond.setValueWhen.value
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
if (supportedConditions.includes('choiceBasedField') && cond.choiceBasedField) {
|
|
471
|
+
finalConditions.choiceBasedField = cond.choiceBasedField;
|
|
472
|
+
}
|
|
473
|
+
if (supportedConditions.includes('conditionalData') &&
|
|
474
|
+
cond.conditionalData && Array.isArray(cond.conditionalData) &&
|
|
475
|
+
cond.conditionalData.length > 0) {
|
|
476
|
+
// Only include rules with valid conditions
|
|
477
|
+
const validRules = cond.conditionalData.filter(rule => {
|
|
478
|
+
if (!rule.condition || !rule.dataSource) {
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
// Check if condition is composite (has rules array) or simple (has field)
|
|
482
|
+
const hasRules = 'rules' in rule.condition && Array.isArray(rule.condition.rules) && rule.condition.rules.length > 0;
|
|
483
|
+
const isSimple = 'field' in rule.condition;
|
|
484
|
+
return hasRules || isSimple;
|
|
485
|
+
});
|
|
486
|
+
if (validRules.length > 0) {
|
|
487
|
+
finalConditions.conditionalData = validRules;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
onChange(finalConditions);
|
|
491
|
+
};
|
|
492
|
+
// Update internal ref when existingConditions prop changes
|
|
493
|
+
useEffect(() => {
|
|
494
|
+
conditionsRef.current = {
|
|
495
|
+
visibleWhen: existingConditions?.visibleWhen,
|
|
496
|
+
hideWhen: existingConditions?.hideWhen,
|
|
497
|
+
readOnlyWhen: existingConditions?.readOnlyWhen,
|
|
498
|
+
disabledWhen: existingConditions?.disabledWhen,
|
|
499
|
+
requiredWhen: existingConditions?.requiredWhen,
|
|
500
|
+
setValueWhen: existingConditions?.setValueWhen,
|
|
501
|
+
choiceBasedField: existingConditions?.choiceBasedField,
|
|
502
|
+
conditionalData: existingConditions?.conditionalData
|
|
503
|
+
};
|
|
504
|
+
}, [existingConditions]);
|
|
505
|
+
const visibleColumns = buildColumnsForQueryBuilder(qbRefs.visible);
|
|
506
|
+
const hiddenColumns = buildColumnsForQueryBuilder(qbRefs.hidden);
|
|
507
|
+
const readOnlyColumns = buildColumnsForQueryBuilder(qbRefs.readOnly);
|
|
508
|
+
const disabledColumns = buildColumnsForQueryBuilder(qbRefs.disabled);
|
|
509
|
+
const requiredColumns = buildColumnsForQueryBuilder(qbRefs.required);
|
|
510
|
+
const setValueColumns = buildColumnsForQueryBuilder(qbRefs.setValue);
|
|
511
|
+
useEffect(() => {
|
|
512
|
+
if (isDialogOpen) {
|
|
513
|
+
setShowStyles(true);
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
const timer = setTimeout(() => {
|
|
517
|
+
setShowStyles(false);
|
|
518
|
+
}, 400); // Remove styles after 300ms
|
|
519
|
+
return () => clearTimeout(timer);
|
|
520
|
+
}
|
|
521
|
+
}, [isDialogOpen]);
|
|
522
|
+
const footerTemplate = useCallback(() => {
|
|
523
|
+
return (_jsxs("div", { className: "import-dialog-footer", children: [_jsx(ButtonComponent, { cssClass: "e-flat", onClick: handleDialogClose, "aria-label": l10n.getConstant('cancel'), children: l10n.getConstant('cancel') }), _jsx(ButtonComponent, { cssClass: "e-primary import-btn", onClick: handleSaveConditions, "aria-label": l10n.getConstant('save'), children: l10n.getConstant('save') })] }));
|
|
524
|
+
}, [handleDialogClose, handleSaveConditions]);
|
|
525
|
+
return (_jsxs("div", { className: "conditions-editor-wrapper", "aria-label": l10n.getConstant('conditions'), children: [savedConditions.length === 0 ? (_jsxs("div", { style: { padding: '0.75rem 1rem' }, children: [_jsx("p", { style: { fontSize: '13px', color: 'rgb(var(--sf-color-on-surface-variant))', margin: '0 0 12px 0' }, children: l10n.getConstant('conditionsEditorLabel') }), _jsx(ButtonComponent, { onClick: handleAddRule, cssClass: "e-outline", style: { width: '100%' }, iconCss: "e-icons e-plus", content: l10n.getConstant('addRule'), "aria-label": l10n.getConstant('addRule') })] })) : (
|
|
526
|
+
// Display saved conditions with Edit/Delete buttons
|
|
527
|
+
_jsxs("div", { style: { padding: '0.75rem 1.2rem' }, className: "conditions-editor-dialog", role: "region", "aria-label": l10n.getConstant('conditions'), children: [_jsxs("div", { style: { marginBottom: '12px' }, children: [_jsx("p", { id: "conditions-editor-description", style: { fontSize: '13px', color: 'rgb(var(--sf-color-on-surface-variant))', margin: '0 0 12px 0' }, children: l10n.getConstant('conditionsEditorLabel') }), _jsx(ButtonComponent, { onClick: handleAddRule, cssClass: "e-outline", style: { width: '100%' }, iconCss: "e-icons e-plus", content: l10n.getConstant('addRule'), "aria-label": l10n.getConstant('addRule') })] }), _jsx(ListBoxComponent, { dataSource: savedConditions.map(c => ({ text: getConditionLabel(c), id: c })), fields: { text: 'text', value: 'id' }, selectionSettings: { mode: 'Single' }, value: [], itemTemplate: (props) => (_jsxs("div", { style: {
|
|
528
|
+
display: 'flex',
|
|
529
|
+
alignItems: 'center',
|
|
530
|
+
justifyContent: 'space-between',
|
|
531
|
+
padding: '10px 12px',
|
|
532
|
+
borderRadius: '4px',
|
|
533
|
+
fontSize: '14px'
|
|
534
|
+
}, children: [_jsx("div", { style: { display: 'flex', alignItems: 'center', gap: '8px' }, children: _jsx("span", { children: props.text }) }), _jsxs("div", { style: { display: 'flex', gap: '8px' }, children: [_jsx(ButtonComponent, { onClick: (e) => {
|
|
535
|
+
e.stopPropagation();
|
|
536
|
+
handleEditCondition(props.id);
|
|
537
|
+
}, cssClass: 'e-flat', iconCss: "e-icons e-edit", title: "Edit", "aria-label": `${l10n.getConstant('edit')} ${props.text}` }), _jsx(ButtonComponent, { onClick: (e) => {
|
|
538
|
+
e.stopPropagation();
|
|
539
|
+
handleDeleteCondition(props.id);
|
|
540
|
+
}, cssClass: 'e-flat', iconCss: "e-icons e-trash", title: "Delete", "aria-label": `${l10n.getConstant('delete')} ${props.text}` })] })] })) })] })), _jsx("div", { id: "targetElement", "aria-hidden": !isDialogOpen, style: showStyles ? {
|
|
541
|
+
position: 'fixed',
|
|
542
|
+
top: '48px',
|
|
543
|
+
left: 0,
|
|
544
|
+
height: '100dvh',
|
|
545
|
+
width: '100dvw'
|
|
546
|
+
} : {}, children: _jsx(DialogComponent, { className: "conditions-editor-dialog", isModal: true, visible: isDialogOpen, close: handleDialogClose, showCloseIcon: true, target: '#targetElement', closeOnEscape: true, header: "Conditions", width: "990px", height: "80vh", footerTemplate: footerTemplate, animationSettings: { effect: 'FadeZoom' }, children: _jsxs("div", { style: { display: 'flex', height: '100%' }, children: [_jsx("div", { role: "navigation", "aria-label": l10n.getConstant('conditions'), style: {
|
|
547
|
+
width: '280px',
|
|
548
|
+
borderRight: '1px solid #e0e0e0',
|
|
549
|
+
overflowY: 'auto',
|
|
550
|
+
maxHeight: '60vh',
|
|
551
|
+
padding: '20px 10px 0 0'
|
|
552
|
+
}, children: _jsx(ListBoxComponent, { dataSource: conditionListData, fields: { text: 'text', value: 'id' }, change: (e) => {
|
|
553
|
+
if (e.value) {
|
|
554
|
+
setActiveConditionType(e.value[0]);
|
|
555
|
+
}
|
|
556
|
+
}, value: [activeConditionType], selectionSettings: { mode: 'Single' }, itemTemplate: (props) => (_jsx("div", { style: {
|
|
557
|
+
padding: '12px 16px',
|
|
558
|
+
cursor: 'pointer',
|
|
559
|
+
fontSize: '14px',
|
|
560
|
+
borderRadius: '6px',
|
|
561
|
+
transition: 'all 0.2s ease',
|
|
562
|
+
marginBottom: '4px'
|
|
563
|
+
}, children: props.text })) }) }), _jsxs("div", { style: {
|
|
564
|
+
flex: 1,
|
|
565
|
+
padding: '16px',
|
|
566
|
+
overflowY: 'auto',
|
|
567
|
+
maxHeight: '60vh'
|
|
568
|
+
}, role: "region", "aria-live": "polite", "aria-label": activeConditionType, children: [activeConditionType === 'visibleWhen' && supportedConditions.includes('visibleWhen') && (_jsxs("div", { children: [_jsx("h4", { style: { marginTop: 0, marginBottom: '12px' }, children: l10n.getConstant('conditionalVisibility') }), _jsx("p", { style: { fontSize: '13px', color: 'rgb(var(--sf-color-on-surface-variant))', marginBottom: '12px' }, children: l10n.getConstant('conditionalVisibilityDescription') }), _jsx("div", { tabIndex: -1, "aria-describedby": "conditional-visibility-description", "aria-label": l10n.getConstant('conditionalVisibility'), children: _jsx(QueryBuilderComponent, { ref: qbRefs.visible, dataSource: [], columns: visibleColumns, rule: conditionsRef.current.visibleWhen, ruleChange: handleVisibilityRuleChange }) })] })), activeConditionType === 'hideWhen' && supportedConditions.includes('hideWhen') && (_jsxs("div", { children: [_jsx("h4", { style: { marginTop: 0, marginBottom: '12px' }, children: l10n.getConstant('conditionalHide') }), _jsx("p", { style: { fontSize: '13px', color: 'rgb(var(--sf-color-on-surface-variant))', marginBottom: '12px' }, children: l10n.getConstant('conditionalHideDescription') }), _jsx("div", { tabIndex: -1, "aria-describedby": "conditional-readonly-description", "aria-label": l10n.getConstant('conditionalHideDescription'), children: _jsx(QueryBuilderComponent, { ref: qbRefs.hidden, dataSource: [], columns: hiddenColumns, rule: conditionsRef.current.hideWhen, ruleChange: handleHideRuleChange }) })] })), activeConditionType === 'readOnlyWhen' && supportedConditions.includes('readOnlyWhen') && (_jsxs("div", { children: [_jsx("h4", { style: { marginTop: 0, marginBottom: '12px' }, children: l10n.getConstant('conditionalReadOnly') }), _jsx("p", { style: { fontSize: '13px', color: 'rgb(var(--sf-color-on-surface-variant))', marginBottom: '12px' }, children: l10n.getConstant('conditionalReadOnlyDescription') }), _jsx("div", { tabIndex: -1, "aria-describedby": "conditional-readonly-description", "aria-label": l10n.getConstant('conditionalReadOnlyDescription'), children: _jsx(QueryBuilderComponent, { ref: qbRefs.readOnly, dataSource: [], columns: readOnlyColumns, rule: conditionsRef.current.readOnlyWhen, ruleChange: handleReadOnlyRuleChange }) })] })), activeConditionType === 'disabledWhen' && supportedConditions.includes('disabledWhen') && (_jsxs("div", { children: [_jsx("h4", { style: { marginTop: 0, marginBottom: '12px' }, children: l10n.getConstant('conditionalDisable') }), _jsx("p", { style: { fontSize: '13px', color: 'rgb(var(--sf-color-on-surface-variant))', marginBottom: '12px' }, children: l10n.getConstant('conditionalDisableDescription') }), _jsx("div", { tabIndex: -1, "aria-describedby": "conditional-readonly-description", "aria-label": l10n.getConstant('conditionalDisableDescription'), children: _jsx(QueryBuilderComponent, { ref: qbRefs.disabled, dataSource: [], columns: disabledColumns, rule: conditionsRef.current.disabledWhen, ruleChange: handleDisabledRuleChange }) })] })), activeConditionType === 'requiredWhen' && supportedConditions.includes('requiredWhen') && (_jsxs("div", { children: [_jsx("h4", { style: { marginTop: 0, marginBottom: '12px' }, children: l10n.getConstant('conditionalRequired') }), _jsx("p", { style: { fontSize: '13px', color: 'rgb(var(--sf-color-on-surface-variant))', marginBottom: '12px' }, children: l10n.getConstant('conditionalRequiredDescription') }), _jsx("div", { tabIndex: -1, "aria-describedby": "conditional-readonly-description", "aria-label": l10n.getConstant('conditionalRequiredDescription'), children: _jsx(QueryBuilderComponent, { ref: qbRefs.required, dataSource: [], columns: requiredColumns, rule: conditionsRef.current.requiredWhen, ruleChange: handleRequiredRuleChange }) })] })), activeConditionType === 'setValueWhen' && supportedConditions.includes('setValueWhen') && (_jsxs("div", { children: [_jsx("h4", { style: { marginTop: 0, marginBottom: '12px' }, children: l10n.getConstant('conditionalSetValue') }), _jsx("p", { style: { fontSize: '13px', color: 'rgb(var(--sf-color-on-surface-variant))', marginBottom: '12px' }, children: l10n.getConstant('conditionalSetValueDescription') }), _jsx("div", { tabIndex: -1, "aria-describedby": "conditional-readonly-description", "aria-label": l10n.getConstant('conditionalSetValueDescription'), children: _jsx(QueryBuilderComponent, { ref: qbRefs.setValue, dataSource: [], columns: setValueColumns, rule: conditionsRef.current.setValueWhen?.condition, ruleChange: handleSetValueRuleChange }) }), _jsx("div", { style: { marginTop: '16px' }, children: _jsx(ValueRenderer, { componentForEdit: componentForEdit, conditionsRef: conditionsRef, handleSetValueValueChange: handleSetValueValueChange }) })] })), activeConditionType === 'choiceBasedField' && supportedConditions.includes('choiceBasedField') && (_jsxs("div", { children: [_jsx("h4", { style: { marginTop: 0, marginBottom: '12px' }, children: l10n.getConstant('choiceBasedField') }), _jsx("p", { style: { fontSize: '13px', color: 'rgb(var(--sf-color-on-surface-variant))', marginBottom: '12px' }, children: l10n.getConstant('choiceBasedFieldDescription') }), componentForEdit && (componentForEdit.type === 'dropdown' || componentForEdit.type === 'multiselect') ? (_jsx(ChoiceBasedFieldEditor, { componentForEdit: componentForEdit, componentFields: componentFields, existingRule: conditionsRef.current.choiceBasedField, onChange: handleChoiceBasedFieldChange })) : (_jsx("div", { className: "e-info", style: { padding: '10px', backgroundColor: '#e7f3ff', border: '1px solid #0066cc', borderRadius: '4px' }, role: "alert", "aria-live": "polite", children: l10n.getConstant('choiceBasedOnlyForDropdown') || 'Choice-Based Field Rules apply only to Dropdown and MultiSelect components' }))] })), activeConditionType === 'conditionalData' && supportedConditions.includes('conditionalData') && componentForEdit?.type === 'dataGrid' && (_jsxs("div", { role: "group", "aria-labelledby": "conditional-data-heading", "aria-describedby": "conditional-data-description", children: [_jsx("h4", { style: { marginTop: 0, marginBottom: '12px' }, children: l10n.getConstant('conditionalData') }), _jsx("p", { style: { fontSize: '13px', color: 'rgb(var(--sf-color-on-surface-variant))', marginBottom: '12px' }, children: l10n.getConstant('conditionalDataDescription') }), _jsx(ConditionDataEditor, { componentFields: componentFields, componentForEdit: componentForEdit, excludeFieldId: excludeFieldId, existingRules: conditionsRef.current.conditionalData || componentForEdit?.conditions?.conditionalData, onChange: (rules) => {
|
|
569
|
+
updateCondition('conditionalData', rules);
|
|
570
|
+
} })] }))] }, savedConditions.join(','))] }) }) })] }));
|
|
571
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React, { type ReactNode } from 'react';
|
|
2
|
+
interface AccordionWrapperProps {
|
|
3
|
+
title: string;
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Accordion Wrapper Component
|
|
8
|
+
* Wraps any content in a collapsible accordion with expand/collapse icon
|
|
9
|
+
* @param title - Accordion header title
|
|
10
|
+
* @param children - Content to display inside accordion
|
|
11
|
+
*/
|
|
12
|
+
export declare const AccordionWrapper: React.FC<AccordionWrapperProps>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* Accordion Wrapper Component
|
|
5
|
+
* Wraps any content in a collapsible accordion with expand/collapse icon
|
|
6
|
+
* @param title - Accordion header title
|
|
7
|
+
* @param children - Content to display inside accordion
|
|
8
|
+
*/
|
|
9
|
+
export const AccordionWrapper = ({ title, children }) => {
|
|
10
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
11
|
+
return (_jsxs("div", { className: 'custom-accordion', style: {
|
|
12
|
+
overflow: 'hidden'
|
|
13
|
+
}, children: [_jsxs("div", { onClick: () => setIsOpen(!isOpen), role: "button", className: 'custom-accordion-header', tabIndex: 0, "aria-expanded": isOpen, "aria-labelledby": `accordion-content-${title}`, "aria-label": title, onKeyDown: (e) => {
|
|
14
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
15
|
+
e.preventDefault();
|
|
16
|
+
setIsOpen(!isOpen);
|
|
17
|
+
}
|
|
18
|
+
}, style: {
|
|
19
|
+
display: 'flex',
|
|
20
|
+
alignItems: 'center',
|
|
21
|
+
gap: '10px',
|
|
22
|
+
height: '45px',
|
|
23
|
+
cursor: 'pointer',
|
|
24
|
+
userSelect: 'none',
|
|
25
|
+
borderBottom: isOpen ? 'none' : '1px solid rgb(var(--sf-color-line-color))'
|
|
26
|
+
}, onMouseEnter: (e) => {
|
|
27
|
+
e.currentTarget.style.backgroundColor = 'rgba(0, 0, 0, 0.04)';
|
|
28
|
+
}, onMouseLeave: (e) => {
|
|
29
|
+
e.currentTarget.style.backgroundColor = 'rgb(var(--sf-color-surface))';
|
|
30
|
+
}, children: [_jsx("span", { style: { marginLeft: '10px' }, className: `e-icons ${isOpen ? 'e-chevron-down' : 'e-chevron-right'}`, "aria-hidden": "true" }), _jsx("span", { style: {
|
|
31
|
+
fontWeight: 500,
|
|
32
|
+
fontSize: '14px',
|
|
33
|
+
color: 'var(--jsonview-text-color)'
|
|
34
|
+
}, children: title })] }), isOpen && (_jsx("div", { id: `accordion-content-${title}`, role: "region", "aria-label": title, style: isOpen ? {
|
|
35
|
+
padding: '0.5rem 1rem 1rem',
|
|
36
|
+
borderBottom: '1px solid rgb(var(--sf-color-line-color))'
|
|
37
|
+
} : undefined, children: children }))] }));
|
|
38
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type CustomValidationRule } from '../types/FormSchema';
|
|
3
|
+
import { type FormComponent } from '../types/FormSchema';
|
|
4
|
+
export interface CustomValidationEditorProps {
|
|
5
|
+
componentFields: FormComponent[];
|
|
6
|
+
excludeFieldId?: string;
|
|
7
|
+
existingRules?: CustomValidationRule[];
|
|
8
|
+
values?: any;
|
|
9
|
+
onChange: (rules: CustomValidationRule[]) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare const CustomValidationEditor: React.FC<CustomValidationEditorProps>;
|