ngssm-tree 22.0.1 → 22.2.0

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.
@@ -1,879 +1,1228 @@
1
- import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, Injectable, input, signal, effect, untracked, Component, viewChild, ViewContainerRef, ChangeDetectorRef, makeEnvironmentProviders } from '@angular/core';
3
- import { NgSsmFeatureState, Logger, Store, createSignal, provideReducers, provideEffects } from 'ngssm-store';
4
- import { DataStatus } from 'ngssm-remote-data';
5
- import { __decorate } from 'tslib';
6
- import update from 'immutability-helper';
7
- import * as i4$1 from '@angular/material/dialog';
8
- import { MatDialogModule, MatDialog } from '@angular/material/dialog';
9
- import { defaultRegexEditorValidator } from 'ngssm-toolkit';
10
- import * as i1 from '@angular/common';
11
- import { CommonModule } from '@angular/common';
12
- import * as i2 from '@angular/cdk/scrolling';
13
- import { ScrollingModule } from '@angular/cdk/scrolling';
14
- import * as i6 from '@angular/material/card';
15
- import { MatCardModule } from '@angular/material/card';
16
- import * as i4 from '@angular/material/icon';
17
- import { MatIconModule } from '@angular/material/icon';
18
- import * as i5 from '@angular/material/progress-spinner';
19
- import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
20
- import * as i2$1 from '@angular/material/button';
21
- import { MatButtonModule } from '@angular/material/button';
22
- import * as i1$1 from '@angular/forms';
23
- import { FormControl, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
24
- import * as i2$2 from '@angular/material/form-field';
25
- import { MatFormFieldModule } from '@angular/material/form-field';
26
- import * as i3 from '@angular/material/input';
27
- import { MatInputModule } from '@angular/material/input';
28
-
1
+ import * as i0 from "@angular/core";
2
+ import { ChangeDetectorRef, Component, Injectable, InjectionToken, ViewContainerRef, effect, inject, input, makeEnvironmentProviders, signal, untracked, viewChild } from "@angular/core";
3
+ import { Logger, NgSsmFeatureState, Store, createSignal, provideEffects, provideReducers } from "ngssm-store";
4
+ import { DataStatus } from "ngssm-remote-data";
5
+ import { __decorate } from "tslib";
6
+ import update from "immutability-helper";
7
+ import * as i4 from "@angular/material/dialog";
8
+ import { MatDialog, MatDialogModule } from "@angular/material/dialog";
9
+ import { defaultRegexEditorValidator } from "ngssm-toolkit";
10
+ import * as i1$1 from "@angular/common";
11
+ import { CommonModule } from "@angular/common";
12
+ import * as i2$2 from "@angular/cdk/scrolling";
13
+ import { ScrollingModule } from "@angular/cdk/scrolling";
14
+ import * as i3$1 from "@angular/material/card";
15
+ import { MatCardModule } from "@angular/material/card";
16
+ import * as i4$1 from "@angular/material/icon";
17
+ import { MatIconModule } from "@angular/material/icon";
18
+ import * as i5 from "@angular/material/progress-spinner";
19
+ import { MatProgressSpinnerModule } from "@angular/material/progress-spinner";
20
+ import * as i2$1 from "@angular/material/button";
21
+ import { MatButtonModule } from "@angular/material/button";
22
+ import * as i1 from "@angular/forms";
23
+ import { FormControl, FormsModule, ReactiveFormsModule, Validators } from "@angular/forms";
24
+ import * as i2 from "@angular/material/form-field";
25
+ import { MatFormFieldModule } from "@angular/material/form-field";
26
+ import * as i3 from "@angular/material/input";
27
+ import { MatInputModule } from "@angular/material/input";
29
28
  var NgssmTreeActionType;
30
- (function (NgssmTreeActionType) {
31
- NgssmTreeActionType["initNgssmTree"] = "[NgssmTreeActionType] initNgssmTree";
32
- NgssmTreeActionType["deleteNgssmTree"] = "[NgssmTreeActionType] deleteNgssmTree";
33
- NgssmTreeActionType["expandNode"] = "[NgssmTreeActionType] expandNode";
34
- NgssmTreeActionType["collapseNode"] = "[NgssmTreeActionType] collapseNode";
35
- NgssmTreeActionType["registerNodes"] = "[NgssmTreeActionType] registerNodes";
36
- NgssmTreeActionType["selectNode"] = "[NgssmTreeActionType] selectNode";
37
- NgssmTreeActionType["loadChildrenOfNode"] = "[NgssmTreeActionType] loadChildrenOfNode";
38
- NgssmTreeActionType["displaySearchDialog"] = "[NgssmTreeActionType] displaySearchDialog";
39
- NgssmTreeActionType["closeSearchDialog"] = "[NgssmTreeActionType] closeSearchDialog";
40
- NgssmTreeActionType["searchTreeNodes"] = "[NgssmTreeActionType] searchTreeNodes";
41
- NgssmTreeActionType["registerPartialSearchResults"] = "[NgssmTreeActionType] registerPartialSearchResults";
42
- NgssmTreeActionType["abortTreeNodesSearch"] = "[NgssmTreeActionType] abortTreeNodesSearch";
29
+ (function(NgssmTreeActionType) {
30
+ NgssmTreeActionType["initNgssmTree"] = "[NgssmTreeActionType] initNgssmTree";
31
+ NgssmTreeActionType["deleteNgssmTree"] = "[NgssmTreeActionType] deleteNgssmTree";
32
+ NgssmTreeActionType["expandNode"] = "[NgssmTreeActionType] expandNode";
33
+ NgssmTreeActionType["collapseNode"] = "[NgssmTreeActionType] collapseNode";
34
+ NgssmTreeActionType["registerNodes"] = "[NgssmTreeActionType] registerNodes";
35
+ NgssmTreeActionType["selectNode"] = "[NgssmTreeActionType] selectNode";
36
+ NgssmTreeActionType["loadChildrenOfNode"] = "[NgssmTreeActionType] loadChildrenOfNode";
37
+ NgssmTreeActionType["displaySearchDialog"] = "[NgssmTreeActionType] displaySearchDialog";
38
+ NgssmTreeActionType["closeSearchDialog"] = "[NgssmTreeActionType] closeSearchDialog";
39
+ NgssmTreeActionType["searchTreeNodes"] = "[NgssmTreeActionType] searchTreeNodes";
40
+ NgssmTreeActionType["registerPartialSearchResults"] = "[NgssmTreeActionType] registerPartialSearchResults";
41
+ NgssmTreeActionType["abortTreeNodesSearch"] = "[NgssmTreeActionType] abortTreeNodesSearch";
43
42
  })(NgssmTreeActionType || (NgssmTreeActionType = {}));
44
-
45
- class TreeAction {
46
- type;
47
- treeId;
48
- constructor(type, treeId) {
49
- this.type = type;
50
- this.treeId = treeId;
51
- }
52
- }
53
-
54
- class InitNgssmTreeAction extends TreeAction {
55
- treeType;
56
- root;
57
- constructor(treeId, treeType, root) {
58
- super(NgssmTreeActionType.initNgssmTree, treeId);
59
- this.treeType = treeType;
60
- this.root = root;
61
- }
62
- }
63
-
64
- class TreeNodeAction extends TreeAction {
65
- nodeId;
66
- constructor(actionType, treeId, nodeId) {
67
- super(actionType, treeId);
68
- this.nodeId = nodeId;
69
- }
70
- }
71
-
72
- class ExpandNodeAction extends TreeNodeAction {
73
- constructor(treeId, nodeId) {
74
- super(NgssmTreeActionType.expandNode, treeId, nodeId);
75
- }
76
- }
77
-
78
- class RegisterNodesAction {
79
- dataStatus;
80
- treeId;
81
- parentNodeId;
82
- nodes;
83
- type = NgssmTreeActionType.registerNodes;
84
- constructor(dataStatus, treeId, parentNodeId, nodes = []) {
85
- this.dataStatus = dataStatus;
86
- this.treeId = treeId;
87
- this.parentNodeId = parentNodeId;
88
- this.nodes = nodes;
89
- }
90
- }
91
-
92
- class CollapseNodeAction extends TreeAction {
93
- nodeId;
94
- constructor(treeId, nodeId) {
95
- super(NgssmTreeActionType.collapseNode, treeId);
96
- this.nodeId = nodeId;
97
- }
98
- }
99
-
100
- class SelectNodeAction extends TreeNodeAction {
101
- constructor(treeId, nodeId) {
102
- super(NgssmTreeActionType.selectNode, treeId, nodeId);
103
- }
104
- }
105
-
106
- class DeleteNgssmTreeAction extends TreeAction {
107
- constructor(treeId) {
108
- super(NgssmTreeActionType.deleteNgssmTree, treeId);
109
- }
110
- }
111
-
112
- class DisplaySearchDialogAction extends TreeAction {
113
- startNodeId;
114
- constructor(treeId, startNodeId) {
115
- super(NgssmTreeActionType.displaySearchDialog, treeId);
116
- this.startNodeId = startNodeId;
117
- }
118
- }
119
-
120
- class SearchTreeNodesAction {
121
- searchPattern;
122
- type = NgssmTreeActionType.searchTreeNodes;
123
- constructor(searchPattern) {
124
- this.searchPattern = searchPattern;
125
- }
126
- }
127
-
128
- class RegisterPartialSearchResultsAction {
129
- matchingNodes;
130
- nodesToProcess;
131
- type = NgssmTreeActionType.registerPartialSearchResults;
132
- constructor(matchingNodes, nodesToProcess) {
133
- this.matchingNodes = matchingNodes;
134
- this.nodesToProcess = nodesToProcess;
135
- }
136
- }
137
-
138
- class LoadChildrenOfNodeAction extends TreeNodeAction {
139
- constructor(treeId, nodeId) {
140
- super(NgssmTreeActionType.loadChildrenOfNode, treeId, nodeId);
141
- }
142
- }
143
-
43
+ var TreeAction = class {
44
+ type;
45
+ treeId;
46
+ constructor(type, treeId) {
47
+ this.type = type;
48
+ this.treeId = treeId;
49
+ }
50
+ };
51
+ var InitNgssmTreeAction = class extends TreeAction {
52
+ treeType;
53
+ root;
54
+ constructor(treeId, treeType, root) {
55
+ super(NgssmTreeActionType.initNgssmTree, treeId);
56
+ this.treeType = treeType;
57
+ this.root = root;
58
+ }
59
+ };
60
+ var TreeNodeAction = class extends TreeAction {
61
+ nodeId;
62
+ constructor(actionType, treeId, nodeId) {
63
+ super(actionType, treeId);
64
+ this.nodeId = nodeId;
65
+ }
66
+ };
67
+ var ExpandNodeAction = class extends TreeNodeAction {
68
+ constructor(treeId, nodeId) {
69
+ super(NgssmTreeActionType.expandNode, treeId, nodeId);
70
+ }
71
+ };
72
+ var RegisterNodesAction = class {
73
+ dataStatus;
74
+ treeId;
75
+ parentNodeId;
76
+ nodes;
77
+ type = NgssmTreeActionType.registerNodes;
78
+ constructor(dataStatus, treeId, parentNodeId, nodes = []) {
79
+ this.dataStatus = dataStatus;
80
+ this.treeId = treeId;
81
+ this.parentNodeId = parentNodeId;
82
+ this.nodes = nodes;
83
+ }
84
+ };
85
+ var CollapseNodeAction = class extends TreeAction {
86
+ nodeId;
87
+ constructor(treeId, nodeId) {
88
+ super(NgssmTreeActionType.collapseNode, treeId);
89
+ this.nodeId = nodeId;
90
+ }
91
+ };
92
+ var SelectNodeAction = class extends TreeNodeAction {
93
+ constructor(treeId, nodeId) {
94
+ super(NgssmTreeActionType.selectNode, treeId, nodeId);
95
+ }
96
+ };
97
+ var DeleteNgssmTreeAction = class extends TreeAction {
98
+ constructor(treeId) {
99
+ super(NgssmTreeActionType.deleteNgssmTree, treeId);
100
+ }
101
+ };
102
+ var DisplaySearchDialogAction = class extends TreeAction {
103
+ startNodeId;
104
+ constructor(treeId, startNodeId) {
105
+ super(NgssmTreeActionType.displaySearchDialog, treeId);
106
+ this.startNodeId = startNodeId;
107
+ }
108
+ };
109
+ var SearchTreeNodesAction = class {
110
+ searchPattern;
111
+ type = NgssmTreeActionType.searchTreeNodes;
112
+ constructor(searchPattern) {
113
+ this.searchPattern = searchPattern;
114
+ }
115
+ };
116
+ var RegisterPartialSearchResultsAction = class {
117
+ matchingNodes;
118
+ nodesToProcess;
119
+ type = NgssmTreeActionType.registerPartialSearchResults;
120
+ constructor(matchingNodes, nodesToProcess) {
121
+ this.matchingNodes = matchingNodes;
122
+ this.nodesToProcess = nodesToProcess;
123
+ }
124
+ };
125
+ var LoadChildrenOfNodeAction = class extends TreeNodeAction {
126
+ constructor(treeId, nodeId) {
127
+ super(NgssmTreeActionType.loadChildrenOfNode, treeId, nodeId);
128
+ }
129
+ };
144
130
  const getNgssmTreeNodeFullPath = (node) => {
145
- if (node.parentFullPath) {
146
- return `${node.parentFullPath}/${node.node.label}`;
147
- }
148
- return node.node.label;
131
+ if (node.parentFullPath) return `${node.parentFullPath}/${node.node.label}`;
132
+ return node.node.label;
149
133
  };
150
-
151
- const NGSSM_TREE_DATA_SERVICE = new InjectionToken('NGSSM_TREE_DATA_SERVICE');
152
-
134
+ const NGSSM_TREE_DATA_SERVICE = new InjectionToken("NGSSM_TREE_DATA_SERVICE");
153
135
  const getNgssmTreePath = (tree, nodeId) => {
154
- const nodesPerId = new Map(tree.nodes.map((n) => [n.node.nodeId, n]));
155
- const path = [];
156
- let node = nodesPerId.get(nodeId);
157
- while (node) {
158
- path.unshift(node);
159
- node = node.node.parentNodeId ? nodesPerId.get(node.node.parentNodeId) : undefined;
160
- }
161
- if (path.length === 0 && tree.nodes.length > 0) {
162
- path.push(tree.nodes[0]);
163
- }
164
- return path;
136
+ const nodesPerId = new Map(tree.nodes.map((n) => [n.node.nodeId, n]));
137
+ const path = [];
138
+ let node = nodesPerId.get(nodeId);
139
+ while (node) {
140
+ path.unshift(node);
141
+ node = node.node.parentNodeId ? nodesPerId.get(node.node.parentNodeId) : void 0;
142
+ }
143
+ if (path.length === 0 && tree.nodes.length > 0) path.push(tree.nodes[0]);
144
+ return path;
165
145
  };
166
-
167
146
  var SearchStatus;
168
- (function (SearchStatus) {
169
- SearchStatus["none"] = "None";
170
- SearchStatus["inProgress"] = "In progress";
171
- SearchStatus["done"] = "Done";
172
- SearchStatus["aborted"] = "Aborted";
147
+ (function(SearchStatus) {
148
+ SearchStatus["none"] = "None";
149
+ SearchStatus["inProgress"] = "In progress";
150
+ SearchStatus["done"] = "Done";
151
+ SearchStatus["aborted"] = "Aborted";
173
152
  })(SearchStatus || (SearchStatus = {}));
174
-
175
153
  const getDefaultTreeNodesSearch = () => ({
176
- searchStatus: SearchStatus.none,
177
- toProcess: [],
178
- matchingNodes: []
154
+ searchStatus: SearchStatus.none,
155
+ toProcess: [],
156
+ matchingNodes: []
179
157
  });
180
-
181
158
  const selectNgssmTreeState = (state) => state[NgssmTreeStateSpecification.featureStateKey];
182
- const updateNgssmTreeState = (state, command) => update(state, {
183
- [NgssmTreeStateSpecification.featureStateKey]: command
184
- });
159
+ const updateNgssmTreeState = (state, command) => update(state, { [NgssmTreeStateSpecification.featureStateKey]: command });
185
160
  let NgssmTreeStateSpecification = class NgssmTreeStateSpecification {
186
- static featureStateKey = 'ngssm-tree-state';
187
- static initialState = {
188
- trees: {},
189
- treeNodesSearch: getDefaultTreeNodesSearch()
190
- };
161
+ static featureStateKey = "ngssm-tree-state";
162
+ static initialState = {
163
+ trees: {},
164
+ treeNodesSearch: getDefaultTreeNodesSearch()
165
+ };
191
166
  };
192
- NgssmTreeStateSpecification = __decorate([
193
- NgSsmFeatureState({
194
- featureStateKey: NgssmTreeStateSpecification.featureStateKey,
195
- initialState: NgssmTreeStateSpecification.initialState
196
- })
197
- ], NgssmTreeStateSpecification);
198
-
167
+ NgssmTreeStateSpecification = __decorate([NgSsmFeatureState({
168
+ featureStateKey: NgssmTreeStateSpecification.featureStateKey,
169
+ initialState: NgssmTreeStateSpecification.initialState
170
+ })], NgssmTreeStateSpecification);
199
171
  const selectNgssmTreeNode = (state, treeId, nodeId) => selectNgssmTreeState(state).trees[treeId]?.nodes.find((n) => n.node.nodeId === nodeId);
200
172
  const selectNgssmTreeNodeChildren = (state, treeId, nodeId) => selectNgssmTreeState(state).trees[treeId]?.nodes.filter((n) => n.node.parentNodeId === nodeId) ?? [];
201
-
202
- class TreeNodeLoadingEffect {
203
- processedActions = [
204
- NgssmTreeActionType.expandNode,
205
- NgssmTreeActionType.selectNode,
206
- NgssmTreeActionType.loadChildrenOfNode
207
- ];
208
- dataServices = inject(NGSSM_TREE_DATA_SERVICE, { optional: true }) ?? [];
209
- logger = inject(Logger);
210
- processAction(actiondispatcher, state, action) {
211
- const treeNodeAction = action;
212
- if (!selectNgssmTreeState(state).trees[treeNodeAction.treeId]) {
213
- this.logger.error(`Trying to process action for tree not initialized: ${treeNodeAction.treeId}.`);
214
- return;
215
- }
216
- const treeType = selectNgssmTreeState(state).trees[treeNodeAction.treeId].type;
217
- const dataService = (this.dataServices ?? []).find((d) => d.treeType === treeType);
218
- if (!dataService) {
219
- this.logger.error(`Trying to process action for tree with no data service: ${treeNodeAction.treeId} / ${treeType}.`);
220
- return;
221
- }
222
- const node = selectNgssmTreeState(state).trees[treeNodeAction.treeId].nodes.find((n) => n.node.nodeId === treeNodeAction.nodeId);
223
- if (node?.status !== DataStatus.loading) {
224
- return;
225
- }
226
- dataService.load(treeNodeAction.treeId, treeNodeAction.nodeId).subscribe({
227
- next: (value) => actiondispatcher.dispatchAction(new RegisterNodesAction(DataStatus.loaded, treeNodeAction.treeId, treeNodeAction.nodeId, value)),
228
- error: (error) => {
229
- this.logger.error(`Unable to load children nodes for tree '${treeNodeAction.treeId}' and node '${treeNodeAction.nodeId}'`, error);
230
- actiondispatcher.dispatchAction(new RegisterNodesAction(DataStatus.error, treeNodeAction.treeId, treeNodeAction.nodeId));
231
- }
232
- });
233
- }
234
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreeNodeLoadingEffect, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
235
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreeNodeLoadingEffect });
236
- }
237
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreeNodeLoadingEffect, decorators: [{
238
- type: Injectable
239
- }] });
240
-
241
- class NgssmTreeComponent {
242
- treeConfig = input(/* @ts-ignore */
243
- ...(ngDevMode ? [undefined, { debugName: "treeConfig" }] : /* istanbul ignore next */ []));
244
- dataStatus = DataStatus;
245
- displayedItems = signal([], /* @ts-ignore */
246
- ...(ngDevMode ? [{ debugName: "displayedItems" }] : /* istanbul ignore next */ []));
247
- selectedNodeId = signal(undefined, /* @ts-ignore */
248
- ...(ngDevMode ? [{ debugName: "selectedNodeId" }] : /* istanbul ignore next */ []));
249
- store = inject(Store);
250
- trees = createSignal((state) => selectNgssmTreeState(state).trees);
251
- tree = signal(undefined, /* @ts-ignore */
252
- ...(ngDevMode ? [{ debugName: "tree" }] : /* istanbul ignore next */ []));
253
- constructor() {
254
- effect(() => {
255
- const currentConfig = this.treeConfig();
256
- const currentTrees = this.trees();
257
- if (currentConfig) {
258
- this.tree.set(currentTrees[currentConfig.treeId]);
259
- }
260
- else {
261
- this.tree.set(undefined);
262
- }
263
- });
264
- effect(() => {
265
- const currentTree = this.tree();
266
- const config = untracked(() => this.treeConfig());
267
- if (!currentTree || !config) {
268
- this.displayedItems.set([]);
269
- return;
270
- }
271
- const alwaysTrue = () => true;
272
- const filter = config.filter ?? alwaysTrue;
273
- const canSearch = config.canSearch ?? alwaysTrue;
274
- const items = [];
275
- let hiddenLevel = -1;
276
- const nodesToFindSelected = new Map();
277
- (currentTree.nodes ?? []).forEach((t) => {
278
- if (t.node.isExpandable && t.isExpanded === false && hiddenLevel === -1) {
279
- hiddenLevel = t.level;
280
- }
281
- if (hiddenLevel === -1 || t.level <= hiddenLevel) {
282
- if (filter(t.node)) {
283
- items.push({
284
- node: t,
285
- canSearch: canSearch(t.node)
286
- });
287
- nodesToFindSelected.set(t.node.nodeId, { isDisplayed: true, node: t });
288
- }
289
- }
290
- if (t.node.isExpandable && t.level <= hiddenLevel) {
291
- hiddenLevel = t.isExpanded === true ? -1 : t.level;
292
- }
293
- if (!nodesToFindSelected.has(t.node.nodeId)) {
294
- nodesToFindSelected.set(t.node.nodeId, { isDisplayed: false, node: t });
295
- }
296
- });
297
- this.displayedItems.set(items);
298
- let selectedNode = currentTree.selectedNode;
299
- if (!selectedNode) {
300
- this.selectedNodeId.set(undefined);
301
- }
302
- else {
303
- while (selectedNode) {
304
- const item = nodesToFindSelected.get(selectedNode);
305
- if (item?.isDisplayed !== true) {
306
- selectedNode = item?.node.node.parentNodeId;
307
- }
308
- else {
309
- break;
310
- }
311
- }
312
- this.selectedNodeId.set(selectedNode);
313
- }
314
- });
315
- }
316
- getItemId(_, node) {
317
- return node.node.node.nodeId;
318
- }
319
- expand(node) {
320
- const treeId = this.treeConfig()?.treeId;
321
- if (treeId) {
322
- this.store.dispatchAction(new ExpandNodeAction(treeId, node.node.nodeId));
323
- }
324
- }
325
- collapse(node) {
326
- const treeId = this.treeConfig()?.treeId;
327
- if (treeId) {
328
- this.store.dispatchAction(new CollapseNodeAction(treeId, node.node.nodeId));
329
- }
330
- }
331
- selectNode(node) {
332
- const treeId = this.treeConfig()?.treeId;
333
- if (treeId) {
334
- this.store.dispatchAction(new SelectNodeAction(treeId, node.node.nodeId));
335
- }
336
- }
337
- displaySearchDialog(node) {
338
- const treeId = this.treeConfig()?.treeId;
339
- if (treeId) {
340
- this.store.dispatchAction(new DisplaySearchDialogAction(treeId, node.node.nodeId));
341
- }
342
- }
343
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgssmTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
344
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: NgssmTreeComponent, isStandalone: true, selector: "ngssm-tree", inputs: { treeConfig: { classPropertyName: "treeConfig", publicName: "treeConfig", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<mat-card class=\"flex-column-stretch fxFlex\">\n @if (treeConfig(); as config) {\n <mat-card-content class=\"flex-column-stretch fxFlex\">\n <cdk-virtual-scroll-viewport itemSize=\"30\" class=\"fxFlex\">\n <div\n *cdkVirtualFor=\"let item of displayedItems(); trackBy: getItemId\"\n class=\"ngssm-tree-node\"\n [style.padding-left.px]=\"item.node.level * 20\"\n (click)=\"selectNode(item.node)\"\n aria-hidden=\"true\"\n (keyup.enter)=\"selectNode(item.node)\"\n [ngClass]=\"{ selected: selectedNodeId() === item.node.node.nodeId }\">\n @if (item.node.node.isExpandable) {\n @if (item.node.status === dataStatus.loading) {\n <mat-spinner diameter=\"20\"></mat-spinner>\n } @else {\n @if (item.node.isExpanded) {\n <mat-icon class=\"fa-solid fa-chevron-down\" (click)=\"$event.stopPropagation(); collapse(item.node)\"></mat-icon>\n } @else {\n <mat-icon class=\"fa-solid fa-chevron-right\" (click)=\"$event.stopPropagation(); expand(item.node)\"></mat-icon>\n }\n }\n } @else {\n <span class=\"not-expandable-padding\"></span>\n }\n\n <mat-icon class=\"{{ config.iconClasses[item.node.node.type] }}\" color=\"primary\"></mat-icon>\n\n <span class=\"ngssm-tree-node-label\">\n {{ item.node.node.label }}\n </span>\n <span class=\"fxFlex\"></span>\n @if (item.canSearch) {\n <i class=\"fa-solid fa-magnifying-glass search-icon\" (click)=\"$event.stopPropagation(); displaySearchDialog(item.node)\"> </i>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n </mat-card-content>\n }\n</mat-card>\n", styles: [":host{display:flex;flex-direction:column}:host .ngssm-tree-node{height:30px;display:flex;flex-direction:row;align-items:center;padding-right:12px}:host .ngssm-tree-node .fa-folder{margin-right:4px}:host .ngssm-tree-node .fa-chevron-right:hover{cursor:pointer}:host .ngssm-tree-node.selected{background-color:#e4e6f1}:host .ngssm-tree-node:hover{cursor:pointer}:host .ngssm-tree-node:hover .search-icon{display:unset}:host .ngssm-tree-node:hover:not(.selected){background-color:#f3f3f3}:host .not-expandable-padding{width:24px}:host .search-icon{font-size:12px;display:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i2.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i2.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i2.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i6.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i6.MatCardContent, selector: "mat-card-content" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i5.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }] });
345
- }
346
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgssmTreeComponent, decorators: [{
347
- type: Component,
348
- args: [{ selector: 'ngssm-tree', imports: [CommonModule, ScrollingModule, MatCardModule, MatIconModule, MatProgressSpinnerModule], template: "<mat-card class=\"flex-column-stretch fxFlex\">\n @if (treeConfig(); as config) {\n <mat-card-content class=\"flex-column-stretch fxFlex\">\n <cdk-virtual-scroll-viewport itemSize=\"30\" class=\"fxFlex\">\n <div\n *cdkVirtualFor=\"let item of displayedItems(); trackBy: getItemId\"\n class=\"ngssm-tree-node\"\n [style.padding-left.px]=\"item.node.level * 20\"\n (click)=\"selectNode(item.node)\"\n aria-hidden=\"true\"\n (keyup.enter)=\"selectNode(item.node)\"\n [ngClass]=\"{ selected: selectedNodeId() === item.node.node.nodeId }\">\n @if (item.node.node.isExpandable) {\n @if (item.node.status === dataStatus.loading) {\n <mat-spinner diameter=\"20\"></mat-spinner>\n } @else {\n @if (item.node.isExpanded) {\n <mat-icon class=\"fa-solid fa-chevron-down\" (click)=\"$event.stopPropagation(); collapse(item.node)\"></mat-icon>\n } @else {\n <mat-icon class=\"fa-solid fa-chevron-right\" (click)=\"$event.stopPropagation(); expand(item.node)\"></mat-icon>\n }\n }\n } @else {\n <span class=\"not-expandable-padding\"></span>\n }\n\n <mat-icon class=\"{{ config.iconClasses[item.node.node.type] }}\" color=\"primary\"></mat-icon>\n\n <span class=\"ngssm-tree-node-label\">\n {{ item.node.node.label }}\n </span>\n <span class=\"fxFlex\"></span>\n @if (item.canSearch) {\n <i class=\"fa-solid fa-magnifying-glass search-icon\" (click)=\"$event.stopPropagation(); displaySearchDialog(item.node)\"> </i>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n </mat-card-content>\n }\n</mat-card>\n", styles: [":host{display:flex;flex-direction:column}:host .ngssm-tree-node{height:30px;display:flex;flex-direction:row;align-items:center;padding-right:12px}:host .ngssm-tree-node .fa-folder{margin-right:4px}:host .ngssm-tree-node .fa-chevron-right:hover{cursor:pointer}:host .ngssm-tree-node.selected{background-color:#e4e6f1}:host .ngssm-tree-node:hover{cursor:pointer}:host .ngssm-tree-node:hover .search-icon{display:unset}:host .ngssm-tree-node:hover:not(.selected){background-color:#f3f3f3}:host .not-expandable-padding{width:24px}:host .search-icon{font-size:12px;display:none}\n"] }]
349
- }], ctorParameters: () => [], propDecorators: { treeConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "treeConfig", required: false }] }] } });
350
-
351
- class NgssmBreadcrumbComponent {
352
- treeId = input(undefined, /* @ts-ignore */
353
- ...(ngDevMode ? [{ debugName: "treeId" }] : /* istanbul ignore next */ []));
354
- nodes = signal([], /* @ts-ignore */
355
- ...(ngDevMode ? [{ debugName: "nodes" }] : /* istanbul ignore next */ []));
356
- store = inject(Store);
357
- treeState = createSignal((state) => selectNgssmTreeState(state));
358
- constructor() {
359
- effect(() => {
360
- const currentTreeId = this.treeId();
361
- if (!currentTreeId) {
362
- this.nodes.set([]);
363
- return;
364
- }
365
- const state = this.treeState();
366
- const tree = state?.trees[currentTreeId];
367
- if (!tree) {
368
- this.nodes.set([]);
369
- return;
370
- }
371
- const nodesPerId = new Map(tree.nodes.map((n) => [n.node.nodeId, n.node]));
372
- const path = [];
373
- let node = tree.selectedNode ? nodesPerId.get(tree.selectedNode) : undefined;
374
- while (node) {
375
- path.unshift(node);
376
- node = node.parentNodeId ? nodesPerId.get(node.parentNodeId) : undefined;
377
- }
378
- if (path.length === 0 && tree.nodes.length > 0) {
379
- path.push(tree.nodes[0]?.node);
380
- }
381
- this.nodes.set(path);
382
- });
383
- }
384
- selectNode(node) {
385
- const treeId = this.treeId();
386
- if (treeId) {
387
- this.store.dispatchAction(new SelectNodeAction(treeId, node.nodeId));
388
- }
389
- }
390
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgssmBreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
391
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: NgssmBreadcrumbComponent, isStandalone: true, selector: "ngssm-breadcrumb", inputs: { treeId: { classPropertyName: "treeId", publicName: "treeId", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"flex-row-center\">\n <mat-icon class=\"fa-solid fa-folder-tree\" color=\"primary\"></mat-icon>\n @for (node of nodes(); track node; let last = $last) {\n <span class=\"flex-row-center\">\n <button mat-button [disabled]=\"last\" (click)=\"selectNode(node)\">\n {{ node.label }}\n </button>\n\n @if (!last) {\n <div class=\"ngssm-breadcrumb-separator\">/</div>\n }\n </span>\n }\n</div>\n", styles: [".ngssm-breadcrumb-separator{font-weight:700}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }] });
392
- }
393
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgssmBreadcrumbComponent, decorators: [{
394
- type: Component,
395
- args: [{ selector: 'ngssm-breadcrumb', imports: [MatIconModule, MatButtonModule], template: "<div class=\"flex-row-center\">\n <mat-icon class=\"fa-solid fa-folder-tree\" color=\"primary\"></mat-icon>\n @for (node of nodes(); track node; let last = $last) {\n <span class=\"flex-row-center\">\n <button mat-button [disabled]=\"last\" (click)=\"selectNode(node)\">\n {{ node.label }}\n </button>\n\n @if (!last) {\n <div class=\"ngssm-breadcrumb-separator\">/</div>\n }\n </span>\n }\n</div>\n", styles: [".ngssm-breadcrumb-separator{font-weight:700}\n"] }]
396
- }], ctorParameters: () => [], propDecorators: { treeId: [{ type: i0.Input, args: [{ isSignal: true, alias: "treeId", required: false }] }] } });
397
-
398
- class NgssmTreeSearchDialogComponent {
399
- resultsViewerContainer = viewChild('resultsViewerContainer', { ...(ngDevMode ? { debugName: "resultsViewerContainer" } : /* istanbul ignore next */ {}), read: ViewContainerRef });
400
- searchStatus = SearchStatus;
401
- searchRootPath = createSignal((state) => selectNgssmTreeState(state).treeNodesSearch.rootSearchPath ?? '');
402
- currentSearchedPath = createSignal((state) => selectNgssmTreeState(state).treeNodesSearch.toProcess[0]?.fullPath ?? '');
403
- currentSearchStatus = createSignal((state) => selectNgssmTreeState(state).treeNodesSearch.searchStatus);
404
- searchPatternControl = new FormControl(undefined, [
405
- Validators.required,
406
- (c) => this.validatedRegex(c)
407
- ]);
408
- store = inject(Store);
409
- changeDetectorRef = inject(ChangeDetectorRef);
410
- dataServices = inject(NGSSM_TREE_DATA_SERVICE, {
411
- optional: true
412
- });
413
- constructor() {
414
- const effectRef = effect(() => {
415
- const container = this.resultsViewerContainer();
416
- if (!container) {
417
- return;
418
- }
419
- const treeState = selectNgssmTreeState(this.store.state());
420
- const treeId = treeState.treeNodesSearch.treeId;
421
- if (!treeId) {
422
- return;
423
- }
424
- const treeType = treeState.trees[treeId]?.type;
425
- if (!treeType) {
426
- return;
427
- }
428
- const dataService = this.dataServices.find((d) => d.treeType === treeType);
429
- if (!dataService?.searchResultViewer) {
430
- return;
431
- }
432
- this.resultsViewerContainer()?.createComponent(dataService.searchResultViewer);
433
- this.changeDetectorRef.markForCheck();
434
- effectRef.destroy();
435
- }, /* @ts-ignore */
436
- ...(ngDevMode ? [{ debugName: "effectRef" }] : /* istanbul ignore next */ []));
437
- }
438
- close() {
439
- this.store.dispatchActionType(NgssmTreeActionType.closeSearchDialog);
440
- }
441
- search() {
442
- const searchPattern = this.searchPatternControl.value;
443
- if (searchPattern) {
444
- this.store.dispatchAction(new SearchTreeNodesAction(searchPattern));
445
- }
446
- }
447
- abort() {
448
- this.store.dispatchActionType(NgssmTreeActionType.abortTreeNodesSearch);
449
- }
450
- validatedRegex(control) {
451
- const result = defaultRegexEditorValidator.validatePattern(control.value);
452
- if (result.isValid) {
453
- return null;
454
- }
455
- return {
456
- regex: result.error
457
- };
458
- }
459
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgssmTreeSearchDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
460
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: NgssmTreeSearchDialogComponent, isStandalone: true, selector: "ngssm-ngssm-tree-search-dialog", viewQueries: [{ propertyName: "resultsViewerContainer", first: true, predicate: ["resultsViewerContainer"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "<h1 mat-dialog-title>Tree search dialog</h1>\n@let searchInProgress = currentSearchStatus() === searchStatus.inProgress;\n<mat-dialog-content class=\"flex-column-stretch fxFlex\">\n <mat-card class=\"flex-column-stretch\">\n <mat-card-content class=\"flex-row-center\">\n <mat-form-field class=\"with-margin-right-12 fxFlex\">\n <mat-label>Starts search in</mat-label>\n <input matInput readonly [ngModel]=\"searchRootPath()\" />\n </mat-form-field>\n\n <mat-form-field class=\"fxFlex with-margin-right-12\">\n <mat-label>Search pattern</mat-label>\n <input matInput [formControl]=\"searchPatternControl\" />\n @if (searchPatternControl.errors?.['regex']; as error) {\n <mat-error>\n {{ error }}\n </mat-error>\n }\n </mat-form-field>\n\n @if (!searchInProgress) {\n <button mat-stroked-button color=\"primary\" [disabled]=\"searchPatternControl.invalid\" (click)=\"search()\">\n <mat-icon class=\"fa-solid fa-magnifying-glass\"></mat-icon>\n Search\n </button>\n } @else {\n <button mat-raised-button color=\"accent\" (click)=\"abort()\">\n <mat-icon class=\"fa-solid fa-ban\"></mat-icon>\n Abort\n </button>\n }\n </mat-card-content>\n @if (searchInProgress) {\n <mat-card-footer class=\"flex-row-center\">\n <mat-spinner [diameter]=\"20\"></mat-spinner>\n {{ currentSearchedPath() }}\n </mat-card-footer>\n }\n </mat-card>\n <mat-card class=\"flex-column-stretch fxFlex with-margin-top-8\">\n <ng-container #resultsViewerContainer></ng-container>\n </mat-card>\n</mat-dialog-content>\n<mat-dialog-actions class=\"flex-row-center\">\n <span class=\"fxFlex\"></span>\n <button mat-button (click)=\"close()\">Close</button>\n</mat-dialog-actions>\n", styles: [":host{display:flex;flex-direction:column;height:100%}:host .mat-mdc-dialog-content{max-height:unset!important}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i4$1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i4$1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i4$1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i6.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i6.MatCardContent, selector: "mat-card-content" }, { kind: "directive", type: i6.MatCardFooter, selector: "mat-card-footer" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i5.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }] });
461
- }
462
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgssmTreeSearchDialogComponent, decorators: [{
463
- type: Component,
464
- args: [{ selector: 'ngssm-ngssm-tree-search-dialog', imports: [
465
- FormsModule,
466
- ReactiveFormsModule,
467
- MatFormFieldModule,
468
- MatInputModule,
469
- MatDialogModule,
470
- MatButtonModule,
471
- MatCardModule,
472
- MatIconModule,
473
- MatProgressSpinnerModule
474
- ], template: "<h1 mat-dialog-title>Tree search dialog</h1>\n@let searchInProgress = currentSearchStatus() === searchStatus.inProgress;\n<mat-dialog-content class=\"flex-column-stretch fxFlex\">\n <mat-card class=\"flex-column-stretch\">\n <mat-card-content class=\"flex-row-center\">\n <mat-form-field class=\"with-margin-right-12 fxFlex\">\n <mat-label>Starts search in</mat-label>\n <input matInput readonly [ngModel]=\"searchRootPath()\" />\n </mat-form-field>\n\n <mat-form-field class=\"fxFlex with-margin-right-12\">\n <mat-label>Search pattern</mat-label>\n <input matInput [formControl]=\"searchPatternControl\" />\n @if (searchPatternControl.errors?.['regex']; as error) {\n <mat-error>\n {{ error }}\n </mat-error>\n }\n </mat-form-field>\n\n @if (!searchInProgress) {\n <button mat-stroked-button color=\"primary\" [disabled]=\"searchPatternControl.invalid\" (click)=\"search()\">\n <mat-icon class=\"fa-solid fa-magnifying-glass\"></mat-icon>\n Search\n </button>\n } @else {\n <button mat-raised-button color=\"accent\" (click)=\"abort()\">\n <mat-icon class=\"fa-solid fa-ban\"></mat-icon>\n Abort\n </button>\n }\n </mat-card-content>\n @if (searchInProgress) {\n <mat-card-footer class=\"flex-row-center\">\n <mat-spinner [diameter]=\"20\"></mat-spinner>\n {{ currentSearchedPath() }}\n </mat-card-footer>\n }\n </mat-card>\n <mat-card class=\"flex-column-stretch fxFlex with-margin-top-8\">\n <ng-container #resultsViewerContainer></ng-container>\n </mat-card>\n</mat-dialog-content>\n<mat-dialog-actions class=\"flex-row-center\">\n <span class=\"fxFlex\"></span>\n <button mat-button (click)=\"close()\">Close</button>\n</mat-dialog-actions>\n", styles: [":host{display:flex;flex-direction:column;height:100%}:host .mat-mdc-dialog-content{max-height:unset!important}\n"] }]
475
- }], ctorParameters: () => [], propDecorators: { resultsViewerContainer: [{ type: i0.ViewChild, args: ['resultsViewerContainer', { ...{ read: ViewContainerRef }, isSignal: true }] }] } });
476
-
477
- class TreeNodesSearchingEffect {
478
- processedActions = [
479
- NgssmTreeActionType.displaySearchDialog,
480
- NgssmTreeActionType.closeSearchDialog,
481
- NgssmTreeActionType.searchTreeNodes,
482
- NgssmTreeActionType.registerNodes,
483
- NgssmTreeActionType.registerPartialSearchResults
484
- ];
485
- matDialog = inject(MatDialog);
486
- logger = inject(Logger);
487
- dialog;
488
- processAction(actiondispatcher, state, action) {
489
- switch (action.type) {
490
- case NgssmTreeActionType.displaySearchDialog: {
491
- this.dialog = this.matDialog.open(NgssmTreeSearchDialogComponent, {
492
- disableClose: true,
493
- width: '80vw',
494
- height: '80vh'
495
- });
496
- break;
497
- }
498
- case NgssmTreeActionType.closeSearchDialog: {
499
- this.closeDialog();
500
- break;
501
- }
502
- case NgssmTreeActionType.searchTreeNodes:
503
- case NgssmTreeActionType.registerNodes:
504
- case NgssmTreeActionType.registerPartialSearchResults: {
505
- const searchState = selectNgssmTreeState(state).treeNodesSearch;
506
- if (!searchState.treeId || !searchState.rootSearchNodeId || searchState.searchStatus !== SearchStatus.inProgress) {
507
- return;
508
- }
509
- if (searchState.toProcess.length === 0) {
510
- return;
511
- }
512
- const currentNode = selectNgssmTreeNode(state, searchState.treeId, searchState.toProcess[0].nodeId);
513
- if (!currentNode) {
514
- this.logger.error(`No node for treeId '${searchState.treeId}' with id '${searchState.toProcess[0].nodeId}'.`);
515
- return;
516
- }
517
- if (currentNode.node.isExpandable && currentNode.status !== DataStatus.loaded && currentNode.status !== DataStatus.loading) {
518
- actiondispatcher.dispatchAction(new LoadChildrenOfNodeAction(searchState.treeId, currentNode.node.nodeId));
519
- return;
520
- }
521
- const childrenNodes = selectNgssmTreeNodeChildren(state, searchState.treeId, currentNode.node.nodeId);
522
- const matching = [];
523
- const toProcess = [];
524
- childrenNodes.forEach((node) => {
525
- const fullPath = `${node.parentFullPath}/${node.node.label}`;
526
- if (defaultRegexEditorValidator.isMatch(searchState.searchPattern ?? '', fullPath)) {
527
- matching.push(node);
528
- }
529
- if (node.node.isExpandable) {
530
- toProcess.push(node);
531
- }
532
- });
533
- actiondispatcher.dispatchAction(new RegisterPartialSearchResultsAction(matching, toProcess));
534
- break;
535
- }
536
- }
537
- }
538
- closeDialog() {
539
- this.dialog?.close();
540
- this.dialog = undefined;
541
- }
542
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreeNodesSearchingEffect, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
543
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreeNodesSearchingEffect });
544
- }
545
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreeNodesSearchingEffect, decorators: [{
546
- type: Injectable
547
- }] });
548
-
549
- class TreeNodeExpandReducer {
550
- processedActions = [
551
- NgssmTreeActionType.expandNode,
552
- NgssmTreeActionType.collapseNode,
553
- NgssmTreeActionType.selectNode,
554
- NgssmTreeActionType.loadChildrenOfNode
555
- ];
556
- updateState(state, action) {
557
- switch (action.type) {
558
- case NgssmTreeActionType.expandNode: {
559
- const expandNodeAction = action;
560
- return updateNgssmTreeState(state, {
561
- trees: {
562
- [expandNodeAction.treeId]: {
563
- nodes: {
564
- $apply: (nodes) => {
565
- const result = [...nodes];
566
- const index = result.findIndex((n) => n.node.nodeId === expandNodeAction.nodeId);
567
- if (index !== -1) {
568
- let item = result[index];
569
- if (item.status === DataStatus.loaded) {
570
- item = update(result[index], {
571
- isExpanded: { $set: true }
572
- });
573
- }
574
- else {
575
- item = update(result[index], {
576
- isExpanded: { $set: true },
577
- status: { $set: DataStatus.loading }
578
- });
579
- }
580
- result.splice(index, 1, item);
581
- }
582
- return result;
583
- }
584
- }
585
- }
586
- }
587
- });
588
- }
589
- case NgssmTreeActionType.collapseNode: {
590
- const collapseNodeAction = action;
591
- return updateNgssmTreeState(state, {
592
- trees: {
593
- [collapseNodeAction.treeId]: {
594
- nodes: {
595
- $apply: (nodes) => {
596
- const result = [...nodes];
597
- const index = result.findIndex((n) => n.node.nodeId === collapseNodeAction.nodeId);
598
- if (index !== -1) {
599
- const item = update(result[index], {
600
- isExpanded: { $set: false }
601
- });
602
- result.splice(index, 1, item);
603
- }
604
- return result;
605
- }
606
- }
607
- }
608
- }
609
- });
610
- }
611
- case NgssmTreeActionType.selectNode: {
612
- const selectNodeAction = action;
613
- if (selectNgssmTreeState(state).trees[selectNodeAction.treeId].nodes.find((n) => n.node.nodeId === selectNodeAction.nodeId)
614
- ?.status === DataStatus.loaded) {
615
- break;
616
- }
617
- return updateNgssmTreeState(state, {
618
- trees: {
619
- [selectNodeAction.treeId]: {
620
- nodes: {
621
- $apply: (nodes) => {
622
- const result = [...nodes];
623
- const index = result.findIndex((n) => n.node.nodeId === selectNodeAction.nodeId);
624
- if (index !== -1) {
625
- const item = update(result[index], {
626
- status: { $set: DataStatus.loading }
627
- });
628
- result.splice(index, 1, item);
629
- }
630
- return result;
631
- }
632
- }
633
- }
634
- }
635
- });
636
- }
637
- case NgssmTreeActionType.loadChildrenOfNode: {
638
- const loadChildrenOfNodeAction = action;
639
- return updateNgssmTreeState(state, {
640
- trees: {
641
- [loadChildrenOfNodeAction.treeId]: {
642
- nodes: {
643
- $apply: (nodes) => {
644
- const result = [...nodes];
645
- const index = result.findIndex((n) => n.node.nodeId === loadChildrenOfNodeAction.nodeId);
646
- if (index !== -1) {
647
- let item = result[index];
648
- if (item.status !== DataStatus.loaded) {
649
- item = update(result[index], {
650
- status: { $set: DataStatus.loading }
651
- });
652
- }
653
- result.splice(index, 1, item);
654
- }
655
- return result;
656
- }
657
- }
658
- }
659
- }
660
- });
661
- }
662
- }
663
- return state;
664
- }
665
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreeNodeExpandReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
666
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreeNodeExpandReducer });
667
- }
668
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreeNodeExpandReducer, decorators: [{
669
- type: Injectable
670
- }] });
671
-
672
- class TreeNodeSelectionReducer {
673
- processedActions = [NgssmTreeActionType.selectNode];
674
- updateState(state, action) {
675
- switch (action.type) {
676
- case NgssmTreeActionType.selectNode: {
677
- const selectNodeAction = action;
678
- return updateNgssmTreeState(state, {
679
- trees: {
680
- [selectNodeAction.treeId]: {
681
- selectedNode: { $set: selectNodeAction.nodeId }
682
- }
683
- }
684
- });
685
- }
686
- }
687
- return state;
688
- }
689
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreeNodeSelectionReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
690
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreeNodeSelectionReducer });
691
- }
692
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreeNodeSelectionReducer, decorators: [{
693
- type: Injectable
694
- }] });
695
-
696
- class TreeNodesSearchReducer {
697
- processedActions = [
698
- NgssmTreeActionType.displaySearchDialog,
699
- NgssmTreeActionType.closeSearchDialog,
700
- NgssmTreeActionType.searchTreeNodes,
701
- NgssmTreeActionType.registerPartialSearchResults,
702
- NgssmTreeActionType.abortTreeNodesSearch
703
- ];
704
- updateState(state, action) {
705
- switch (action.type) {
706
- case NgssmTreeActionType.displaySearchDialog: {
707
- const displaySearchDialogAction = action;
708
- const path = getNgssmTreePath(selectNgssmTreeState(state).trees[displaySearchDialogAction.treeId], displaySearchDialogAction.startNodeId);
709
- return updateNgssmTreeState(state, {
710
- treeNodesSearch: {
711
- treeId: { $set: displaySearchDialogAction.treeId },
712
- rootSearchNodeId: { $set: displaySearchDialogAction.startNodeId },
713
- rootSearchPath: { $set: path.map((p) => p.node.label).join('/') }
714
- }
715
- });
716
- }
717
- case NgssmTreeActionType.closeSearchDialog: {
718
- return updateNgssmTreeState(state, {
719
- treeNodesSearch: { $set: getDefaultTreeNodesSearch() }
720
- });
721
- }
722
- case NgssmTreeActionType.searchTreeNodes: {
723
- const searchTreeNodesAction = action;
724
- const startNode = selectNgssmTreeNode(state, selectNgssmTreeState(state).treeNodesSearch.treeId ?? '', selectNgssmTreeState(state).treeNodesSearch.rootSearchNodeId ?? '');
725
- const toBeProcess = [];
726
- if (startNode) {
727
- toBeProcess.push({ nodeId: startNode.node.nodeId, fullPath: getNgssmTreeNodeFullPath(startNode) });
728
- }
729
- return updateNgssmTreeState(state, {
730
- treeNodesSearch: {
731
- searchPattern: { $set: searchTreeNodesAction.searchPattern },
732
- searchStatus: { $set: SearchStatus.inProgress },
733
- toProcess: { $set: toBeProcess },
734
- matchingNodes: { $set: [] }
735
- }
736
- });
737
- }
738
- case NgssmTreeActionType.registerPartialSearchResults: {
739
- const registerPartialSearchResultsAction = action;
740
- const toProcess = selectNgssmTreeState(state).treeNodesSearch.toProcess.slice(1);
741
- toProcess.push(...registerPartialSearchResultsAction.nodesToProcess.map((n) => ({
742
- nodeId: n.node.nodeId,
743
- fullPath: getNgssmTreeNodeFullPath(n)
744
- })));
745
- return updateNgssmTreeState(state, {
746
- treeNodesSearch: {
747
- searchStatus: {
748
- $apply: (value) => {
749
- if (toProcess.length === 0) {
750
- return SearchStatus.done;
751
- }
752
- return value;
753
- }
754
- },
755
- toProcess: { $set: toProcess },
756
- matchingNodes: { $push: registerPartialSearchResultsAction.matchingNodes.map((n) => n.node.nodeId) }
757
- }
758
- });
759
- }
760
- case NgssmTreeActionType.abortTreeNodesSearch: {
761
- return updateNgssmTreeState(state, {
762
- treeNodesSearch: {
763
- searchStatus: { $set: SearchStatus.aborted },
764
- toProcess: { $set: [] }
765
- }
766
- });
767
- }
768
- }
769
- return state;
770
- }
771
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreeNodesSearchReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
772
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreeNodesSearchReducer });
773
- }
774
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreeNodesSearchReducer, decorators: [{
775
- type: Injectable
776
- }] });
777
-
778
- class TreeNodesReducer {
779
- processedActions = [NgssmTreeActionType.registerNodes];
780
- updateState(state, action) {
781
- switch (action.type) {
782
- case NgssmTreeActionType.registerNodes: {
783
- const registerNodesAction = action;
784
- return updateNgssmTreeState(state, {
785
- trees: {
786
- [registerNodesAction.treeId]: {
787
- nodes: {
788
- $apply: (nodes) => {
789
- const index = nodes.findIndex((n) => n.node.nodeId === registerNodesAction.parentNodeId);
790
- if (index === -1) {
791
- return nodes;
792
- }
793
- return [
794
- ...nodes.slice(0, index),
795
- update(nodes[index], { status: { $set: registerNodesAction.dataStatus } }),
796
- ...registerNodesAction.nodes.map((i) => ({
797
- status: DataStatus.none,
798
- isExpanded: false,
799
- level: nodes[index].level + 1,
800
- node: i,
801
- parentFullPath: nodes[index].parentFullPath !== undefined
802
- ? `${nodes[index].parentFullPath}/${nodes[index].node.label}`
803
- : nodes[index].node.label
804
- })),
805
- ...nodes.slice(index + 1)
806
- ];
807
- }
808
- }
809
- }
810
- }
811
- });
812
- }
813
- }
814
- return state;
815
- }
816
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreeNodesReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
817
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreeNodesReducer });
818
- }
819
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreeNodesReducer, decorators: [{
820
- type: Injectable
821
- }] });
822
-
823
- class TreesReducer {
824
- processedActions = [NgssmTreeActionType.initNgssmTree, NgssmTreeActionType.deleteNgssmTree];
825
- updateState(state, action) {
826
- switch (action.type) {
827
- case NgssmTreeActionType.initNgssmTree: {
828
- const initNgssmTreeAction = action;
829
- return updateNgssmTreeState(state, {
830
- trees: {
831
- [initNgssmTreeAction.treeId]: {
832
- $set: {
833
- nodes: [
834
- {
835
- status: DataStatus.none,
836
- isExpanded: false,
837
- level: 0,
838
- node: initNgssmTreeAction.root
839
- }
840
- ],
841
- type: initNgssmTreeAction.treeType
842
- }
843
- }
844
- }
845
- });
846
- }
847
- case NgssmTreeActionType.deleteNgssmTree: {
848
- const deleteNgssmTreeAction = action;
849
- return updateNgssmTreeState(state, {
850
- trees: { $unset: [deleteNgssmTreeAction.treeId] }
851
- });
852
- }
853
- }
854
- return state;
855
- }
856
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreesReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
857
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreesReducer });
858
- }
859
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TreesReducer, decorators: [{
860
- type: Injectable
861
- }] });
862
-
173
+ var TreeNodeLoadingEffect = class TreeNodeLoadingEffect {
174
+ processedActions = [
175
+ NgssmTreeActionType.expandNode,
176
+ NgssmTreeActionType.selectNode,
177
+ NgssmTreeActionType.loadChildrenOfNode
178
+ ];
179
+ dataServices = inject(NGSSM_TREE_DATA_SERVICE, { optional: true }) ?? [];
180
+ logger = inject(Logger);
181
+ processAction(actiondispatcher, state, action) {
182
+ const treeNodeAction = action;
183
+ if (!selectNgssmTreeState(state).trees[treeNodeAction.treeId]) {
184
+ this.logger.error(`Trying to process action for tree not initialized: ${treeNodeAction.treeId}.`);
185
+ return;
186
+ }
187
+ const treeType = selectNgssmTreeState(state).trees[treeNodeAction.treeId].type;
188
+ const dataService = (this.dataServices ?? []).find((d) => d.treeType === treeType);
189
+ if (!dataService) {
190
+ this.logger.error(`Trying to process action for tree with no data service: ${treeNodeAction.treeId} / ${treeType}.`);
191
+ return;
192
+ }
193
+ if (selectNgssmTreeState(state).trees[treeNodeAction.treeId].nodes.find((n) => n.node.nodeId === treeNodeAction.nodeId)?.status !== DataStatus.loading) return;
194
+ dataService.load(treeNodeAction.treeId, treeNodeAction.nodeId).subscribe({
195
+ next: (value) => actiondispatcher.dispatchAction(new RegisterNodesAction(DataStatus.loaded, treeNodeAction.treeId, treeNodeAction.nodeId, value)),
196
+ error: (error) => {
197
+ this.logger.error(`Unable to load children nodes for tree '${treeNodeAction.treeId}' and node '${treeNodeAction.nodeId}'`, error);
198
+ actiondispatcher.dispatchAction(new RegisterNodesAction(DataStatus.error, treeNodeAction.treeId, treeNodeAction.nodeId));
199
+ }
200
+ });
201
+ }
202
+ static ɵfac = i0.ɵɵngDeclareFactory({
203
+ minVersion: "12.0.0",
204
+ version: "22.2.0",
205
+ ngImport: i0,
206
+ type: TreeNodeLoadingEffect,
207
+ deps: [],
208
+ target: i0.ɵɵFactoryTarget.Injectable
209
+ });
210
+ static ɵprov = i0.ɵɵngDeclareInjectable({
211
+ minVersion: "12.0.0",
212
+ version: "22.2.0",
213
+ ngImport: i0,
214
+ type: TreeNodeLoadingEffect
215
+ });
216
+ };
217
+ i0.ɵɵngDeclareClassMetadata({
218
+ minVersion: "12.0.0",
219
+ version: "22.2.0",
220
+ ngImport: i0,
221
+ type: TreeNodeLoadingEffect,
222
+ decorators: [{ type: Injectable }]
223
+ });
224
+ var NgssmTreeComponent = class NgssmTreeComponent {
225
+ treeConfig = input(...ngDevMode ? [void 0, { debugName: "treeConfig" }] : /* istanbul ignore next */ []);
226
+ dataStatus = DataStatus;
227
+ displayedItems = signal([], ...ngDevMode ? [{ debugName: "displayedItems" }] : /* istanbul ignore next */ []);
228
+ selectedNodeId = signal(void 0, ...ngDevMode ? [{ debugName: "selectedNodeId" }] : /* istanbul ignore next */ []);
229
+ store = inject(Store);
230
+ trees = createSignal((state) => selectNgssmTreeState(state).trees);
231
+ tree = signal(void 0, ...ngDevMode ? [{ debugName: "tree" }] : /* istanbul ignore next */ []);
232
+ constructor() {
233
+ effect(() => {
234
+ const currentConfig = this.treeConfig();
235
+ const currentTrees = this.trees();
236
+ if (currentConfig) this.tree.set(currentTrees[currentConfig.treeId]);
237
+ else this.tree.set(void 0);
238
+ });
239
+ effect(() => {
240
+ const currentTree = this.tree();
241
+ const config = untracked(() => this.treeConfig());
242
+ if (!currentTree || !config) {
243
+ this.displayedItems.set([]);
244
+ return;
245
+ }
246
+ const alwaysTrue = () => true;
247
+ const filter = config.filter ?? alwaysTrue;
248
+ const canSearch = config.canSearch ?? alwaysTrue;
249
+ const items = [];
250
+ let hiddenLevel = -1;
251
+ const nodesToFindSelected = /* @__PURE__ */ new Map();
252
+ (currentTree.nodes ?? []).forEach((t) => {
253
+ if (t.node.isExpandable && t.isExpanded === false && hiddenLevel === -1) hiddenLevel = t.level;
254
+ if (hiddenLevel === -1 || t.level <= hiddenLevel) {
255
+ if (filter(t.node)) {
256
+ items.push({
257
+ node: t,
258
+ canSearch: canSearch(t.node)
259
+ });
260
+ nodesToFindSelected.set(t.node.nodeId, {
261
+ isDisplayed: true,
262
+ node: t
263
+ });
264
+ }
265
+ }
266
+ if (t.node.isExpandable && t.level <= hiddenLevel) hiddenLevel = t.isExpanded === true ? -1 : t.level;
267
+ if (!nodesToFindSelected.has(t.node.nodeId)) nodesToFindSelected.set(t.node.nodeId, {
268
+ isDisplayed: false,
269
+ node: t
270
+ });
271
+ });
272
+ this.displayedItems.set(items);
273
+ let selectedNode = currentTree.selectedNode;
274
+ if (!selectedNode) this.selectedNodeId.set(void 0);
275
+ else {
276
+ while (selectedNode) {
277
+ const item = nodesToFindSelected.get(selectedNode);
278
+ if (item?.isDisplayed !== true) selectedNode = item?.node.node.parentNodeId;
279
+ else break;
280
+ }
281
+ this.selectedNodeId.set(selectedNode);
282
+ }
283
+ });
284
+ }
285
+ getItemId(_, node) {
286
+ return node.node.node.nodeId;
287
+ }
288
+ expand(node) {
289
+ const treeId = this.treeConfig()?.treeId;
290
+ if (treeId) this.store.dispatchAction(new ExpandNodeAction(treeId, node.node.nodeId));
291
+ }
292
+ collapse(node) {
293
+ const treeId = this.treeConfig()?.treeId;
294
+ if (treeId) this.store.dispatchAction(new CollapseNodeAction(treeId, node.node.nodeId));
295
+ }
296
+ selectNode(node) {
297
+ const treeId = this.treeConfig()?.treeId;
298
+ if (treeId) this.store.dispatchAction(new SelectNodeAction(treeId, node.node.nodeId));
299
+ }
300
+ displaySearchDialog(node) {
301
+ const treeId = this.treeConfig()?.treeId;
302
+ if (treeId) this.store.dispatchAction(new DisplaySearchDialogAction(treeId, node.node.nodeId));
303
+ }
304
+ static ɵfac = i0.ɵɵngDeclareFactory({
305
+ minVersion: "12.0.0",
306
+ version: "22.2.0",
307
+ ngImport: i0,
308
+ type: NgssmTreeComponent,
309
+ deps: [],
310
+ target: i0.ɵɵFactoryTarget.Component
311
+ });
312
+ static ɵcmp = i0.ɵɵngDeclareComponent({
313
+ minVersion: "17.0.0",
314
+ version: "22.2.0",
315
+ type: NgssmTreeComponent,
316
+ isStandalone: true,
317
+ selector: "ngssm-tree",
318
+ inputs: { treeConfig: {
319
+ classPropertyName: "treeConfig",
320
+ publicName: "treeConfig",
321
+ isSignal: true,
322
+ isRequired: false,
323
+ transformFunction: null
324
+ } },
325
+ ngImport: i0,
326
+ template: "<mat-card class=\"flex-column-stretch fxFlex\">\n @if (treeConfig(); as config) {\n <mat-card-content class=\"flex-column-stretch fxFlex\">\n <cdk-virtual-scroll-viewport itemSize=\"30\" class=\"fxFlex\">\n <div\n *cdkVirtualFor=\"let item of displayedItems(); trackBy: getItemId\"\n class=\"ngssm-tree-node\"\n [style.padding-left.px]=\"item.node.level * 20\"\n (click)=\"selectNode(item.node)\"\n aria-hidden=\"true\"\n (keyup.enter)=\"selectNode(item.node)\"\n [ngClass]=\"{ selected: selectedNodeId() === item.node.node.nodeId }\">\n @if (item.node.node.isExpandable) {\n @if (item.node.status === dataStatus.loading) {\n <mat-spinner diameter=\"20\"></mat-spinner>\n } @else {\n @if (item.node.isExpanded) {\n <mat-icon class=\"fa-solid fa-chevron-down\" (click)=\"$event.stopPropagation(); collapse(item.node)\"></mat-icon>\n } @else {\n <mat-icon class=\"fa-solid fa-chevron-right\" (click)=\"$event.stopPropagation(); expand(item.node)\"></mat-icon>\n }\n }\n } @else {\n <span class=\"not-expandable-padding\"></span>\n }\n\n <mat-icon class=\"{{ config.iconClasses[item.node.node.type] }}\" color=\"primary\"></mat-icon>\n\n <span class=\"ngssm-tree-node-label\">\n {{ item.node.node.label }}\n </span>\n <span class=\"fxFlex\"></span>\n @if (item.canSearch) {\n <i class=\"fa-solid fa-magnifying-glass search-icon\" (click)=\"$event.stopPropagation(); displaySearchDialog(item.node)\"> </i>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n </mat-card-content>\n }\n</mat-card>\n",
327
+ styles: [":host{display:flex;flex-direction:column}:host .ngssm-tree-node{height:30px;display:flex;flex-direction:row;align-items:center;padding-right:12px}:host .ngssm-tree-node .fa-folder{margin-right:4px}:host .ngssm-tree-node .fa-chevron-right:hover{cursor:pointer}:host .ngssm-tree-node.selected{background-color:#e4e6f1}:host .ngssm-tree-node:hover{cursor:pointer}:host .ngssm-tree-node:hover .search-icon{display:unset}:host .ngssm-tree-node:hover:not(.selected){background-color:#f3f3f3}:host .not-expandable-padding{width:24px}:host .search-icon{font-size:12px;display:none}\n"],
328
+ dependencies: [
329
+ {
330
+ kind: "ngmodule",
331
+ type: CommonModule
332
+ },
333
+ {
334
+ kind: "directive",
335
+ type: i1$1.NgClass,
336
+ selector: "[ngClass]",
337
+ inputs: ["class", "ngClass"]
338
+ },
339
+ {
340
+ kind: "ngmodule",
341
+ type: ScrollingModule
342
+ },
343
+ {
344
+ kind: "directive",
345
+ type: i2$2.CdkFixedSizeVirtualScroll,
346
+ selector: "cdk-virtual-scroll-viewport[itemSize]",
347
+ inputs: [
348
+ "itemSize",
349
+ "minBufferPx",
350
+ "maxBufferPx"
351
+ ]
352
+ },
353
+ {
354
+ kind: "directive",
355
+ type: i2$2.CdkVirtualForOf,
356
+ selector: "[cdkVirtualFor][cdkVirtualForOf]",
357
+ inputs: [
358
+ "cdkVirtualForOf",
359
+ "cdkVirtualForTrackBy",
360
+ "cdkVirtualForTemplate",
361
+ "cdkVirtualForTemplateCacheSize"
362
+ ]
363
+ },
364
+ {
365
+ kind: "component",
366
+ type: i2$2.CdkVirtualScrollViewport,
367
+ selector: "cdk-virtual-scroll-viewport",
368
+ inputs: ["orientation", "appendOnly"],
369
+ outputs: ["scrolledIndexChange"]
370
+ },
371
+ {
372
+ kind: "ngmodule",
373
+ type: MatCardModule
374
+ },
375
+ {
376
+ kind: "component",
377
+ type: i3$1.MatCard,
378
+ selector: "mat-card",
379
+ inputs: ["appearance"],
380
+ exportAs: ["matCard"]
381
+ },
382
+ {
383
+ kind: "directive",
384
+ type: i3$1.MatCardContent,
385
+ selector: "mat-card-content"
386
+ },
387
+ {
388
+ kind: "ngmodule",
389
+ type: MatIconModule
390
+ },
391
+ {
392
+ kind: "component",
393
+ type: i4$1.MatIcon,
394
+ selector: "mat-icon",
395
+ inputs: [
396
+ "color",
397
+ "inline",
398
+ "svgIcon",
399
+ "fontSet",
400
+ "fontIcon"
401
+ ],
402
+ exportAs: ["matIcon"]
403
+ },
404
+ {
405
+ kind: "ngmodule",
406
+ type: MatProgressSpinnerModule
407
+ },
408
+ {
409
+ kind: "component",
410
+ type: i5.MatProgressSpinner,
411
+ selector: "mat-progress-spinner, mat-spinner",
412
+ inputs: [
413
+ "color",
414
+ "mode",
415
+ "value",
416
+ "diameter",
417
+ "strokeWidth"
418
+ ],
419
+ exportAs: ["matProgressSpinner"]
420
+ }
421
+ ]
422
+ });
423
+ };
424
+ i0.ɵɵngDeclareClassMetadata({
425
+ minVersion: "12.0.0",
426
+ version: "22.2.0",
427
+ ngImport: i0,
428
+ type: NgssmTreeComponent,
429
+ decorators: [{
430
+ type: Component,
431
+ args: [{
432
+ selector: "ngssm-tree",
433
+ imports: [
434
+ CommonModule,
435
+ ScrollingModule,
436
+ MatCardModule,
437
+ MatIconModule,
438
+ MatProgressSpinnerModule
439
+ ],
440
+ template: "<mat-card class=\"flex-column-stretch fxFlex\">\n @if (treeConfig(); as config) {\n <mat-card-content class=\"flex-column-stretch fxFlex\">\n <cdk-virtual-scroll-viewport itemSize=\"30\" class=\"fxFlex\">\n <div\n *cdkVirtualFor=\"let item of displayedItems(); trackBy: getItemId\"\n class=\"ngssm-tree-node\"\n [style.padding-left.px]=\"item.node.level * 20\"\n (click)=\"selectNode(item.node)\"\n aria-hidden=\"true\"\n (keyup.enter)=\"selectNode(item.node)\"\n [ngClass]=\"{ selected: selectedNodeId() === item.node.node.nodeId }\">\n @if (item.node.node.isExpandable) {\n @if (item.node.status === dataStatus.loading) {\n <mat-spinner diameter=\"20\"></mat-spinner>\n } @else {\n @if (item.node.isExpanded) {\n <mat-icon class=\"fa-solid fa-chevron-down\" (click)=\"$event.stopPropagation(); collapse(item.node)\"></mat-icon>\n } @else {\n <mat-icon class=\"fa-solid fa-chevron-right\" (click)=\"$event.stopPropagation(); expand(item.node)\"></mat-icon>\n }\n }\n } @else {\n <span class=\"not-expandable-padding\"></span>\n }\n\n <mat-icon class=\"{{ config.iconClasses[item.node.node.type] }}\" color=\"primary\"></mat-icon>\n\n <span class=\"ngssm-tree-node-label\">\n {{ item.node.node.label }}\n </span>\n <span class=\"fxFlex\"></span>\n @if (item.canSearch) {\n <i class=\"fa-solid fa-magnifying-glass search-icon\" (click)=\"$event.stopPropagation(); displaySearchDialog(item.node)\"> </i>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n </mat-card-content>\n }\n</mat-card>\n",
441
+ styles: [":host{display:flex;flex-direction:column}:host .ngssm-tree-node{height:30px;display:flex;flex-direction:row;align-items:center;padding-right:12px}:host .ngssm-tree-node .fa-folder{margin-right:4px}:host .ngssm-tree-node .fa-chevron-right:hover{cursor:pointer}:host .ngssm-tree-node.selected{background-color:#e4e6f1}:host .ngssm-tree-node:hover{cursor:pointer}:host .ngssm-tree-node:hover .search-icon{display:unset}:host .ngssm-tree-node:hover:not(.selected){background-color:#f3f3f3}:host .not-expandable-padding{width:24px}:host .search-icon{font-size:12px;display:none}\n"]
442
+ }]
443
+ }],
444
+ ctorParameters: () => [],
445
+ propDecorators: { treeConfig: [{
446
+ type: i0.Input,
447
+ args: [{
448
+ isSignal: true,
449
+ alias: "treeConfig",
450
+ required: false
451
+ }]
452
+ }] }
453
+ });
454
+ var NgssmBreadcrumbComponent = class NgssmBreadcrumbComponent {
455
+ treeId = input(void 0, ...ngDevMode ? [{ debugName: "treeId" }] : /* istanbul ignore next */ []);
456
+ nodes = signal([], ...ngDevMode ? [{ debugName: "nodes" }] : /* istanbul ignore next */ []);
457
+ store = inject(Store);
458
+ treeState = createSignal((state) => selectNgssmTreeState(state));
459
+ constructor() {
460
+ effect(() => {
461
+ const currentTreeId = this.treeId();
462
+ if (!currentTreeId) {
463
+ this.nodes.set([]);
464
+ return;
465
+ }
466
+ const tree = this.treeState()?.trees[currentTreeId];
467
+ if (!tree) {
468
+ this.nodes.set([]);
469
+ return;
470
+ }
471
+ const nodesPerId = new Map(tree.nodes.map((n) => [n.node.nodeId, n.node]));
472
+ const path = [];
473
+ let node = tree.selectedNode ? nodesPerId.get(tree.selectedNode) : void 0;
474
+ while (node) {
475
+ path.unshift(node);
476
+ node = node.parentNodeId ? nodesPerId.get(node.parentNodeId) : void 0;
477
+ }
478
+ if (path.length === 0 && tree.nodes.length > 0) path.push(tree.nodes[0]?.node);
479
+ this.nodes.set(path);
480
+ });
481
+ }
482
+ selectNode(node) {
483
+ const treeId = this.treeId();
484
+ if (treeId) this.store.dispatchAction(new SelectNodeAction(treeId, node.nodeId));
485
+ }
486
+ static ɵfac = i0.ɵɵngDeclareFactory({
487
+ minVersion: "12.0.0",
488
+ version: "22.2.0",
489
+ ngImport: i0,
490
+ type: NgssmBreadcrumbComponent,
491
+ deps: [],
492
+ target: i0.ɵɵFactoryTarget.Component
493
+ });
494
+ static ɵcmp = i0.ɵɵngDeclareComponent({
495
+ minVersion: "17.0.0",
496
+ version: "22.2.0",
497
+ type: NgssmBreadcrumbComponent,
498
+ isStandalone: true,
499
+ selector: "ngssm-breadcrumb",
500
+ inputs: { treeId: {
501
+ classPropertyName: "treeId",
502
+ publicName: "treeId",
503
+ isSignal: true,
504
+ isRequired: false,
505
+ transformFunction: null
506
+ } },
507
+ ngImport: i0,
508
+ template: "<div class=\"flex-row-center\">\n <mat-icon class=\"fa-solid fa-folder-tree\" color=\"primary\"></mat-icon>\n @for (node of nodes(); track node; let last = $last) {\n <span class=\"flex-row-center\">\n <button mat-button [disabled]=\"last\" (click)=\"selectNode(node)\">\n {{ node.label }}\n </button>\n\n @if (!last) {\n <div class=\"ngssm-breadcrumb-separator\">/</div>\n }\n </span>\n }\n</div>\n",
509
+ styles: [".ngssm-breadcrumb-separator{font-weight:700}\n"],
510
+ dependencies: [
511
+ {
512
+ kind: "ngmodule",
513
+ type: MatIconModule
514
+ },
515
+ {
516
+ kind: "component",
517
+ type: i4$1.MatIcon,
518
+ selector: "mat-icon",
519
+ inputs: [
520
+ "color",
521
+ "inline",
522
+ "svgIcon",
523
+ "fontSet",
524
+ "fontIcon"
525
+ ],
526
+ exportAs: ["matIcon"]
527
+ },
528
+ {
529
+ kind: "ngmodule",
530
+ type: MatButtonModule
531
+ },
532
+ {
533
+ kind: "component",
534
+ type: i2$1.MatButton,
535
+ selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ",
536
+ inputs: ["matButton"],
537
+ exportAs: ["matButton", "matAnchor"]
538
+ }
539
+ ]
540
+ });
541
+ };
542
+ i0.ɵɵngDeclareClassMetadata({
543
+ minVersion: "12.0.0",
544
+ version: "22.2.0",
545
+ ngImport: i0,
546
+ type: NgssmBreadcrumbComponent,
547
+ decorators: [{
548
+ type: Component,
549
+ args: [{
550
+ selector: "ngssm-breadcrumb",
551
+ imports: [MatIconModule, MatButtonModule],
552
+ template: "<div class=\"flex-row-center\">\n <mat-icon class=\"fa-solid fa-folder-tree\" color=\"primary\"></mat-icon>\n @for (node of nodes(); track node; let last = $last) {\n <span class=\"flex-row-center\">\n <button mat-button [disabled]=\"last\" (click)=\"selectNode(node)\">\n {{ node.label }}\n </button>\n\n @if (!last) {\n <div class=\"ngssm-breadcrumb-separator\">/</div>\n }\n </span>\n }\n</div>\n",
553
+ styles: [".ngssm-breadcrumb-separator{font-weight:700}\n"]
554
+ }]
555
+ }],
556
+ ctorParameters: () => [],
557
+ propDecorators: { treeId: [{
558
+ type: i0.Input,
559
+ args: [{
560
+ isSignal: true,
561
+ alias: "treeId",
562
+ required: false
563
+ }]
564
+ }] }
565
+ });
566
+ var NgssmTreeSearchDialogComponent = class NgssmTreeSearchDialogComponent {
567
+ resultsViewerContainer = viewChild("resultsViewerContainer", {
568
+ ...ngDevMode ? { debugName: "resultsViewerContainer" } : /* istanbul ignore next */ {},
569
+ read: ViewContainerRef
570
+ });
571
+ searchStatus = SearchStatus;
572
+ searchRootPath = createSignal((state) => selectNgssmTreeState(state).treeNodesSearch.rootSearchPath ?? "");
573
+ currentSearchedPath = createSignal((state) => selectNgssmTreeState(state).treeNodesSearch.toProcess[0]?.fullPath ?? "");
574
+ currentSearchStatus = createSignal((state) => selectNgssmTreeState(state).treeNodesSearch.searchStatus);
575
+ searchPatternControl = new FormControl(void 0, [Validators.required, (c) => this.validatedRegex(c)]);
576
+ store = inject(Store);
577
+ changeDetectorRef = inject(ChangeDetectorRef);
578
+ dataServices = inject(NGSSM_TREE_DATA_SERVICE, { optional: true });
579
+ constructor() {
580
+ const effectRef = effect(() => {
581
+ if (!this.resultsViewerContainer()) return;
582
+ const treeState = selectNgssmTreeState(this.store.state());
583
+ const treeId = treeState.treeNodesSearch.treeId;
584
+ if (!treeId) return;
585
+ const treeType = treeState.trees[treeId]?.type;
586
+ if (!treeType) return;
587
+ const dataService = this.dataServices.find((d) => d.treeType === treeType);
588
+ if (!dataService?.searchResultViewer) return;
589
+ this.resultsViewerContainer()?.createComponent(dataService.searchResultViewer);
590
+ this.changeDetectorRef.markForCheck();
591
+ effectRef.destroy();
592
+ }, ...ngDevMode ? [{ debugName: "effectRef" }] : /* istanbul ignore next */ []);
593
+ }
594
+ close() {
595
+ this.store.dispatchActionType(NgssmTreeActionType.closeSearchDialog);
596
+ }
597
+ search() {
598
+ const searchPattern = this.searchPatternControl.value;
599
+ if (searchPattern) this.store.dispatchAction(new SearchTreeNodesAction(searchPattern));
600
+ }
601
+ abort() {
602
+ this.store.dispatchActionType(NgssmTreeActionType.abortTreeNodesSearch);
603
+ }
604
+ validatedRegex(control) {
605
+ const result = defaultRegexEditorValidator.validatePattern(control.value);
606
+ if (result.isValid) return null;
607
+ return { regex: result.error };
608
+ }
609
+ static ɵfac = i0.ɵɵngDeclareFactory({
610
+ minVersion: "12.0.0",
611
+ version: "22.2.0",
612
+ ngImport: i0,
613
+ type: NgssmTreeSearchDialogComponent,
614
+ deps: [],
615
+ target: i0.ɵɵFactoryTarget.Component
616
+ });
617
+ static ɵcmp = i0.ɵɵngDeclareComponent({
618
+ minVersion: "17.0.0",
619
+ version: "22.2.0",
620
+ type: NgssmTreeSearchDialogComponent,
621
+ isStandalone: true,
622
+ selector: "ngssm-ngssm-tree-search-dialog",
623
+ viewQueries: [{
624
+ propertyName: "resultsViewerContainer",
625
+ first: true,
626
+ predicate: ["resultsViewerContainer"],
627
+ descendants: true,
628
+ read: ViewContainerRef,
629
+ isSignal: true
630
+ }],
631
+ ngImport: i0,
632
+ template: "<h1 mat-dialog-title>Tree search dialog</h1>\n@let searchInProgress = currentSearchStatus() === searchStatus.inProgress;\n<mat-dialog-content class=\"flex-column-stretch fxFlex\">\n <mat-card class=\"flex-column-stretch\">\n <mat-card-content class=\"flex-row-center\">\n <mat-form-field class=\"with-margin-right-12 fxFlex\">\n <mat-label>Starts search in</mat-label>\n <input matInput readonly [ngModel]=\"searchRootPath()\" />\n </mat-form-field>\n\n <mat-form-field class=\"fxFlex with-margin-right-12\">\n <mat-label>Search pattern</mat-label>\n <input matInput [formControl]=\"searchPatternControl\" />\n @if (searchPatternControl.errors?.['regex']; as error) {\n <mat-error>\n {{ error }}\n </mat-error>\n }\n </mat-form-field>\n\n @if (!searchInProgress) {\n <button mat-stroked-button color=\"primary\" [disabled]=\"searchPatternControl.invalid\" (click)=\"search()\">\n <mat-icon class=\"fa-solid fa-magnifying-glass\"></mat-icon>\n Search\n </button>\n } @else {\n <button mat-raised-button color=\"accent\" (click)=\"abort()\">\n <mat-icon class=\"fa-solid fa-ban\"></mat-icon>\n Abort\n </button>\n }\n </mat-card-content>\n @if (searchInProgress) {\n <mat-card-footer class=\"flex-row-center\">\n <mat-spinner [diameter]=\"20\"></mat-spinner>\n {{ currentSearchedPath() }}\n </mat-card-footer>\n }\n </mat-card>\n <mat-card class=\"flex-column-stretch fxFlex with-margin-top-8\">\n <ng-container #resultsViewerContainer></ng-container>\n </mat-card>\n</mat-dialog-content>\n<mat-dialog-actions class=\"flex-row-center\">\n <span class=\"fxFlex\"></span>\n <button mat-button (click)=\"close()\">Close</button>\n</mat-dialog-actions>\n",
633
+ styles: [":host{display:flex;flex-direction:column;height:100%}:host .mat-mdc-dialog-content{max-height:unset!important}\n"],
634
+ dependencies: [
635
+ {
636
+ kind: "ngmodule",
637
+ type: FormsModule
638
+ },
639
+ {
640
+ kind: "directive",
641
+ type: i1.DefaultValueAccessor,
642
+ selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]"
643
+ },
644
+ {
645
+ kind: "directive",
646
+ type: i1.NgControlStatus,
647
+ selector: "[formControlName],[ngModel],[formControl]"
648
+ },
649
+ {
650
+ kind: "directive",
651
+ type: i1.NgModel,
652
+ selector: "[ngModel]:not([formControlName]):not([formControl])",
653
+ inputs: [
654
+ "name",
655
+ "disabled",
656
+ "ngModel",
657
+ "ngModelOptions"
658
+ ],
659
+ outputs: ["ngModelChange"],
660
+ exportAs: ["ngModel"]
661
+ },
662
+ {
663
+ kind: "ngmodule",
664
+ type: ReactiveFormsModule
665
+ },
666
+ {
667
+ kind: "directive",
668
+ type: i1.FormControlDirective,
669
+ selector: "[formControl]",
670
+ inputs: [
671
+ "formControl",
672
+ "disabled",
673
+ "ngModel"
674
+ ],
675
+ outputs: ["ngModelChange"],
676
+ exportAs: ["ngForm"]
677
+ },
678
+ {
679
+ kind: "ngmodule",
680
+ type: MatFormFieldModule
681
+ },
682
+ {
683
+ kind: "component",
684
+ type: i2.MatFormField,
685
+ selector: "mat-form-field",
686
+ inputs: [
687
+ "hideRequiredMarker",
688
+ "color",
689
+ "floatLabel",
690
+ "appearance",
691
+ "subscriptSizing",
692
+ "hintLabel"
693
+ ],
694
+ exportAs: ["matFormField"]
695
+ },
696
+ {
697
+ kind: "directive",
698
+ type: i2.MatLabel,
699
+ selector: "mat-label"
700
+ },
701
+ {
702
+ kind: "directive",
703
+ type: i2.MatError,
704
+ selector: "mat-error, [matError]",
705
+ inputs: ["id"]
706
+ },
707
+ {
708
+ kind: "ngmodule",
709
+ type: MatInputModule
710
+ },
711
+ {
712
+ kind: "directive",
713
+ type: i3.MatInput,
714
+ selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",
715
+ inputs: [
716
+ "disabled",
717
+ "id",
718
+ "placeholder",
719
+ "name",
720
+ "required",
721
+ "type",
722
+ "errorStateMatcher",
723
+ "aria-describedby",
724
+ "value",
725
+ "readonly",
726
+ "disabledInteractive"
727
+ ],
728
+ exportAs: ["matInput"]
729
+ },
730
+ {
731
+ kind: "ngmodule",
732
+ type: MatDialogModule
733
+ },
734
+ {
735
+ kind: "directive",
736
+ type: i4.MatDialogTitle,
737
+ selector: "[mat-dialog-title], [matDialogTitle]",
738
+ inputs: ["id"],
739
+ exportAs: ["matDialogTitle"]
740
+ },
741
+ {
742
+ kind: "directive",
743
+ type: i4.MatDialogActions,
744
+ selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]",
745
+ inputs: ["align"]
746
+ },
747
+ {
748
+ kind: "directive",
749
+ type: i4.MatDialogContent,
750
+ selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]"
751
+ },
752
+ {
753
+ kind: "ngmodule",
754
+ type: MatButtonModule
755
+ },
756
+ {
757
+ kind: "component",
758
+ type: i2$1.MatButton,
759
+ selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ",
760
+ inputs: ["matButton"],
761
+ exportAs: ["matButton", "matAnchor"]
762
+ },
763
+ {
764
+ kind: "ngmodule",
765
+ type: MatCardModule
766
+ },
767
+ {
768
+ kind: "component",
769
+ type: i3$1.MatCard,
770
+ selector: "mat-card",
771
+ inputs: ["appearance"],
772
+ exportAs: ["matCard"]
773
+ },
774
+ {
775
+ kind: "directive",
776
+ type: i3$1.MatCardContent,
777
+ selector: "mat-card-content"
778
+ },
779
+ {
780
+ kind: "directive",
781
+ type: i3$1.MatCardFooter,
782
+ selector: "mat-card-footer"
783
+ },
784
+ {
785
+ kind: "ngmodule",
786
+ type: MatIconModule
787
+ },
788
+ {
789
+ kind: "component",
790
+ type: i4$1.MatIcon,
791
+ selector: "mat-icon",
792
+ inputs: [
793
+ "color",
794
+ "inline",
795
+ "svgIcon",
796
+ "fontSet",
797
+ "fontIcon"
798
+ ],
799
+ exportAs: ["matIcon"]
800
+ },
801
+ {
802
+ kind: "ngmodule",
803
+ type: MatProgressSpinnerModule
804
+ },
805
+ {
806
+ kind: "component",
807
+ type: i5.MatProgressSpinner,
808
+ selector: "mat-progress-spinner, mat-spinner",
809
+ inputs: [
810
+ "color",
811
+ "mode",
812
+ "value",
813
+ "diameter",
814
+ "strokeWidth"
815
+ ],
816
+ exportAs: ["matProgressSpinner"]
817
+ }
818
+ ]
819
+ });
820
+ };
821
+ i0.ɵɵngDeclareClassMetadata({
822
+ minVersion: "12.0.0",
823
+ version: "22.2.0",
824
+ ngImport: i0,
825
+ type: NgssmTreeSearchDialogComponent,
826
+ decorators: [{
827
+ type: Component,
828
+ args: [{
829
+ selector: "ngssm-ngssm-tree-search-dialog",
830
+ imports: [
831
+ FormsModule,
832
+ ReactiveFormsModule,
833
+ MatFormFieldModule,
834
+ MatInputModule,
835
+ MatDialogModule,
836
+ MatButtonModule,
837
+ MatCardModule,
838
+ MatIconModule,
839
+ MatProgressSpinnerModule
840
+ ],
841
+ template: "<h1 mat-dialog-title>Tree search dialog</h1>\n@let searchInProgress = currentSearchStatus() === searchStatus.inProgress;\n<mat-dialog-content class=\"flex-column-stretch fxFlex\">\n <mat-card class=\"flex-column-stretch\">\n <mat-card-content class=\"flex-row-center\">\n <mat-form-field class=\"with-margin-right-12 fxFlex\">\n <mat-label>Starts search in</mat-label>\n <input matInput readonly [ngModel]=\"searchRootPath()\" />\n </mat-form-field>\n\n <mat-form-field class=\"fxFlex with-margin-right-12\">\n <mat-label>Search pattern</mat-label>\n <input matInput [formControl]=\"searchPatternControl\" />\n @if (searchPatternControl.errors?.['regex']; as error) {\n <mat-error>\n {{ error }}\n </mat-error>\n }\n </mat-form-field>\n\n @if (!searchInProgress) {\n <button mat-stroked-button color=\"primary\" [disabled]=\"searchPatternControl.invalid\" (click)=\"search()\">\n <mat-icon class=\"fa-solid fa-magnifying-glass\"></mat-icon>\n Search\n </button>\n } @else {\n <button mat-raised-button color=\"accent\" (click)=\"abort()\">\n <mat-icon class=\"fa-solid fa-ban\"></mat-icon>\n Abort\n </button>\n }\n </mat-card-content>\n @if (searchInProgress) {\n <mat-card-footer class=\"flex-row-center\">\n <mat-spinner [diameter]=\"20\"></mat-spinner>\n {{ currentSearchedPath() }}\n </mat-card-footer>\n }\n </mat-card>\n <mat-card class=\"flex-column-stretch fxFlex with-margin-top-8\">\n <ng-container #resultsViewerContainer></ng-container>\n </mat-card>\n</mat-dialog-content>\n<mat-dialog-actions class=\"flex-row-center\">\n <span class=\"fxFlex\"></span>\n <button mat-button (click)=\"close()\">Close</button>\n</mat-dialog-actions>\n",
842
+ styles: [":host{display:flex;flex-direction:column;height:100%}:host .mat-mdc-dialog-content{max-height:unset!important}\n"]
843
+ }]
844
+ }],
845
+ ctorParameters: () => [],
846
+ propDecorators: { resultsViewerContainer: [{
847
+ type: i0.ViewChild,
848
+ args: ["resultsViewerContainer", {
849
+ read: ViewContainerRef,
850
+ isSignal: true
851
+ }]
852
+ }] }
853
+ });
854
+ var TreeNodesSearchingEffect = class TreeNodesSearchingEffect {
855
+ processedActions = [
856
+ NgssmTreeActionType.displaySearchDialog,
857
+ NgssmTreeActionType.closeSearchDialog,
858
+ NgssmTreeActionType.searchTreeNodes,
859
+ NgssmTreeActionType.registerNodes,
860
+ NgssmTreeActionType.registerPartialSearchResults
861
+ ];
862
+ matDialog = inject(MatDialog);
863
+ logger = inject(Logger);
864
+ dialog;
865
+ processAction(actiondispatcher, state, action) {
866
+ switch (action.type) {
867
+ case NgssmTreeActionType.displaySearchDialog:
868
+ this.dialog = this.matDialog.open(NgssmTreeSearchDialogComponent, {
869
+ disableClose: true,
870
+ width: "80vw",
871
+ height: "80vh"
872
+ });
873
+ break;
874
+ case NgssmTreeActionType.closeSearchDialog:
875
+ this.closeDialog();
876
+ break;
877
+ case NgssmTreeActionType.searchTreeNodes:
878
+ case NgssmTreeActionType.registerNodes:
879
+ case NgssmTreeActionType.registerPartialSearchResults: {
880
+ const searchState = selectNgssmTreeState(state).treeNodesSearch;
881
+ if (!searchState.treeId || !searchState.rootSearchNodeId || searchState.searchStatus !== SearchStatus.inProgress) return;
882
+ if (searchState.toProcess.length === 0) return;
883
+ const currentNode = selectNgssmTreeNode(state, searchState.treeId, searchState.toProcess[0].nodeId);
884
+ if (!currentNode) {
885
+ this.logger.error(`No node for treeId '${searchState.treeId}' with id '${searchState.toProcess[0].nodeId}'.`);
886
+ return;
887
+ }
888
+ if (currentNode.node.isExpandable && currentNode.status !== DataStatus.loaded && currentNode.status !== DataStatus.loading) {
889
+ actiondispatcher.dispatchAction(new LoadChildrenOfNodeAction(searchState.treeId, currentNode.node.nodeId));
890
+ return;
891
+ }
892
+ const childrenNodes = selectNgssmTreeNodeChildren(state, searchState.treeId, currentNode.node.nodeId);
893
+ const matching = [];
894
+ const toProcess = [];
895
+ childrenNodes.forEach((node) => {
896
+ const fullPath = `${node.parentFullPath}/${node.node.label}`;
897
+ if (defaultRegexEditorValidator.isMatch(searchState.searchPattern ?? "", fullPath)) matching.push(node);
898
+ if (node.node.isExpandable) toProcess.push(node);
899
+ });
900
+ actiondispatcher.dispatchAction(new RegisterPartialSearchResultsAction(matching, toProcess));
901
+ break;
902
+ }
903
+ }
904
+ }
905
+ closeDialog() {
906
+ this.dialog?.close();
907
+ this.dialog = void 0;
908
+ }
909
+ static ɵfac = i0.ɵɵngDeclareFactory({
910
+ minVersion: "12.0.0",
911
+ version: "22.2.0",
912
+ ngImport: i0,
913
+ type: TreeNodesSearchingEffect,
914
+ deps: [],
915
+ target: i0.ɵɵFactoryTarget.Injectable
916
+ });
917
+ static ɵprov = i0.ɵɵngDeclareInjectable({
918
+ minVersion: "12.0.0",
919
+ version: "22.2.0",
920
+ ngImport: i0,
921
+ type: TreeNodesSearchingEffect
922
+ });
923
+ };
924
+ i0.ɵɵngDeclareClassMetadata({
925
+ minVersion: "12.0.0",
926
+ version: "22.2.0",
927
+ ngImport: i0,
928
+ type: TreeNodesSearchingEffect,
929
+ decorators: [{ type: Injectable }]
930
+ });
931
+ var TreeNodeExpandReducer = class TreeNodeExpandReducer {
932
+ processedActions = [
933
+ NgssmTreeActionType.expandNode,
934
+ NgssmTreeActionType.collapseNode,
935
+ NgssmTreeActionType.selectNode,
936
+ NgssmTreeActionType.loadChildrenOfNode
937
+ ];
938
+ updateState(state, action) {
939
+ switch (action.type) {
940
+ case NgssmTreeActionType.expandNode: {
941
+ const expandNodeAction = action;
942
+ return updateNgssmTreeState(state, { trees: { [expandNodeAction.treeId]: { nodes: { $apply: (nodes) => {
943
+ const result = [...nodes];
944
+ const index = result.findIndex((n) => n.node.nodeId === expandNodeAction.nodeId);
945
+ if (index !== -1) {
946
+ let item = result[index];
947
+ if (item.status === DataStatus.loaded) item = update(result[index], { isExpanded: { $set: true } });
948
+ else item = update(result[index], {
949
+ isExpanded: { $set: true },
950
+ status: { $set: DataStatus.loading }
951
+ });
952
+ result.splice(index, 1, item);
953
+ }
954
+ return result;
955
+ } } } } });
956
+ }
957
+ case NgssmTreeActionType.collapseNode: {
958
+ const collapseNodeAction = action;
959
+ return updateNgssmTreeState(state, { trees: { [collapseNodeAction.treeId]: { nodes: { $apply: (nodes) => {
960
+ const result = [...nodes];
961
+ const index = result.findIndex((n) => n.node.nodeId === collapseNodeAction.nodeId);
962
+ if (index !== -1) {
963
+ const item = update(result[index], { isExpanded: { $set: false } });
964
+ result.splice(index, 1, item);
965
+ }
966
+ return result;
967
+ } } } } });
968
+ }
969
+ case NgssmTreeActionType.selectNode: {
970
+ const selectNodeAction = action;
971
+ if (selectNgssmTreeState(state).trees[selectNodeAction.treeId].nodes.find((n) => n.node.nodeId === selectNodeAction.nodeId)?.status === DataStatus.loaded) break;
972
+ return updateNgssmTreeState(state, { trees: { [selectNodeAction.treeId]: { nodes: { $apply: (nodes) => {
973
+ const result = [...nodes];
974
+ const index = result.findIndex((n) => n.node.nodeId === selectNodeAction.nodeId);
975
+ if (index !== -1) {
976
+ const item = update(result[index], { status: { $set: DataStatus.loading } });
977
+ result.splice(index, 1, item);
978
+ }
979
+ return result;
980
+ } } } } });
981
+ }
982
+ case NgssmTreeActionType.loadChildrenOfNode: {
983
+ const loadChildrenOfNodeAction = action;
984
+ return updateNgssmTreeState(state, { trees: { [loadChildrenOfNodeAction.treeId]: { nodes: { $apply: (nodes) => {
985
+ const result = [...nodes];
986
+ const index = result.findIndex((n) => n.node.nodeId === loadChildrenOfNodeAction.nodeId);
987
+ if (index !== -1) {
988
+ let item = result[index];
989
+ if (item.status !== DataStatus.loaded) item = update(result[index], { status: { $set: DataStatus.loading } });
990
+ result.splice(index, 1, item);
991
+ }
992
+ return result;
993
+ } } } } });
994
+ }
995
+ }
996
+ return state;
997
+ }
998
+ static ɵfac = i0.ɵɵngDeclareFactory({
999
+ minVersion: "12.0.0",
1000
+ version: "22.2.0",
1001
+ ngImport: i0,
1002
+ type: TreeNodeExpandReducer,
1003
+ deps: [],
1004
+ target: i0.ɵɵFactoryTarget.Injectable
1005
+ });
1006
+ static ɵprov = i0.ɵɵngDeclareInjectable({
1007
+ minVersion: "12.0.0",
1008
+ version: "22.2.0",
1009
+ ngImport: i0,
1010
+ type: TreeNodeExpandReducer
1011
+ });
1012
+ };
1013
+ i0.ɵɵngDeclareClassMetadata({
1014
+ minVersion: "12.0.0",
1015
+ version: "22.2.0",
1016
+ ngImport: i0,
1017
+ type: TreeNodeExpandReducer,
1018
+ decorators: [{ type: Injectable }]
1019
+ });
1020
+ var TreeNodeSelectionReducer = class TreeNodeSelectionReducer {
1021
+ processedActions = [NgssmTreeActionType.selectNode];
1022
+ updateState(state, action) {
1023
+ switch (action.type) {
1024
+ case NgssmTreeActionType.selectNode: {
1025
+ const selectNodeAction = action;
1026
+ return updateNgssmTreeState(state, { trees: { [selectNodeAction.treeId]: { selectedNode: { $set: selectNodeAction.nodeId } } } });
1027
+ }
1028
+ }
1029
+ return state;
1030
+ }
1031
+ static ɵfac = i0.ɵɵngDeclareFactory({
1032
+ minVersion: "12.0.0",
1033
+ version: "22.2.0",
1034
+ ngImport: i0,
1035
+ type: TreeNodeSelectionReducer,
1036
+ deps: [],
1037
+ target: i0.ɵɵFactoryTarget.Injectable
1038
+ });
1039
+ static ɵprov = i0.ɵɵngDeclareInjectable({
1040
+ minVersion: "12.0.0",
1041
+ version: "22.2.0",
1042
+ ngImport: i0,
1043
+ type: TreeNodeSelectionReducer
1044
+ });
1045
+ };
1046
+ i0.ɵɵngDeclareClassMetadata({
1047
+ minVersion: "12.0.0",
1048
+ version: "22.2.0",
1049
+ ngImport: i0,
1050
+ type: TreeNodeSelectionReducer,
1051
+ decorators: [{ type: Injectable }]
1052
+ });
1053
+ var TreeNodesSearchReducer = class TreeNodesSearchReducer {
1054
+ processedActions = [
1055
+ NgssmTreeActionType.displaySearchDialog,
1056
+ NgssmTreeActionType.closeSearchDialog,
1057
+ NgssmTreeActionType.searchTreeNodes,
1058
+ NgssmTreeActionType.registerPartialSearchResults,
1059
+ NgssmTreeActionType.abortTreeNodesSearch
1060
+ ];
1061
+ updateState(state, action) {
1062
+ switch (action.type) {
1063
+ case NgssmTreeActionType.displaySearchDialog: {
1064
+ const displaySearchDialogAction = action;
1065
+ const path = getNgssmTreePath(selectNgssmTreeState(state).trees[displaySearchDialogAction.treeId], displaySearchDialogAction.startNodeId);
1066
+ return updateNgssmTreeState(state, { treeNodesSearch: {
1067
+ treeId: { $set: displaySearchDialogAction.treeId },
1068
+ rootSearchNodeId: { $set: displaySearchDialogAction.startNodeId },
1069
+ rootSearchPath: { $set: path.map((p) => p.node.label).join("/") }
1070
+ } });
1071
+ }
1072
+ case NgssmTreeActionType.closeSearchDialog: return updateNgssmTreeState(state, { treeNodesSearch: { $set: getDefaultTreeNodesSearch() } });
1073
+ case NgssmTreeActionType.searchTreeNodes: {
1074
+ const searchTreeNodesAction = action;
1075
+ const startNode = selectNgssmTreeNode(state, selectNgssmTreeState(state).treeNodesSearch.treeId ?? "", selectNgssmTreeState(state).treeNodesSearch.rootSearchNodeId ?? "");
1076
+ const toBeProcess = [];
1077
+ if (startNode) toBeProcess.push({
1078
+ nodeId: startNode.node.nodeId,
1079
+ fullPath: getNgssmTreeNodeFullPath(startNode)
1080
+ });
1081
+ return updateNgssmTreeState(state, { treeNodesSearch: {
1082
+ searchPattern: { $set: searchTreeNodesAction.searchPattern },
1083
+ searchStatus: { $set: SearchStatus.inProgress },
1084
+ toProcess: { $set: toBeProcess },
1085
+ matchingNodes: { $set: [] }
1086
+ } });
1087
+ }
1088
+ case NgssmTreeActionType.registerPartialSearchResults: {
1089
+ const registerPartialSearchResultsAction = action;
1090
+ const toProcess = selectNgssmTreeState(state).treeNodesSearch.toProcess.slice(1);
1091
+ toProcess.push(...registerPartialSearchResultsAction.nodesToProcess.map((n) => ({
1092
+ nodeId: n.node.nodeId,
1093
+ fullPath: getNgssmTreeNodeFullPath(n)
1094
+ })));
1095
+ return updateNgssmTreeState(state, { treeNodesSearch: {
1096
+ searchStatus: { $apply: (value) => {
1097
+ if (toProcess.length === 0) return SearchStatus.done;
1098
+ return value;
1099
+ } },
1100
+ toProcess: { $set: toProcess },
1101
+ matchingNodes: { $push: registerPartialSearchResultsAction.matchingNodes.map((n) => n.node.nodeId) }
1102
+ } });
1103
+ }
1104
+ case NgssmTreeActionType.abortTreeNodesSearch: return updateNgssmTreeState(state, { treeNodesSearch: {
1105
+ searchStatus: { $set: SearchStatus.aborted },
1106
+ toProcess: { $set: [] }
1107
+ } });
1108
+ }
1109
+ return state;
1110
+ }
1111
+ static ɵfac = i0.ɵɵngDeclareFactory({
1112
+ minVersion: "12.0.0",
1113
+ version: "22.2.0",
1114
+ ngImport: i0,
1115
+ type: TreeNodesSearchReducer,
1116
+ deps: [],
1117
+ target: i0.ɵɵFactoryTarget.Injectable
1118
+ });
1119
+ static ɵprov = i0.ɵɵngDeclareInjectable({
1120
+ minVersion: "12.0.0",
1121
+ version: "22.2.0",
1122
+ ngImport: i0,
1123
+ type: TreeNodesSearchReducer
1124
+ });
1125
+ };
1126
+ i0.ɵɵngDeclareClassMetadata({
1127
+ minVersion: "12.0.0",
1128
+ version: "22.2.0",
1129
+ ngImport: i0,
1130
+ type: TreeNodesSearchReducer,
1131
+ decorators: [{ type: Injectable }]
1132
+ });
1133
+ var TreeNodesReducer = class TreeNodesReducer {
1134
+ processedActions = [NgssmTreeActionType.registerNodes];
1135
+ updateState(state, action) {
1136
+ switch (action.type) {
1137
+ case NgssmTreeActionType.registerNodes: {
1138
+ const registerNodesAction = action;
1139
+ return updateNgssmTreeState(state, { trees: { [registerNodesAction.treeId]: { nodes: { $apply: (nodes) => {
1140
+ const index = nodes.findIndex((n) => n.node.nodeId === registerNodesAction.parentNodeId);
1141
+ if (index === -1) return nodes;
1142
+ return [
1143
+ ...nodes.slice(0, index),
1144
+ update(nodes[index], { status: { $set: registerNodesAction.dataStatus } }),
1145
+ ...registerNodesAction.nodes.map((i) => ({
1146
+ status: DataStatus.none,
1147
+ isExpanded: false,
1148
+ level: nodes[index].level + 1,
1149
+ node: i,
1150
+ parentFullPath: nodes[index].parentFullPath !== void 0 ? `${nodes[index].parentFullPath}/${nodes[index].node.label}` : nodes[index].node.label
1151
+ })),
1152
+ ...nodes.slice(index + 1)
1153
+ ];
1154
+ } } } } });
1155
+ }
1156
+ }
1157
+ return state;
1158
+ }
1159
+ static ɵfac = i0.ɵɵngDeclareFactory({
1160
+ minVersion: "12.0.0",
1161
+ version: "22.2.0",
1162
+ ngImport: i0,
1163
+ type: TreeNodesReducer,
1164
+ deps: [],
1165
+ target: i0.ɵɵFactoryTarget.Injectable
1166
+ });
1167
+ static ɵprov = i0.ɵɵngDeclareInjectable({
1168
+ minVersion: "12.0.0",
1169
+ version: "22.2.0",
1170
+ ngImport: i0,
1171
+ type: TreeNodesReducer
1172
+ });
1173
+ };
1174
+ i0.ɵɵngDeclareClassMetadata({
1175
+ minVersion: "12.0.0",
1176
+ version: "22.2.0",
1177
+ ngImport: i0,
1178
+ type: TreeNodesReducer,
1179
+ decorators: [{ type: Injectable }]
1180
+ });
1181
+ var TreesReducer = class TreesReducer {
1182
+ processedActions = [NgssmTreeActionType.initNgssmTree, NgssmTreeActionType.deleteNgssmTree];
1183
+ updateState(state, action) {
1184
+ switch (action.type) {
1185
+ case NgssmTreeActionType.initNgssmTree: {
1186
+ const initNgssmTreeAction = action;
1187
+ return updateNgssmTreeState(state, { trees: { [initNgssmTreeAction.treeId]: { $set: {
1188
+ nodes: [{
1189
+ status: DataStatus.none,
1190
+ isExpanded: false,
1191
+ level: 0,
1192
+ node: initNgssmTreeAction.root
1193
+ }],
1194
+ type: initNgssmTreeAction.treeType
1195
+ } } } });
1196
+ }
1197
+ case NgssmTreeActionType.deleteNgssmTree: return updateNgssmTreeState(state, { trees: { $unset: [action.treeId] } });
1198
+ }
1199
+ return state;
1200
+ }
1201
+ static ɵfac = i0.ɵɵngDeclareFactory({
1202
+ minVersion: "12.0.0",
1203
+ version: "22.2.0",
1204
+ ngImport: i0,
1205
+ type: TreesReducer,
1206
+ deps: [],
1207
+ target: i0.ɵɵFactoryTarget.Injectable
1208
+ });
1209
+ static ɵprov = i0.ɵɵngDeclareInjectable({
1210
+ minVersion: "12.0.0",
1211
+ version: "22.2.0",
1212
+ ngImport: i0,
1213
+ type: TreesReducer
1214
+ });
1215
+ };
1216
+ i0.ɵɵngDeclareClassMetadata({
1217
+ minVersion: "12.0.0",
1218
+ version: "22.2.0",
1219
+ ngImport: i0,
1220
+ type: TreesReducer,
1221
+ decorators: [{ type: Injectable }]
1222
+ });
863
1223
  const provideNgssmTree = () => {
864
- return makeEnvironmentProviders([
865
- provideReducers(TreeNodeExpandReducer, TreeNodeSelectionReducer, TreeNodesSearchReducer, TreeNodesReducer, TreesReducer),
866
- provideEffects(TreeNodeLoadingEffect, TreeNodesSearchingEffect)
867
- ]);
1224
+ return makeEnvironmentProviders([provideReducers(TreeNodeExpandReducer, TreeNodeSelectionReducer, TreeNodesSearchReducer, TreeNodesReducer, TreesReducer), provideEffects(TreeNodeLoadingEffect, TreeNodesSearchingEffect)]);
868
1225
  };
869
-
870
- /*
871
- * Public API Surface of ngssm-tree
872
- */
873
-
874
- /**
875
- * Generated bundle index. Do not edit.
876
- */
877
-
878
1226
  export { CollapseNodeAction, DeleteNgssmTreeAction, DisplaySearchDialogAction, ExpandNodeAction, InitNgssmTreeAction, LoadChildrenOfNodeAction, NGSSM_TREE_DATA_SERVICE, NgssmBreadcrumbComponent, NgssmTreeActionType, NgssmTreeComponent, NgssmTreeSearchDialogComponent, NgssmTreeStateSpecification, RegisterNodesAction, RegisterPartialSearchResultsAction, SearchStatus, SearchTreeNodesAction, SelectNodeAction, TreeAction, TreeNodeAction, getDefaultTreeNodesSearch, getNgssmTreeNodeFullPath, getNgssmTreePath, provideNgssmTree, selectNgssmTreeNode, selectNgssmTreeNodeChildren, selectNgssmTreeState, updateNgssmTreeState };
879
- //# sourceMappingURL=ngssm-tree.mjs.map
1227
+
1228
+ //# sourceMappingURL=ngssm-tree.mjs.map