@gridsuite/commons-ui 0.116.3 → 0.116.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/contingencyList/criteriaBased/CriteriaBasedForm.js +3 -0
- package/dist/components/dialogs/elementSaveDialog/ElementSaveDialog.js +35 -26
- package/dist/components/dialogs/elementSaveDialog/utils.d.ts +23 -0
- package/dist/components/dialogs/elementSaveDialog/utils.js +33 -0
- package/dist/components/directoryItemSelector/DirectoryItemSelector.d.ts +1 -1
- package/dist/components/directoryItemSelector/DirectoryItemSelector.js +72 -15
- package/dist/components/directoryItemSelector/utils.d.ts +52 -0
- package/dist/components/directoryItemSelector/utils.js +95 -0
- package/dist/components/dnd-table/dnd-table-add-rows-dialog.js +2 -2
- package/dist/components/filter/FilterForm.js +3 -0
- package/dist/components/filter/expert/ExpertFilterForm.js +3 -0
- package/dist/components/icons/ArrowsOutputIcon.d.ts +2 -0
- package/dist/components/icons/ArrowsOutputIcon.js +9 -0
- package/dist/components/icons/index.d.ts +1 -0
- package/dist/components/icons/index.js +2 -0
- package/dist/components/index.js +2 -0
- package/dist/components/inputs/reactHookForm/autocompleteInputs/AutocompleteInput.d.ts +3 -2
- package/dist/components/inputs/reactHookForm/autocompleteInputs/AutocompleteInput.js +9 -2
- package/dist/components/inputs/reactHookForm/selectInputs/SelectInput.d.ts +3 -2
- package/dist/components/inputs/reactHookForm/selectInputs/SelectInput.js +2 -0
- package/dist/components/parameters/common/ProviderParam.js +2 -2
- package/dist/components/parameters/common/limitreductions/limit-reduction-table-cell.js +2 -2
- package/dist/components/parameters/common/limitreductions/limit-reductions-table-form.js +2 -2
- package/dist/components/parameters/common/name-element-editor/name-element-editor-utils.js +1 -1
- package/dist/components/parameters/common/parameters-creation-dialog.js +2 -0
- package/dist/components/parameters/common/voltage-level-table/custom-voltage-level-table-cell.js +2 -2
- package/dist/components/parameters/common/widget/parameter-float.js +2 -2
- package/dist/components/parameters/common/widget/parameter-line-slider.js +2 -2
- package/dist/components/parameters/loadflow/load-flow-general-parameters.js +2 -2
- package/dist/components/parameters/loadflow/load-flow-parameter-field.js +2 -2
- package/dist/components/parameters/loadflow/load-flow-parameters-content.js +2 -2
- package/dist/components/parameters/loadflow/load-flow-parameters-dialog.js +4 -4
- package/dist/components/parameters/loadflow/load-flow-parameters-form.js +2 -2
- package/dist/components/parameters/loadflow/load-flow-parameters-header.js +2 -2
- package/dist/components/parameters/loadflow/load-flow-parameters-utils.js +3 -3
- package/dist/components/parameters/loadflow/use-load-flow-parameters-form.js +2 -2
- package/dist/components/parameters/network-visualizations/map-parameters.js +2 -2
- package/dist/components/parameters/network-visualizations/network-area-diagram-parameters.js +2 -2
- package/dist/components/parameters/network-visualizations/network-visualizations-form.js +2 -2
- package/dist/components/parameters/network-visualizations/single-line-diagram-parameters.js +2 -2
- package/dist/components/parameters/network-visualizations/use-network-visualizations-parameters-form.js +1 -1
- package/dist/components/parameters/security-analysis/security-analysis-parameters-dialog.js +2 -2
- package/dist/components/parameters/security-analysis/security-analysis-parameters-form.js +2 -2
- package/dist/components/parameters/security-analysis/security-analysis-parameters-selector.js +2 -2
- package/dist/components/parameters/security-analysis/security-analysis-violations-hiding.js +2 -2
- package/dist/components/parameters/sensi/sensitivity-Flow-parameters.js +2 -2
- package/dist/components/parameters/sensi/sensitivity-analysis-parameters-dialog.js +2 -2
- package/dist/components/parameters/sensi/sensitivity-analysis-parameters-form.js +2 -2
- package/dist/components/parameters/sensi/sensitivity-parameters-selector.js +2 -2
- package/dist/components/parameters/sensi/sensitivity-table.js +2 -2
- package/dist/components/parameters/sensi/use-sensitivity-analysis-parameters.js +2 -2
- package/dist/components/parameters/short-circuit/short-circuit-fields.js +2 -2
- package/dist/components/parameters/short-circuit/short-circuit-parameters-form.js +2 -2
- package/dist/components/parameters/short-circuit/use-short-circuit-parameters-form.js +1 -1
- package/dist/components/parameters/voltage-init/equipment-selection-parameters.js +2 -2
- package/dist/components/parameters/voltage-init/general-parameters.js +2 -2
- package/dist/components/parameters/voltage-init/use-voltage-init-parameters-form.js +1 -1
- package/dist/components/parameters/voltage-init/voltage-init-form-utils.js +2 -2
- package/dist/components/parameters/voltage-init/voltage-init-parameters-form.js +2 -2
- package/dist/components/treeViewFinder/TreeViewFinder.js +14 -13
- package/dist/hooks/useModificationLabelComputer.js +1 -0
- package/dist/index.js +9 -1
- package/dist/services/directory.d.ts +1 -0
- package/dist/services/directory.js +10 -2
- package/dist/services/index.js +2 -1
- package/dist/translations/en/networkModificationsEn.d.ts +1 -0
- package/dist/translations/en/networkModificationsEn.js +2 -1
- package/dist/translations/fr/networkModificationsFr.d.ts +1 -0
- package/dist/translations/fr/networkModificationsFr.js +2 -1
- package/dist/utils/constants/configConstants.d.ts +4 -0
- package/dist/utils/constants/configConstants.js +10 -0
- package/dist/utils/constants/index.d.ts +1 -0
- package/dist/utils/constants/index.js +5 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/types/modificationType.d.ts +5 -1
- package/dist/utils/types/modificationType.js +5 -0
- package/package.json +1 -1
|
@@ -12,6 +12,9 @@ import "../../dialogs/elementSaveDialog/ElementSaveDialog.js";
|
|
|
12
12
|
import "react-intl";
|
|
13
13
|
import "@mui/icons-material";
|
|
14
14
|
import "../../treeViewFinder/TreeViewFinder.js";
|
|
15
|
+
import "../../../utils/conversionUtils.js";
|
|
16
|
+
import "../../../utils/types/equipmentType.js";
|
|
17
|
+
import "../../../utils/yupConfig.js";
|
|
15
18
|
function CriteriaBasedForm({ equipments, defaultValues, children }) {
|
|
16
19
|
const { getValues, setValue } = useFormContext();
|
|
17
20
|
const { snackError } = useSnackMessage();
|
|
@@ -6,7 +6,6 @@ import { useForm } from "react-hook-form";
|
|
|
6
6
|
import { yupResolver } from "@hookform/resolvers/yup";
|
|
7
7
|
import "../../../utils/yupConfig.js";
|
|
8
8
|
import "../../../utils/types/equipmentType.js";
|
|
9
|
-
import { fetchDirectoryElementPath } from "../../../services/directory.js";
|
|
10
9
|
import "localized-countries";
|
|
11
10
|
import "localized-countries/data/fr";
|
|
12
11
|
import "localized-countries/data/en";
|
|
@@ -36,6 +35,7 @@ import "uuid";
|
|
|
36
35
|
import "../../inputs/reactQueryBuilder/PropertyValueEditor.js";
|
|
37
36
|
import "react-querybuilder";
|
|
38
37
|
import { CustomMuiDialog } from "../customMuiDialog/CustomMuiDialog.js";
|
|
38
|
+
import { initializeDirectory } from "./utils.js";
|
|
39
39
|
var OperationType = /* @__PURE__ */ ((OperationType2) => {
|
|
40
40
|
OperationType2["CREATE"] = "CREATE";
|
|
41
41
|
OperationType2["UPDATE"] = "UPDATE";
|
|
@@ -73,6 +73,7 @@ function ElementSaveDialog({
|
|
|
73
73
|
const [directorySelectorOpen, setDirectorySelectorOpen] = useState(false);
|
|
74
74
|
const [destinationFolder, setDestinationFolder] = useState();
|
|
75
75
|
const [selectedItem, setSelectedItem] = useState();
|
|
76
|
+
const [expanded, setExpanded] = useState([]);
|
|
76
77
|
const formMethods = useForm({
|
|
77
78
|
defaultValues: {
|
|
78
79
|
...emptyFormData,
|
|
@@ -89,8 +90,35 @@ function ElementSaveDialog({
|
|
|
89
90
|
const operationType = createOnlyMode ? "CREATE" : watch(FieldConstants.OPERATION_TYPE);
|
|
90
91
|
const isCreateMode = operationType === "CREATE";
|
|
91
92
|
const disableSave = Object.keys(errors).length > 0 || isCreateMode && !destinationFolder || !isCreateMode && !selectedItem;
|
|
93
|
+
const setDestinationFolderWithPath = useCallback(
|
|
94
|
+
(elementUuid, elementName, path) => {
|
|
95
|
+
setDestinationFolder({
|
|
96
|
+
id: elementUuid,
|
|
97
|
+
name: elementName
|
|
98
|
+
});
|
|
99
|
+
if (path && path.length > 0) {
|
|
100
|
+
const expandPath = path.map((element) => element.elementUuid);
|
|
101
|
+
setExpanded(expandPath);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
[]
|
|
105
|
+
);
|
|
106
|
+
const initializeDestinationFolder = useCallback(async () => {
|
|
107
|
+
const config = {
|
|
108
|
+
studyUuid,
|
|
109
|
+
initDirectory,
|
|
110
|
+
onError: (messageTxt, headerId) => {
|
|
111
|
+
snackError({ messageTxt, headerId });
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
const result = await initializeDirectory(config);
|
|
115
|
+
if (result) {
|
|
116
|
+
setDestinationFolderWithPath(result.element.elementUuid, result.element.elementName, result.path);
|
|
117
|
+
}
|
|
118
|
+
}, [studyUuid, initDirectory, snackError, setDestinationFolderWithPath]);
|
|
92
119
|
const onCancel = useCallback(() => {
|
|
93
120
|
reset({ ...emptyFormData, [FieldConstants.OPERATION_TYPE]: initialOperation });
|
|
121
|
+
setExpanded([]);
|
|
94
122
|
onClose();
|
|
95
123
|
}, [onClose, reset, initialOperation]);
|
|
96
124
|
useEffect(() => {
|
|
@@ -110,32 +138,11 @@ function ElementSaveDialog({
|
|
|
110
138
|
}
|
|
111
139
|
}, [prefixIdForGeneratedName, intl, reset, isCreateMode]);
|
|
112
140
|
useEffect(() => {
|
|
113
|
-
if (open
|
|
114
|
-
|
|
115
|
-
if (!res || res.length < 2) {
|
|
116
|
-
snackError({
|
|
117
|
-
messageTxt: "unknown study directory",
|
|
118
|
-
headerId: "studyDirectoryFetchingError"
|
|
119
|
-
});
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
const parentFolderIndex = res.length - 2;
|
|
123
|
-
const { elementUuid, elementName } = res[parentFolderIndex];
|
|
124
|
-
setDestinationFolder({
|
|
125
|
-
id: elementUuid,
|
|
126
|
-
name: elementName
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
}, [studyUuid, open, snackError, isCreateMode]);
|
|
131
|
-
useEffect(() => {
|
|
132
|
-
if (open && isCreateMode && initDirectory) {
|
|
133
|
-
setDestinationFolder({
|
|
134
|
-
id: initDirectory.elementUuid,
|
|
135
|
-
name: initDirectory.elementName
|
|
136
|
-
});
|
|
141
|
+
if (!open || !isCreateMode) {
|
|
142
|
+
return;
|
|
137
143
|
}
|
|
138
|
-
|
|
144
|
+
initializeDestinationFolder();
|
|
145
|
+
}, [open, isCreateMode, initializeDestinationFolder]);
|
|
139
146
|
const handleChangeFolder = useCallback(() => {
|
|
140
147
|
setDirectorySelectorOpen(true);
|
|
141
148
|
}, []);
|
|
@@ -145,6 +152,7 @@ function ElementSaveDialog({
|
|
|
145
152
|
if ((items == null ? void 0 : items.length) > 0 && items[0].id !== (destinationFolder == null ? void 0 : destinationFolder.id)) {
|
|
146
153
|
const { id, name } = items[0];
|
|
147
154
|
setDestinationFolder({ id, name });
|
|
155
|
+
setExpanded([]);
|
|
148
156
|
}
|
|
149
157
|
} else if ((items == null ? void 0 : items.length) > 0 && items[0].id !== (selectedItem == null ? void 0 : selectedItem.id)) {
|
|
150
158
|
const { id, name, description, parents } = items[0];
|
|
@@ -251,6 +259,7 @@ function ElementSaveDialog({
|
|
|
251
259
|
types: isCreateMode ? [ElementType.DIRECTORY] : [type],
|
|
252
260
|
onlyLeaves: isCreateMode ? false : void 0,
|
|
253
261
|
multiSelect: false,
|
|
262
|
+
expanded: isCreateMode ? expanded : [],
|
|
254
263
|
validationButtonText: intl.formatMessage({
|
|
255
264
|
id: "validate"
|
|
256
265
|
}),
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { UUID } from 'crypto';
|
|
2
|
+
import { ElementAttributes } from '../../../utils';
|
|
3
|
+
/**
|
|
4
|
+
* Generic directory initialization configuration
|
|
5
|
+
*/
|
|
6
|
+
export interface DirectoryInitConfig {
|
|
7
|
+
studyUuid?: UUID;
|
|
8
|
+
initDirectory?: ElementAttributes;
|
|
9
|
+
onError?: (message: string, headerId: string) => void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Generic destination directory initialization that follows the standard priority:
|
|
13
|
+
* 1. Last selected directory from localStorage
|
|
14
|
+
* 2. Study UUID (if provided)
|
|
15
|
+
* 3. Initial directory (if provided)
|
|
16
|
+
*
|
|
17
|
+
* @param config Configuration object
|
|
18
|
+
* @returns Promise resolving to { element, path } or null if all methods fail
|
|
19
|
+
*/
|
|
20
|
+
export declare function initializeDirectory(config: DirectoryInitConfig): Promise<{
|
|
21
|
+
element: ElementAttributes;
|
|
22
|
+
path?: ElementAttributes[];
|
|
23
|
+
} | null>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { getLastSelectedDirectoryId, fetchDirectoryPathSafe, clearLastSelectedDirectory } from "../../directoryItemSelector/utils.js";
|
|
2
|
+
async function initializeDirectory(config) {
|
|
3
|
+
const { studyUuid, initDirectory, onError } = config;
|
|
4
|
+
const lastSelectedDirId = getLastSelectedDirectoryId();
|
|
5
|
+
if (lastSelectedDirId) {
|
|
6
|
+
const path = await fetchDirectoryPathSafe(lastSelectedDirId);
|
|
7
|
+
if (path && path.length > 0) {
|
|
8
|
+
const targetElement = path[path.length - 1];
|
|
9
|
+
return { element: targetElement, path };
|
|
10
|
+
}
|
|
11
|
+
await clearLastSelectedDirectory();
|
|
12
|
+
}
|
|
13
|
+
if (studyUuid) {
|
|
14
|
+
const path = await fetchDirectoryPathSafe(studyUuid);
|
|
15
|
+
if (path && path.length >= 2) {
|
|
16
|
+
const parentFolderIndex = path.length - 2;
|
|
17
|
+
const parentElement = path[parentFolderIndex];
|
|
18
|
+
return {
|
|
19
|
+
element: parentElement,
|
|
20
|
+
path: path.slice(0, parentFolderIndex + 1)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
onError == null ? void 0 : onError("unknown study directory", "studyDirectoryFetchingError");
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
if (initDirectory) {
|
|
27
|
+
return { element: initDirectory };
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
export {
|
|
32
|
+
initializeDirectory
|
|
33
|
+
};
|
|
@@ -8,4 +8,4 @@ export interface DirectoryItemSelectorProps extends TreeViewFinderProps {
|
|
|
8
8
|
expanded?: UUID[];
|
|
9
9
|
selected?: UUID[];
|
|
10
10
|
}
|
|
11
|
-
export declare function DirectoryItemSelector({ open, types, equipmentTypes, itemFilter, expanded, selected, ...otherTreeViewFinderProps }: Readonly<DirectoryItemSelectorProps>): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export declare function DirectoryItemSelector({ open, types, equipmentTypes, itemFilter, expanded, selected, onClose, ...otherTreeViewFinderProps }: Readonly<DirectoryItemSelectorProps>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -6,6 +6,7 @@ import { TreeViewFinder } from "../treeViewFinder/TreeViewFinder.js";
|
|
|
6
6
|
import { useSnackMessage } from "../../hooks/useSnackMessage.js";
|
|
7
7
|
import { fetchElementsInfos } from "../../services/explore.js";
|
|
8
8
|
import { fetchRootFolders, fetchDirectoryContent } from "../../services/directory.js";
|
|
9
|
+
import { getExpansionPathsForSelected, fetchChildrenForExpandedNodes, initializeFromLastSelected, saveLastSelectedDirectoryFromNode } from "./utils.js";
|
|
9
10
|
const styles = {
|
|
10
11
|
icon: (theme) => ({
|
|
11
12
|
marginRight: theme.spacing(1),
|
|
@@ -108,10 +109,13 @@ function DirectoryItemSelector({
|
|
|
108
109
|
itemFilter,
|
|
109
110
|
expanded,
|
|
110
111
|
selected,
|
|
112
|
+
onClose,
|
|
111
113
|
...otherTreeViewFinderProps
|
|
112
114
|
}) {
|
|
113
115
|
const [data, setData] = useState([]);
|
|
114
116
|
const [rootDirectories, setRootDirectories] = useState([]);
|
|
117
|
+
const [isRootsLoaded, setIsRootsLoaded] = useState(false);
|
|
118
|
+
const [autoExpandedNodes, setAutoExpandedNodes] = useState([]);
|
|
115
119
|
const nodeMap = useRef({});
|
|
116
120
|
const dataRef = useRef([]);
|
|
117
121
|
dataRef.current = data;
|
|
@@ -158,6 +162,7 @@ function DirectoryItemSelector({
|
|
|
158
162
|
[convertRoots]
|
|
159
163
|
);
|
|
160
164
|
const updateRootDirectories = useCallback(() => {
|
|
165
|
+
setIsRootsLoaded(false);
|
|
161
166
|
fetchRootFolders(types).then((newData) => {
|
|
162
167
|
const [nrs, mdr] = updatedTree(rootsRef.current, nodeMap.current, null, newData);
|
|
163
168
|
setRootDirectories(nrs);
|
|
@@ -168,6 +173,8 @@ function DirectoryItemSelector({
|
|
|
168
173
|
messageTxt: error.message,
|
|
169
174
|
headerId: "DirectoryItemSelector"
|
|
170
175
|
});
|
|
176
|
+
}).finally(() => {
|
|
177
|
+
setIsRootsLoaded(true);
|
|
171
178
|
});
|
|
172
179
|
}, [convertRoots, types, snackError]);
|
|
173
180
|
const fetchDirectoryChildren = useCallback(
|
|
@@ -200,24 +207,73 @@ function DirectoryItemSelector({
|
|
|
200
207
|
},
|
|
201
208
|
[types, equipmentTypes, itemFilter, contentFilter, addToDirectory]
|
|
202
209
|
);
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
210
|
+
const fetchNodeChildrenIfNeeded = useCallback(
|
|
211
|
+
(nodeId, delay = 0) => {
|
|
212
|
+
setTimeout(() => {
|
|
213
|
+
const node = nodeMap.current[nodeId];
|
|
214
|
+
if (node && (!node.children || node.children.length === 0) && node.type === ElementType.DIRECTORY) {
|
|
215
|
+
fetchDirectoryChildren(nodeId);
|
|
216
|
+
}
|
|
217
|
+
}, delay);
|
|
218
|
+
},
|
|
219
|
+
[fetchDirectoryChildren]
|
|
220
|
+
);
|
|
221
|
+
const handleSelectedExpansion = useCallback(async () => {
|
|
222
|
+
if (!selected || selected.length === 0) {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
const expandedArray = await getExpansionPathsForSelected(selected, expanded);
|
|
226
|
+
setAutoExpandedNodes(expandedArray);
|
|
227
|
+
fetchChildrenForExpandedNodes(expandedArray, fetchNodeChildrenIfNeeded);
|
|
228
|
+
return true;
|
|
229
|
+
}, [selected, expanded, fetchNodeChildrenIfNeeded]);
|
|
230
|
+
const handleProvidedExpansion = useCallback(() => {
|
|
231
|
+
if (!expanded || expanded.length === 0) {
|
|
232
|
+
return false;
|
|
214
233
|
}
|
|
215
|
-
|
|
234
|
+
setAutoExpandedNodes(expanded);
|
|
235
|
+
fetchChildrenForExpandedNodes(expanded, fetchNodeChildrenIfNeeded);
|
|
236
|
+
return true;
|
|
237
|
+
}, [expanded, fetchNodeChildrenIfNeeded]);
|
|
238
|
+
const handleLastSelectedExpansion = useCallback(async () => {
|
|
239
|
+
const expandPath = await initializeFromLastSelected();
|
|
240
|
+
if (!expandPath) {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
setAutoExpandedNodes(expandPath);
|
|
244
|
+
fetchChildrenForExpandedNodes(expandPath, fetchNodeChildrenIfNeeded);
|
|
245
|
+
return true;
|
|
246
|
+
}, [fetchNodeChildrenIfNeeded]);
|
|
247
|
+
const initializeExpansion = useCallback(async () => {
|
|
248
|
+
const selectedSuccess = await handleSelectedExpansion();
|
|
249
|
+
if (selectedSuccess) return;
|
|
250
|
+
const expandedSuccess = handleProvidedExpansion();
|
|
251
|
+
if (expandedSuccess) return;
|
|
252
|
+
await handleLastSelectedExpansion();
|
|
253
|
+
}, [handleSelectedExpansion, handleProvidedExpansion, handleLastSelectedExpansion]);
|
|
216
254
|
useEffect(() => {
|
|
217
|
-
if (open) {
|
|
255
|
+
if (!open) {
|
|
256
|
+
setIsRootsLoaded(false);
|
|
257
|
+
setAutoExpandedNodes([]);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (!isRootsLoaded) {
|
|
218
261
|
updateRootDirectories();
|
|
262
|
+
return;
|
|
219
263
|
}
|
|
220
|
-
|
|
264
|
+
initializeExpansion();
|
|
265
|
+
}, [open, isRootsLoaded, updateRootDirectories, initializeExpansion]);
|
|
266
|
+
const handleClose = useCallback(
|
|
267
|
+
(nodes) => {
|
|
268
|
+
if (nodes && nodes.length > 0) {
|
|
269
|
+
const lastSelectedNode = nodes[0];
|
|
270
|
+
saveLastSelectedDirectoryFromNode(lastSelectedNode);
|
|
271
|
+
}
|
|
272
|
+
setAutoExpandedNodes([]);
|
|
273
|
+
onClose(nodes);
|
|
274
|
+
},
|
|
275
|
+
[onClose]
|
|
276
|
+
);
|
|
221
277
|
return /* @__PURE__ */ jsx(
|
|
222
278
|
TreeViewFinder,
|
|
223
279
|
{
|
|
@@ -225,9 +281,10 @@ function DirectoryItemSelector({
|
|
|
225
281
|
sortMethod: sortHandlingDirectories,
|
|
226
282
|
multiSelect: true,
|
|
227
283
|
open,
|
|
228
|
-
expanded,
|
|
284
|
+
expanded: autoExpandedNodes,
|
|
229
285
|
onlyLeaves: true,
|
|
230
286
|
selected,
|
|
287
|
+
onClose: handleClose,
|
|
231
288
|
...otherTreeViewFinderProps,
|
|
232
289
|
data
|
|
233
290
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { UUID } from 'crypto';
|
|
2
|
+
import { ElementAttributes } from '../../utils';
|
|
3
|
+
/**
|
|
4
|
+
* Gets the last selected directory ID from localStorage with proper null handling
|
|
5
|
+
* @returns UUID or null if no valid directory ID is stored
|
|
6
|
+
*/
|
|
7
|
+
export declare function getLastSelectedDirectoryId(): UUID | null;
|
|
8
|
+
/**
|
|
9
|
+
* Clears the last selected directory from both localStorage and backend
|
|
10
|
+
*/
|
|
11
|
+
export declare function clearLastSelectedDirectory(): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Saves a directory ID as the last selected directory
|
|
14
|
+
* @param directoryId The directory UUID to save
|
|
15
|
+
*/
|
|
16
|
+
export declare function saveLastSelectedDirectory(directoryId: UUID): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Fetches directory path with error handling and validation
|
|
19
|
+
* @param directoryId The directory UUID to fetch path for
|
|
20
|
+
* @returns Promise resolving to path array or null if failed
|
|
21
|
+
*/
|
|
22
|
+
export declare function fetchDirectoryPathSafe(directoryId: UUID): Promise<ElementAttributes[] | null>;
|
|
23
|
+
/**
|
|
24
|
+
* Initializes directory expansion from last selected directory
|
|
25
|
+
* @returns Promise resolving to expansion path or null if failed
|
|
26
|
+
*/
|
|
27
|
+
export declare function initializeFromLastSelected(): Promise<UUID[] | null>;
|
|
28
|
+
/**
|
|
29
|
+
* Fetches expansion paths for multiple selected items
|
|
30
|
+
* @param selectedIds Array of selected item UUIDs
|
|
31
|
+
* @param expanded Optional existing expanded nodes
|
|
32
|
+
* @returns Promise resolving to combined expansion array
|
|
33
|
+
*/
|
|
34
|
+
export declare function getExpansionPathsForSelected(selectedIds: UUID[], expanded?: UUID[]): Promise<UUID[]>;
|
|
35
|
+
/**
|
|
36
|
+
* Saves the last selected directory from a TreeViewFinderNode
|
|
37
|
+
* @param node The selected node
|
|
38
|
+
*/
|
|
39
|
+
export declare function saveLastSelectedDirectoryFromNode(node: {
|
|
40
|
+
id: UUID;
|
|
41
|
+
type?: string;
|
|
42
|
+
parents?: Array<{
|
|
43
|
+
id: UUID;
|
|
44
|
+
}>;
|
|
45
|
+
}): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Fetches children for expanded nodes with staggered delay to avoid overwhelming the server
|
|
48
|
+
* @param expandedNodes Array of node UUIDs to fetch children for
|
|
49
|
+
* @param fetchChildrenCallback Function to fetch children for a single node
|
|
50
|
+
* @param delayBetweenRequests Delay in milliseconds between requests (default: 100ms)
|
|
51
|
+
*/
|
|
52
|
+
export declare function fetchChildrenForExpandedNodes(expandedNodes: UUID[], fetchChildrenCallback: (nodeId: UUID, delay: number) => void, delayBetweenRequests?: number): void;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { LAST_SELECTED_DIRECTORY } from "../../utils/constants/configConstants.js";
|
|
2
|
+
import "../../utils/conversionUtils.js";
|
|
3
|
+
import "react/jsx-runtime";
|
|
4
|
+
import "@mui/icons-material";
|
|
5
|
+
import { ElementType } from "../../utils/types/elementType.js";
|
|
6
|
+
import "../../utils/types/equipmentType.js";
|
|
7
|
+
import "../../utils/yupConfig.js";
|
|
8
|
+
import { updateConfigParameter, fetchDirectoryElementPath } from "../../services/directory.js";
|
|
9
|
+
function getLastSelectedDirectoryId() {
|
|
10
|
+
const lastSelectedDirId = localStorage.getItem(LAST_SELECTED_DIRECTORY);
|
|
11
|
+
if (!lastSelectedDirId || lastSelectedDirId === "null") {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
return lastSelectedDirId;
|
|
15
|
+
}
|
|
16
|
+
async function clearLastSelectedDirectory() {
|
|
17
|
+
localStorage.removeItem(LAST_SELECTED_DIRECTORY);
|
|
18
|
+
try {
|
|
19
|
+
await updateConfigParameter(LAST_SELECTED_DIRECTORY, "null");
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error("Failed to clear last selected directory:", error);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async function saveLastSelectedDirectory(directoryId) {
|
|
25
|
+
try {
|
|
26
|
+
await updateConfigParameter(LAST_SELECTED_DIRECTORY, directoryId);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error("Failed to save last selected directory:", error);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async function fetchDirectoryPathSafe(directoryId) {
|
|
32
|
+
try {
|
|
33
|
+
const path = await fetchDirectoryElementPath(directoryId);
|
|
34
|
+
if (!path || path.length === 0) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
return path;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.warn(`Failed to fetch directory path for ${directoryId}:`, error);
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async function initializeFromLastSelected() {
|
|
44
|
+
const lastSelectedDirId = getLastSelectedDirectoryId();
|
|
45
|
+
if (!lastSelectedDirId) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const path = await fetchDirectoryPathSafe(lastSelectedDirId);
|
|
49
|
+
if (!path) {
|
|
50
|
+
await clearLastSelectedDirectory();
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
return path.map((element) => element.elementUuid);
|
|
54
|
+
}
|
|
55
|
+
async function getExpansionPathsForSelected(selectedIds, expanded = []) {
|
|
56
|
+
const expandedSet = new Set(expanded);
|
|
57
|
+
const fetchPromises = selectedIds.map(async (selectedId) => {
|
|
58
|
+
const path = await fetchDirectoryPathSafe(selectedId);
|
|
59
|
+
if (path && path.length > 0) {
|
|
60
|
+
path.forEach((element, index) => {
|
|
61
|
+
if (index < path.length - 1) {
|
|
62
|
+
expandedSet.add(element.elementUuid);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
await Promise.all(fetchPromises);
|
|
68
|
+
return Array.from(expandedSet);
|
|
69
|
+
}
|
|
70
|
+
async function saveLastSelectedDirectoryFromNode(node) {
|
|
71
|
+
let lastSelectedDirId;
|
|
72
|
+
if (node.type === ElementType.DIRECTORY || node.type === void 0) {
|
|
73
|
+
lastSelectedDirId = node.id;
|
|
74
|
+
} else if (node.parents && node.parents.length > 0) {
|
|
75
|
+
lastSelectedDirId = node.parents[node.parents.length - 1].id;
|
|
76
|
+
}
|
|
77
|
+
if (lastSelectedDirId) {
|
|
78
|
+
await saveLastSelectedDirectory(lastSelectedDirId);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function fetchChildrenForExpandedNodes(expandedNodes, fetchChildrenCallback, delayBetweenRequests = 100) {
|
|
82
|
+
expandedNodes.forEach((nodeId, index) => {
|
|
83
|
+
fetchChildrenCallback(nodeId, index * delayBetweenRequests);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
export {
|
|
87
|
+
clearLastSelectedDirectory,
|
|
88
|
+
fetchChildrenForExpandedNodes,
|
|
89
|
+
fetchDirectoryPathSafe,
|
|
90
|
+
getExpansionPathsForSelected,
|
|
91
|
+
getLastSelectedDirectoryId,
|
|
92
|
+
initializeFromLastSelected,
|
|
93
|
+
saveLastSelectedDirectory,
|
|
94
|
+
saveLastSelectedDirectoryFromNode
|
|
95
|
+
};
|
|
@@ -14,14 +14,14 @@ import "@mui/icons-material";
|
|
|
14
14
|
import "yup";
|
|
15
15
|
import "../overflowableText/OverflowableText.js";
|
|
16
16
|
import "../treeViewFinder/TreeViewFinder.js";
|
|
17
|
+
import "../../utils/conversionUtils.js";
|
|
18
|
+
import "../../utils/yupConfig.js";
|
|
17
19
|
import "../inputs/reactHookForm/agGridTable/BottomRightButtons.js";
|
|
18
20
|
import "../customAGGrid/customAggrid.js";
|
|
19
21
|
import "ag-grid-community";
|
|
20
22
|
import "react-papaparse";
|
|
21
23
|
import "react-csv-downloader";
|
|
22
24
|
import "../inputs/reactHookForm/numbers/RangeInput.js";
|
|
23
|
-
import "../../utils/conversionUtils.js";
|
|
24
|
-
import "../../utils/yupConfig.js";
|
|
25
25
|
import "@react-querybuilder/material";
|
|
26
26
|
import "../filter/expert/expertFilterConstants.js";
|
|
27
27
|
import "../inputs/reactQueryBuilder/CustomReactQueryBuilder.js";
|
|
@@ -13,6 +13,9 @@ import "react-hook-form";
|
|
|
13
13
|
import "@mui/icons-material";
|
|
14
14
|
import "../treeViewFinder/TreeViewFinder.js";
|
|
15
15
|
import "notistack";
|
|
16
|
+
import "../../utils/conversionUtils.js";
|
|
17
|
+
import "../../utils/types/equipmentType.js";
|
|
18
|
+
import "../../utils/yupConfig.js";
|
|
16
19
|
function FilterForm({
|
|
17
20
|
sourceFilterForExplicitNamingConversion,
|
|
18
21
|
creation,
|
|
@@ -19,7 +19,10 @@ import "react-intl";
|
|
|
19
19
|
import "@mui/icons-material";
|
|
20
20
|
import "../../treeViewFinder/TreeViewFinder.js";
|
|
21
21
|
import "notistack";
|
|
22
|
+
import "../../../utils/conversionUtils.js";
|
|
23
|
+
import "../../../utils/types/equipmentType.js";
|
|
22
24
|
import { FieldType } from "../../../utils/types/fieldType.js";
|
|
25
|
+
import "../../../utils/yupConfig.js";
|
|
23
26
|
import { useFormatLabelWithUnit } from "../../../hooks/useFormatLabelWithUnit.js";
|
|
24
27
|
import { filterStyles } from "../HeaderFilterForm.js";
|
|
25
28
|
yup.setLocale({
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { SvgIcon } from "@mui/material";
|
|
3
|
+
import ArrowsOutput from "@material-symbols/svg-400/outlined/arrows_output.svg?react";
|
|
4
|
+
function ArrowsOutputIcon(props) {
|
|
5
|
+
return /* @__PURE__ */ jsx(SvgIcon, { component: ArrowsOutput, inheritViewBox: true, ...props });
|
|
6
|
+
}
|
|
7
|
+
export {
|
|
8
|
+
ArrowsOutputIcon
|
|
9
|
+
};
|
|
@@ -5,5 +5,6 @@
|
|
|
5
5
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
6
6
|
*/
|
|
7
7
|
export { LeftPanelOpenIcon } from './LeftPanelOpenIcon';
|
|
8
|
+
export { ArrowsOutputIcon } from './ArrowsOutputIcon';
|
|
8
9
|
export { LeftPanelCloseIcon } from './LeftPanelCloseIcon';
|
|
9
10
|
export { DeviceHubIcon } from './DeviceHubIcon';
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { LeftPanelOpenIcon } from "./LeftPanelOpenIcon.js";
|
|
2
|
+
import { ArrowsOutputIcon } from "./ArrowsOutputIcon.js";
|
|
2
3
|
import { LeftPanelCloseIcon } from "./LeftPanelCloseIcon.js";
|
|
3
4
|
import { DeviceHubIcon } from "./DeviceHubIcon.js";
|
|
4
5
|
export {
|
|
6
|
+
ArrowsOutputIcon,
|
|
5
7
|
DeviceHubIcon,
|
|
6
8
|
LeftPanelCloseIcon,
|
|
7
9
|
LeftPanelOpenIcon
|
package/dist/components/index.js
CHANGED
|
@@ -125,6 +125,7 @@ import { NotificationsContext } from "./notifications/contexts/NotificationsCont
|
|
|
125
125
|
import { useNotificationsListener } from "./notifications/hooks/useNotificationsListener.js";
|
|
126
126
|
import { useListenerManager } from "./notifications/hooks/useListenerManager.js";
|
|
127
127
|
import { LeftPanelOpenIcon } from "./icons/LeftPanelOpenIcon.js";
|
|
128
|
+
import { ArrowsOutputIcon } from "./icons/ArrowsOutputIcon.js";
|
|
128
129
|
import { LeftPanelCloseIcon } from "./icons/LeftPanelCloseIcon.js";
|
|
129
130
|
import { DeviceHubIcon } from "./icons/DeviceHubIcon.js";
|
|
130
131
|
import { ComputingType, formatComputingTypeLabel, isValidComputingType } from "./parameters/common/computing-type.js";
|
|
@@ -173,6 +174,7 @@ export {
|
|
|
173
174
|
AddButton,
|
|
174
175
|
AnnouncementBanner,
|
|
175
176
|
AnnouncementNotification,
|
|
177
|
+
ArrowsOutputIcon,
|
|
176
178
|
AuthenticationRouter,
|
|
177
179
|
default2 as AuthenticationRouterErrorDisplay,
|
|
178
180
|
AutocompleteInput,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AutocompleteProps, TextFieldProps } from '@mui/material';
|
|
2
|
-
import { Option } from '../../../../utils
|
|
2
|
+
import { Option } from '../../../../utils';
|
|
3
3
|
export interface AutocompleteInputProps extends Omit<AutocompleteProps<Option, boolean | undefined, boolean | undefined, boolean | undefined>, 'value' | 'onChange' | 'renderInput'> {
|
|
4
4
|
name: string;
|
|
5
5
|
options: Option[];
|
|
@@ -12,8 +12,9 @@ export interface AutocompleteInputProps extends Omit<AutocompleteProps<Option, b
|
|
|
12
12
|
onChangeCallback?: () => void;
|
|
13
13
|
formProps?: Omit<TextFieldProps, 'value' | 'onChange' | 'inputRef' | 'inputProps' | 'InputProps'>;
|
|
14
14
|
disabledTooltip?: boolean;
|
|
15
|
+
onCheckNewValue?: (value: Option | null) => boolean;
|
|
15
16
|
}
|
|
16
17
|
export declare function AutocompleteInput({ name, label, options, outputTransform, // transform materialUi input value before sending it to react hook form, mostly used to deal with select fields that need to return a string
|
|
17
18
|
inputTransform, // transform react hook form value before sending it to materialUi input, mostly used to deal with select fields that need to return a string
|
|
18
19
|
readOnly, previousValue, allowNewValue, onChangeCallback, // method called when input value is changing
|
|
19
|
-
formProps, disabledTooltip, ...props }: AutocompleteInputProps): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
formProps, disabledTooltip, onCheckNewValue, ...props }: AutocompleteInputProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,10 +2,13 @@ import { jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { useMemo } from "react";
|
|
3
3
|
import { Autocomplete, TextField } from "@mui/material";
|
|
4
4
|
import { useController } from "react-hook-form";
|
|
5
|
-
import
|
|
5
|
+
import "react-intl";
|
|
6
6
|
import { FieldLabel } from "../utils/FieldLabel.js";
|
|
7
|
-
import
|
|
7
|
+
import "@mui/icons-material";
|
|
8
|
+
import { identity, genHelperError, isFieldRequired } from "../utils/functions.js";
|
|
8
9
|
import { HelperPreviousValue } from "../utils/HelperPreviousValue.js";
|
|
10
|
+
import "../provider/CustomFormProvider.js";
|
|
11
|
+
import { useCustomFormContext } from "../provider/useCustomFormContext.js";
|
|
9
12
|
function AutocompleteInput({
|
|
10
13
|
name,
|
|
11
14
|
label,
|
|
@@ -21,6 +24,7 @@ function AutocompleteInput({
|
|
|
21
24
|
// method called when input value is changing
|
|
22
25
|
formProps,
|
|
23
26
|
disabledTooltip,
|
|
27
|
+
onCheckNewValue,
|
|
24
28
|
...props
|
|
25
29
|
}) {
|
|
26
30
|
const { validationSchema, getValues, removeOptional, isNodeBuilt, isUpdate } = useCustomFormContext();
|
|
@@ -33,6 +37,9 @@ function AutocompleteInput({
|
|
|
33
37
|
if ((currentValue == null ? void 0 : currentValue.id) === newValue) {
|
|
34
38
|
return;
|
|
35
39
|
}
|
|
40
|
+
if (!(onCheckNewValue == null ? void 0 : onCheckNewValue(newValue))) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
36
43
|
onChangeCallback == null ? void 0 : onChangeCallback();
|
|
37
44
|
if (!allowNewValue || typeof newValue !== "string") {
|
|
38
45
|
onChange(outputTransform(newValue));
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { AutocompleteInputProps } from '../autocompleteInputs
|
|
2
|
-
import { Option } from '../../../../utils
|
|
1
|
+
import { AutocompleteInputProps } from '../autocompleteInputs';
|
|
2
|
+
import { Option } from '../../../../utils';
|
|
3
3
|
export interface SelectInputProps extends Omit<AutocompleteInputProps, 'outputTransform' | 'inputTransform' | 'readOnly' | 'getOptionLabel'> {
|
|
4
4
|
options: Option[];
|
|
5
|
+
onCheckNewValue?: (value: Option | null) => boolean;
|
|
5
6
|
}
|
|
6
7
|
export declare function SelectInput(props: SelectInputProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useIntl } from "react-intl";
|
|
3
3
|
import { AutocompleteInput } from "../autocompleteInputs/AutocompleteInput.js";
|
|
4
|
+
import "react";
|
|
5
|
+
import "react-hook-form";
|
|
4
6
|
function SelectInput(props) {
|
|
5
7
|
const intl = useIntl();
|
|
6
8
|
const { options } = props;
|
|
@@ -15,6 +15,8 @@ import "@mui/icons-material";
|
|
|
15
15
|
import "yup";
|
|
16
16
|
import "../../overflowableText/OverflowableText.js";
|
|
17
17
|
import "../../treeViewFinder/TreeViewFinder.js";
|
|
18
|
+
import "../../../utils/conversionUtils.js";
|
|
19
|
+
import "../../../utils/yupConfig.js";
|
|
18
20
|
import "../../inputs/reactHookForm/agGridTable/BottomRightButtons.js";
|
|
19
21
|
import "../../customAGGrid/customAggrid.js";
|
|
20
22
|
import "ag-grid-community";
|
|
@@ -22,8 +24,6 @@ import "react-papaparse";
|
|
|
22
24
|
import "react-csv-downloader";
|
|
23
25
|
import "../../inputs/reactHookForm/numbers/RangeInput.js";
|
|
24
26
|
import { MuiSelectInput } from "../../inputs/reactHookForm/selectInputs/MuiSelectInput.js";
|
|
25
|
-
import "../../../utils/conversionUtils.js";
|
|
26
|
-
import "../../../utils/yupConfig.js";
|
|
27
27
|
import "@react-querybuilder/material";
|
|
28
28
|
import "../../filter/expert/expertFilterConstants.js";
|
|
29
29
|
import "../../inputs/reactQueryBuilder/CustomReactQueryBuilder.js";
|