ngssm-tree 19.3.0 → 19.3.2

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,35 +1,34 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, Inject, Optional, Injectable, Input, ChangeDetectionStrategy, Component, ViewContainerRef, ViewChild, makeEnvironmentProviders, EventEmitter, Output } from '@angular/core';
2
+ import { InjectionToken, Inject, Optional, Injectable, inject, signal, input, effect, untracked, ChangeDetectionStrategy, Component, ChangeDetectorRef, viewChild, ViewContainerRef, makeEnvironmentProviders, ElementRef, output } from '@angular/core';
3
3
  import * as i1 from 'ngssm-store';
4
- import { NgSsmFeatureState, NgSsmComponent, provideReducers, provideEffects } from 'ngssm-store';
4
+ import { NgSsmFeatureState, Store, createSignal, provideReducers, provideEffects } from 'ngssm-store';
5
5
  import { DataStatus } from 'ngssm-remote-data';
6
6
  import { __decorate } from 'tslib';
7
7
  import update from 'immutability-helper';
8
8
  import { defaultRegexEditorValidator, NgssmComponentDisplayDirective } from 'ngssm-toolkit';
9
- import * as i2 from '@angular/common';
9
+ import * as i1$1 from '@angular/common';
10
10
  import { CommonModule } from '@angular/common';
11
- import * as i3 from '@angular/cdk/scrolling';
11
+ import * as i2 from '@angular/cdk/scrolling';
12
12
  import { ScrollingModule } from '@angular/cdk/scrolling';
13
- import * as i4 from '@angular/material/card';
14
- import { MatCardModule } from '@angular/material/card';
15
- import * as i3$1 from '@angular/material/icon';
16
- import { MatIconModule } from '@angular/material/icon';
17
- import * as i6 from '@angular/material/progress-spinner';
13
+ import * as i6 from '@angular/material/card';
14
+ import { MatCardModule, MatCard, MatCardContent } from '@angular/material/card';
15
+ import * as i1$2 from '@angular/material/icon';
16
+ import { MatIconModule, MatIcon } from '@angular/material/icon';
17
+ import * as i5 from '@angular/material/progress-spinner';
18
18
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
19
- import { BehaviorSubject, combineLatest, take, filter, takeUntil, switchMap, Subject } from 'rxjs';
20
- import * as i4$1 from '@angular/material/button';
19
+ import * as i2$1 from '@angular/material/button';
21
20
  import { MatButtonModule } from '@angular/material/button';
22
- import * as i3$2 from '@angular/forms';
23
- import { FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
24
- import * as i6$1 from '@angular/material/dialog';
21
+ import * as i1$3 from '@angular/forms';
22
+ import { FormControl, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
23
+ import * as i4 from '@angular/material/dialog';
25
24
  import { MatDialogModule } from '@angular/material/dialog';
26
- import * as i4$2 from '@angular/material/form-field';
25
+ import * as i2$2 from '@angular/material/form-field';
27
26
  import { MatFormFieldModule } from '@angular/material/form-field';
28
- import * as i5 from '@angular/material/input';
27
+ import * as i3 from '@angular/material/input';
29
28
  import { MatInputModule } from '@angular/material/input';
30
- import * as i5$1 from '@angular/material/divider';
31
- import { MatDividerModule } from '@angular/material/divider';
32
- import * as i4$3 from '@angular/material/menu';
29
+ import * as i3$1 from '@angular/material/divider';
30
+ import { MatDividerModule, MatDivider } from '@angular/material/divider';
31
+ import * as i2$3 from '@angular/material/menu';
33
32
  import { MatMenuModule } from '@angular/material/menu';
34
33
 
35
34
  var NgssmTreeActionType;
@@ -225,10 +224,10 @@ class TreeNodeLoadingEffect {
225
224
  }
226
225
  });
227
226
  }
228
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodeLoadingEffect, deps: [{ token: NGSSM_TREE_DATA_SERVICE, optional: true }, { token: i1.Logger }], target: i0.ɵɵFactoryTarget.Injectable }); }
229
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodeLoadingEffect }); }
227
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodeLoadingEffect, deps: [{ token: NGSSM_TREE_DATA_SERVICE, optional: true }, { token: i1.Logger }], target: i0.ɵɵFactoryTarget.Injectable }); }
228
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodeLoadingEffect }); }
230
229
  }
231
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodeLoadingEffect, decorators: [{
230
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodeLoadingEffect, decorators: [{
232
231
  type: Injectable
233
232
  }], ctorParameters: () => [{ type: undefined, decorators: [{
234
233
  type: Inject,
@@ -237,129 +236,128 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImpor
237
236
  type: Optional
238
237
  }] }, { type: i1.Logger }] });
239
238
 
240
- class NgssmTreeComponent extends NgSsmComponent {
241
- constructor(store) {
242
- super(store);
243
- this._treeConfig$ = new BehaviorSubject(undefined);
244
- this._displayedItems$ = new BehaviorSubject([]);
245
- this._selectedNodeId$ = new BehaviorSubject(undefined);
239
+ class NgssmTreeComponent {
240
+ constructor() {
241
+ this.store = inject(Store);
242
+ this.trees = createSignal((state) => selectNgssmTreeState(state).trees);
243
+ this.tree = signal(undefined);
244
+ this.treeConfig = input();
246
245
  this.dataStatus = DataStatus;
247
- }
248
- set treeConfig(value) {
249
- if (value) {
250
- this._treeConfig$.next({ ...value });
251
- this.treeSubscription?.unsubscribe();
252
- this.treeSubscription = this.watch((s) => selectNgssmTreeState(s).trees[value.treeId]).subscribe((tree) => {
253
- const config = this._treeConfig$.getValue();
254
- if (!tree || !config) {
255
- this._displayedItems$.next([]);
256
- return;
246
+ this.displayedItems = signal([]);
247
+ this.selectedNodeId = signal(undefined);
248
+ effect(() => {
249
+ const currentConfig = this.treeConfig();
250
+ const currentTrees = this.trees();
251
+ if (currentConfig) {
252
+ this.tree.set(currentTrees[currentConfig.treeId]);
253
+ }
254
+ else {
255
+ this.tree.set(undefined);
256
+ }
257
+ });
258
+ effect(() => {
259
+ const currentTree = this.tree();
260
+ const config = untracked(() => this.treeConfig());
261
+ if (!currentTree || !config) {
262
+ this.displayedItems.set([]);
263
+ return;
264
+ }
265
+ const alwaysTrue = () => true;
266
+ const filter = config.filter ?? alwaysTrue;
267
+ const canSearch = config.canSearch ?? alwaysTrue;
268
+ const items = [];
269
+ let hiddenLevel = -1;
270
+ const nodesToFindSelected = new Map();
271
+ (currentTree.nodes ?? []).forEach((t) => {
272
+ if (t.node.isExpandable && t.isExpanded === false && hiddenLevel === -1) {
273
+ hiddenLevel = t.level;
257
274
  }
258
- const alwaysTrue = () => true;
259
- const filter = config.filter ?? alwaysTrue;
260
- const canSearch = config.canSearch ?? alwaysTrue;
261
- const items = [];
262
- let hiddenLevel = -1;
263
- const nodesToFindSelected = new Map();
264
- (tree.nodes ?? []).forEach((t) => {
265
- if (t.node.isExpandable && t.isExpanded === false && hiddenLevel === -1) {
266
- hiddenLevel = t.level;
267
- }
268
- if (hiddenLevel === -1 || t.level <= hiddenLevel) {
269
- if (filter(t.node)) {
270
- items.push({
271
- node: t,
272
- canSearch: canSearch(t.node)
273
- });
274
- nodesToFindSelected.set(t.node.nodeId, { isDisplayed: true, node: t });
275
- }
275
+ if (hiddenLevel === -1 || t.level <= hiddenLevel) {
276
+ if (filter(t.node)) {
277
+ items.push({
278
+ node: t,
279
+ canSearch: canSearch(t.node)
280
+ });
281
+ nodesToFindSelected.set(t.node.nodeId, { isDisplayed: true, node: t });
276
282
  }
277
- if (t.node.isExpandable && t.level <= hiddenLevel) {
278
- hiddenLevel = t.isExpanded === true ? -1 : t.level;
279
- }
280
- if (!nodesToFindSelected.has(t.node.nodeId)) {
281
- nodesToFindSelected.set(t.node.nodeId, { isDisplayed: false, node: t });
282
- }
283
- });
284
- this._displayedItems$.next(items);
285
- let selectedNode = tree.selectedNode;
286
- if (!selectedNode) {
287
- this._selectedNodeId$.next(undefined);
288
283
  }
289
- else {
290
- while (selectedNode) {
291
- const item = nodesToFindSelected.get(selectedNode);
292
- if (item?.isDisplayed !== true) {
293
- selectedNode = item?.node.node.parentNodeId;
294
- }
295
- else {
296
- break;
297
- }
298
- }
299
- this._selectedNodeId$.next(selectedNode);
284
+ if (t.node.isExpandable && t.level <= hiddenLevel) {
285
+ hiddenLevel = t.isExpanded === true ? -1 : t.level;
286
+ }
287
+ if (!nodesToFindSelected.has(t.node.nodeId)) {
288
+ nodesToFindSelected.set(t.node.nodeId, { isDisplayed: false, node: t });
300
289
  }
301
290
  });
302
- }
303
- }
304
- get treeConfig$() {
305
- return this._treeConfig$.asObservable();
306
- }
307
- get displayedItems$() {
308
- return this._displayedItems$.asObservable();
309
- }
310
- get selectedNodeId$() {
311
- return this._selectedNodeId$.asObservable();
291
+ this.displayedItems.set(items);
292
+ let selectedNode = currentTree.selectedNode;
293
+ if (!selectedNode) {
294
+ this.selectedNodeId.set(undefined);
295
+ }
296
+ else {
297
+ while (selectedNode) {
298
+ const item = nodesToFindSelected.get(selectedNode);
299
+ if (item?.isDisplayed !== true) {
300
+ selectedNode = item?.node.node.parentNodeId;
301
+ }
302
+ else {
303
+ break;
304
+ }
305
+ }
306
+ this.selectedNodeId.set(selectedNode);
307
+ }
308
+ });
312
309
  }
313
310
  getItemId(_, node) {
314
311
  return node.node.node.nodeId;
315
312
  }
316
313
  expand(node) {
317
- const treeId = this._treeConfig$.getValue()?.treeId;
314
+ const treeId = this.treeConfig()?.treeId;
318
315
  if (treeId) {
319
- this.dispatchAction(new ExpandNodeAction(treeId, node.node.nodeId));
316
+ this.store.dispatchAction(new ExpandNodeAction(treeId, node.node.nodeId));
320
317
  }
321
318
  }
322
319
  collapse(node) {
323
- const treeId = this._treeConfig$.getValue()?.treeId;
320
+ const treeId = this.treeConfig()?.treeId;
324
321
  if (treeId) {
325
- this.dispatchAction(new CollapseNodeAction(treeId, node.node.nodeId));
322
+ this.store.dispatchAction(new CollapseNodeAction(treeId, node.node.nodeId));
326
323
  }
327
324
  }
328
325
  selectNode(node) {
329
- const treeId = this._treeConfig$.getValue()?.treeId;
326
+ const treeId = this.treeConfig()?.treeId;
330
327
  if (treeId) {
331
- this.dispatchAction(new SelectNodeAction(treeId, node.node.nodeId));
328
+ this.store.dispatchAction(new SelectNodeAction(treeId, node.node.nodeId));
332
329
  }
333
330
  }
334
331
  displaySearchDialog(node) {
335
- const treeId = this._treeConfig$.getValue()?.treeId;
332
+ const treeId = this.treeConfig()?.treeId;
336
333
  if (treeId) {
337
- this.dispatchAction(new DisplaySearchDialogAction(treeId, node.node.nodeId));
334
+ this.store.dispatchAction(new DisplaySearchDialogAction(treeId, node.node.nodeId));
338
335
  }
339
336
  }
340
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: NgssmTreeComponent, deps: [{ token: i1.Store }], target: i0.ɵɵFactoryTarget.Component }); }
341
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.5", type: NgssmTreeComponent, isStandalone: true, selector: "ngssm-tree", inputs: { treeConfig: "treeConfig" }, usesInheritance: true, ngImport: i0, template: "<mat-card class=\"flex-column-stretch fxFlex\">\n <mat-card-content class=\"flex-column-stretch fxFlex\" *ngIf=\"treeConfig$ | async as treeConfig\">\n <cdk-virtual-scroll-viewport itemSize=\"30\" class=\"fxFlex\">\n <div\n *cdkVirtualFor=\"let item of displayedItems$ | async; 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$ | async) === item.node.node.nodeId }\">\n <mat-icon\n class=\"fa-solid fa-chevron-right\"\n *ngIf=\"item.node.node.isExpandable && item.node.isExpanded === false && item.node.status !== dataStatus.loading\"\n (click)=\"$event.stopPropagation(); expand(item.node)\"></mat-icon>\n <mat-icon\n class=\"fa-solid fa-chevron-down\"\n *ngIf=\"item.node.node.isExpandable && item.node.isExpanded && item.node.status !== dataStatus.loading\"\n (click)=\"$event.stopPropagation(); collapse(item.node)\"></mat-icon>\n <mat-spinner diameter=\"20\" *ngIf=\"item.node.node.isExpandable && item.node.status === dataStatus.loading\"></mat-spinner>\n <span *ngIf=\"!item.node.node.isExpandable\" class=\"not-expandable-padding\"></span>\n\n <mat-icon class=\"{{ treeConfig.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 <i\n class=\"fa-solid fa-magnifying-glass search-icon\"\n *ngIf=\"item.canSearch\"\n (click)=\"$event.stopPropagation(); displaySearchDialog(item.node)\">\n </i>\n </div>\n </cdk-virtual-scroll-viewport>\n </mat-card-content>\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: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i3.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i3.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i3.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i4.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i4.MatCardContent, selector: "mat-card-content" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i6.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
337
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: NgssmTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
338
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", 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$1.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: i1$2.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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
342
339
  }
343
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: NgssmTreeComponent, decorators: [{
340
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: NgssmTreeComponent, decorators: [{
344
341
  type: Component,
345
- args: [{ selector: 'ngssm-tree', imports: [CommonModule, ScrollingModule, MatCardModule, MatIconModule, MatProgressSpinnerModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<mat-card class=\"flex-column-stretch fxFlex\">\n <mat-card-content class=\"flex-column-stretch fxFlex\" *ngIf=\"treeConfig$ | async as treeConfig\">\n <cdk-virtual-scroll-viewport itemSize=\"30\" class=\"fxFlex\">\n <div\n *cdkVirtualFor=\"let item of displayedItems$ | async; 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$ | async) === item.node.node.nodeId }\">\n <mat-icon\n class=\"fa-solid fa-chevron-right\"\n *ngIf=\"item.node.node.isExpandable && item.node.isExpanded === false && item.node.status !== dataStatus.loading\"\n (click)=\"$event.stopPropagation(); expand(item.node)\"></mat-icon>\n <mat-icon\n class=\"fa-solid fa-chevron-down\"\n *ngIf=\"item.node.node.isExpandable && item.node.isExpanded && item.node.status !== dataStatus.loading\"\n (click)=\"$event.stopPropagation(); collapse(item.node)\"></mat-icon>\n <mat-spinner diameter=\"20\" *ngIf=\"item.node.node.isExpandable && item.node.status === dataStatus.loading\"></mat-spinner>\n <span *ngIf=\"!item.node.node.isExpandable\" class=\"not-expandable-padding\"></span>\n\n <mat-icon class=\"{{ treeConfig.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 <i\n class=\"fa-solid fa-magnifying-glass search-icon\"\n *ngIf=\"item.canSearch\"\n (click)=\"$event.stopPropagation(); displaySearchDialog(item.node)\">\n </i>\n </div>\n </cdk-virtual-scroll-viewport>\n </mat-card-content>\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"] }]
346
- }], ctorParameters: () => [{ type: i1.Store }], propDecorators: { treeConfig: [{
347
- type: Input
348
- }] } });
342
+ args: [{ selector: 'ngssm-tree', imports: [CommonModule, ScrollingModule, MatCardModule, MatIconModule, MatProgressSpinnerModule], changeDetection: ChangeDetectionStrategy.OnPush, 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"] }]
343
+ }], ctorParameters: () => [] });
349
344
 
350
- class NgssmBreadcrumbComponent extends NgSsmComponent {
351
- constructor(store) {
352
- super(store);
353
- this._treeId$ = new BehaviorSubject(undefined);
354
- this._nodes$ = new BehaviorSubject([]);
355
- combineLatest([this._treeId$, this.watch((s) => selectNgssmTreeState(s))]).subscribe((values) => {
356
- if (!values[0]) {
357
- this._nodes$.next([]);
345
+ class NgssmBreadcrumbComponent {
346
+ constructor() {
347
+ this.store = inject(Store);
348
+ this.treeState = createSignal((state) => selectNgssmTreeState(state));
349
+ this.treeId = input(undefined);
350
+ this.nodes = signal([]);
351
+ effect(() => {
352
+ const currentTreeId = this.treeId();
353
+ if (!currentTreeId) {
354
+ this.nodes.set([]);
358
355
  return;
359
356
  }
360
- const tree = values[1]?.trees[values[0]];
357
+ const state = this.treeState();
358
+ const tree = state?.trees[currentTreeId];
361
359
  if (!tree) {
362
- this._nodes$.next([]);
360
+ this.nodes.set([]);
363
361
  return;
364
362
  }
365
363
  const nodesPerId = new Map(tree.nodes.map((n) => [n.node.nodeId, n.node]));
@@ -372,70 +370,50 @@ class NgssmBreadcrumbComponent extends NgSsmComponent {
372
370
  if (path.length === 0 && tree.nodes.length > 0) {
373
371
  path.push(tree.nodes[0]?.node);
374
372
  }
375
- this._nodes$.next(path);
373
+ this.nodes.set(path);
376
374
  });
377
375
  }
378
- set treeId(value) {
379
- this._treeId$.next(value);
380
- }
381
- get nodes$() {
382
- return this._nodes$.asObservable();
383
- }
384
376
  selectNode(node) {
385
- const treeId = this._treeId$.getValue();
377
+ const treeId = this.treeId();
386
378
  if (treeId) {
387
- this.dispatchAction(new SelectNodeAction(treeId, node.nodeId));
379
+ this.store.dispatchAction(new SelectNodeAction(treeId, node.nodeId));
388
380
  }
389
381
  }
390
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: NgssmBreadcrumbComponent, deps: [{ token: i1.Store }], target: i0.ɵɵFactoryTarget.Component }); }
391
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.5", type: NgssmBreadcrumbComponent, isStandalone: true, selector: "ngssm-breadcrumb", inputs: { treeId: "treeId" }, usesInheritance: true, ngImport: i0, template: "<div class=\"flex-row-center\">\n <mat-icon class=\"fa-solid fa-folder-tree\" color=\"primary\"></mat-icon>\n <span *ngFor=\"let node of nodes$ | async; last as last\" class=\"flex-row-center\">\n\n <button mat-button [disabled]=\"last\" (click)=\"selectNode(node)\">\n {{node.label}}\n </button>\n\n <div class=\"ngssm-breadcrumb-separator\" *ngIf=\"!last\">/</div>\n </span>\n</div>", styles: [".ngssm-breadcrumb-separator{font-weight:700}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
382
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: NgssmBreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
383
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", 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: CommonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
392
384
  }
393
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: NgssmBreadcrumbComponent, decorators: [{
385
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: NgssmBreadcrumbComponent, decorators: [{
394
386
  type: Component,
395
- args: [{ selector: 'ngssm-breadcrumb', imports: [CommonModule, MatIconModule, MatButtonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex-row-center\">\n <mat-icon class=\"fa-solid fa-folder-tree\" color=\"primary\"></mat-icon>\n <span *ngFor=\"let node of nodes$ | async; last as last\" class=\"flex-row-center\">\n\n <button mat-button [disabled]=\"last\" (click)=\"selectNode(node)\">\n {{node.label}}\n </button>\n\n <div class=\"ngssm-breadcrumb-separator\" *ngIf=\"!last\">/</div>\n </span>\n</div>", styles: [".ngssm-breadcrumb-separator{font-weight:700}\n"] }]
396
- }], ctorParameters: () => [{ type: i1.Store }], propDecorators: { treeId: [{
397
- type: Input
398
- }] } });
387
+ args: [{ selector: 'ngssm-breadcrumb', imports: [CommonModule, MatIconModule, MatButtonModule], changeDetection: ChangeDetectionStrategy.OnPush, 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"] }]
388
+ }], ctorParameters: () => [] });
399
389
 
400
- class NgssmTreeSearchDialogComponent extends NgSsmComponent {
401
- constructor(store, dataServices, changeDetectorRef) {
402
- super(store);
403
- this.dataServices = dataServices;
404
- this.changeDetectorRef = changeDetectorRef;
405
- this._currentSearchedPath$ = new BehaviorSubject('');
390
+ class NgssmTreeSearchDialogComponent {
391
+ constructor() {
392
+ this.store = inject(Store);
393
+ this.changeDetectorRef = inject(ChangeDetectorRef);
394
+ this.dataServices = inject(NGSSM_TREE_DATA_SERVICE, {
395
+ optional: true
396
+ });
397
+ this.resultsViewerContainer = viewChild('resultsViewerContainer', { read: ViewContainerRef });
406
398
  this.searchStatus = SearchStatus;
407
- this.searchRootPathControl = new FormControl(undefined);
399
+ this.searchRootPath = createSignal((state) => selectNgssmTreeState(state).treeNodesSearch.rootSearchPath ?? '');
400
+ this.currentSearchedPath = createSignal((state) => selectNgssmTreeState(state).treeNodesSearch.toProcess[0]?.fullPath ?? '');
401
+ this.currentSearchStatus = createSignal((state) => selectNgssmTreeState(state).treeNodesSearch.searchStatus);
408
402
  this.searchPatternControl = new FormControl(undefined, [
409
403
  Validators.required,
410
404
  (c) => this.validatedRegex(c)
411
405
  ]);
412
- this.watch((s) => selectNgssmTreeState(s).treeNodesSearch.rootSearchPath)
413
- .pipe(take(1))
414
- .subscribe((v) => this.searchRootPathControl.setValue(v));
415
- this.watch((s) => selectNgssmTreeState(s).treeNodesSearch.toProcess[0]).subscribe((node) => {
416
- if (node) {
417
- this._currentSearchedPath$.next(node.fullPath);
418
- }
419
- else {
420
- this._currentSearchedPath$.next('');
406
+ const effectRef = effect(() => {
407
+ const container = this.resultsViewerContainer();
408
+ if (!container) {
409
+ return;
421
410
  }
422
- });
423
- }
424
- get searchStatus$() {
425
- return this.watch((s) => selectNgssmTreeState(s).treeNodesSearch.searchStatus);
426
- }
427
- get currentSearchedPath$() {
428
- return this._currentSearchedPath$.asObservable();
429
- }
430
- ngAfterViewInit() {
431
- this.watch((s) => selectNgssmTreeState(s))
432
- .pipe(take(1))
433
- .subscribe((state) => {
434
- const treeId = state.treeNodesSearch.treeId;
411
+ const treeState = selectNgssmTreeState(this.store.state());
412
+ const treeId = treeState.treeNodesSearch.treeId;
435
413
  if (!treeId) {
436
414
  return;
437
415
  }
438
- const treeType = state.trees[treeId]?.type;
416
+ const treeType = treeState.trees[treeId]?.type;
439
417
  if (!treeType) {
440
418
  return;
441
419
  }
@@ -443,21 +421,22 @@ class NgssmTreeSearchDialogComponent extends NgSsmComponent {
443
421
  if (!dataService?.searchResultViewer) {
444
422
  return;
445
423
  }
446
- this.resultsViewerContainer?.createComponent(dataService.searchResultViewer);
424
+ this.resultsViewerContainer()?.createComponent(dataService.searchResultViewer);
447
425
  this.changeDetectorRef.markForCheck();
426
+ effectRef.destroy();
448
427
  });
449
428
  }
450
429
  close() {
451
- this.dispatchActionType(NgssmTreeActionType.closeSearchDialog);
430
+ this.store.dispatchActionType(NgssmTreeActionType.closeSearchDialog);
452
431
  }
453
432
  search() {
454
433
  const searchPattern = this.searchPatternControl.value;
455
434
  if (searchPattern) {
456
- this.dispatchAction(new SearchTreeNodesAction(searchPattern));
435
+ this.store.dispatchAction(new SearchTreeNodesAction(searchPattern));
457
436
  }
458
437
  }
459
438
  abort() {
460
- this.dispatchActionType(NgssmTreeActionType.abortTreeNodesSearch);
439
+ this.store.dispatchActionType(NgssmTreeActionType.abortTreeNodesSearch);
461
440
  }
462
441
  validatedRegex(control) {
463
442
  const result = defaultRegexEditorValidator.validatePattern(control.value);
@@ -468,13 +447,14 @@ class NgssmTreeSearchDialogComponent extends NgSsmComponent {
468
447
  regex: result.error
469
448
  };
470
449
  }
471
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: NgssmTreeSearchDialogComponent, deps: [{ token: i1.Store }, { token: NGSSM_TREE_DATA_SERVICE, optional: true }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
472
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.5", type: NgssmTreeSearchDialogComponent, isStandalone: true, selector: "ngssm-ngssm-tree-search-dialog", viewQueries: [{ propertyName: "resultsViewerContainer", first: true, predicate: ["resultsViewerContainer"], descendants: true, read: ViewContainerRef }], usesInheritance: true, ngImport: i0, template: "<h1 mat-dialog-title>Tree search dialog</h1>\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 [formControl]=\"searchRootPathControl\">\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 <mat-error *ngIf=\"searchPatternControl.errors?.['regex']\">\n {{searchPatternControl.errors?.['regex']}}\n </mat-error>\n </mat-form-field>\n\n <button mat-stroked-button color=\"primary\" [disabled]=\"searchPatternControl.invalid\" (click)=\"search()\"\n *ngIf=\"(searchStatus$ | async) !== searchStatus.inProgress\">\n <mat-icon class=\"fa-solid fa-magnifying-glass\"></mat-icon>\n Search\n </button>\n\n <button mat-raised-button color=\"accent\" (click)=\"abort()\"\n *ngIf=\"(searchStatus$ | async) === searchStatus.inProgress\">\n <mat-icon class=\"fa-solid fa-ban\"></mat-icon>\n Abort\n </button>\n </mat-card-content>\n <mat-card-footer class=\"flex-row-center\" *ngIf=\"(searchStatus$ | async) === searchStatus.inProgress\">\n <mat-spinner [diameter]=\"20\"></mat-spinner>\n {{ currentSearchedPath$ | async }}\n </mat-card-footer>\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>", styles: [":host{display:flex;flex-direction:column;height:100%}:host .mat-mdc-dialog-content{max-height:unset!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: i6$1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i6$1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i6$1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i4.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i4.MatCardContent, selector: "mat-card-content" }, { kind: "directive", type: i4.MatCardFooter, selector: "mat-card-footer" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i6.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
450
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: NgssmTreeSearchDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
451
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", 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: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.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.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i4.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i4.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { 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: i1$2.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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
473
452
  }
474
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: NgssmTreeSearchDialogComponent, decorators: [{
453
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: NgssmTreeSearchDialogComponent, decorators: [{
475
454
  type: Component,
476
455
  args: [{ selector: 'ngssm-ngssm-tree-search-dialog', imports: [
477
456
  CommonModule,
457
+ FormsModule,
478
458
  ReactiveFormsModule,
479
459
  MatFormFieldModule,
480
460
  MatInputModule,
@@ -483,16 +463,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImpor
483
463
  MatCardModule,
484
464
  MatIconModule,
485
465
  MatProgressSpinnerModule
486
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<h1 mat-dialog-title>Tree search dialog</h1>\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 [formControl]=\"searchRootPathControl\">\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 <mat-error *ngIf=\"searchPatternControl.errors?.['regex']\">\n {{searchPatternControl.errors?.['regex']}}\n </mat-error>\n </mat-form-field>\n\n <button mat-stroked-button color=\"primary\" [disabled]=\"searchPatternControl.invalid\" (click)=\"search()\"\n *ngIf=\"(searchStatus$ | async) !== searchStatus.inProgress\">\n <mat-icon class=\"fa-solid fa-magnifying-glass\"></mat-icon>\n Search\n </button>\n\n <button mat-raised-button color=\"accent\" (click)=\"abort()\"\n *ngIf=\"(searchStatus$ | async) === searchStatus.inProgress\">\n <mat-icon class=\"fa-solid fa-ban\"></mat-icon>\n Abort\n </button>\n </mat-card-content>\n <mat-card-footer class=\"flex-row-center\" *ngIf=\"(searchStatus$ | async) === searchStatus.inProgress\">\n <mat-spinner [diameter]=\"20\"></mat-spinner>\n {{ currentSearchedPath$ | async }}\n </mat-card-footer>\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>", styles: [":host{display:flex;flex-direction:column;height:100%}:host .mat-mdc-dialog-content{max-height:unset!important}\n"] }]
487
- }], ctorParameters: () => [{ type: i1.Store }, { type: undefined, decorators: [{
488
- type: Inject,
489
- args: [NGSSM_TREE_DATA_SERVICE]
490
- }, {
491
- type: Optional
492
- }] }, { type: i0.ChangeDetectorRef }], propDecorators: { resultsViewerContainer: [{
493
- type: ViewChild,
494
- args: ['resultsViewerContainer', { read: ViewContainerRef }]
495
- }] } });
466
+ ], changeDetection: ChangeDetectionStrategy.OnPush, 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"] }]
467
+ }], ctorParameters: () => [] });
496
468
 
497
469
  class TreeNodesSearchingEffect {
498
470
  constructor(matDialog, logger) {
@@ -560,12 +532,12 @@ class TreeNodesSearchingEffect {
560
532
  this.dialog?.close();
561
533
  this.dialog = undefined;
562
534
  }
563
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodesSearchingEffect, deps: [{ token: i6$1.MatDialog }, { token: i1.Logger }], target: i0.ɵɵFactoryTarget.Injectable }); }
564
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodesSearchingEffect }); }
535
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodesSearchingEffect, deps: [{ token: i4.MatDialog }, { token: i1.Logger }], target: i0.ɵɵFactoryTarget.Injectable }); }
536
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodesSearchingEffect }); }
565
537
  }
566
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodesSearchingEffect, decorators: [{
538
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodesSearchingEffect, decorators: [{
567
539
  type: Injectable
568
- }], ctorParameters: () => [{ type: i6$1.MatDialog }, { type: i1.Logger }] });
540
+ }], ctorParameters: () => [{ type: i4.MatDialog }, { type: i1.Logger }] });
569
541
 
570
542
  let TreeNodeExpandReducer$1 = class TreeNodeExpandReducer {
571
543
  constructor() {
@@ -685,10 +657,10 @@ let TreeNodeExpandReducer$1 = class TreeNodeExpandReducer {
685
657
  }
686
658
  return state;
687
659
  }
688
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodeExpandReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
689
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodeExpandReducer }); }
660
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodeExpandReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
661
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodeExpandReducer }); }
690
662
  };
691
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodeExpandReducer$1, decorators: [{
663
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodeExpandReducer$1, decorators: [{
692
664
  type: Injectable
693
665
  }] });
694
666
 
@@ -711,10 +683,10 @@ class TreeNodeSelectionReducer {
711
683
  }
712
684
  return state;
713
685
  }
714
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodeSelectionReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
715
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodeSelectionReducer }); }
686
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodeSelectionReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
687
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodeSelectionReducer }); }
716
688
  }
717
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodeSelectionReducer, decorators: [{
689
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodeSelectionReducer, decorators: [{
718
690
  type: Injectable
719
691
  }] });
720
692
 
@@ -795,10 +767,10 @@ class TreeNodesSearchReducer {
795
767
  }
796
768
  return state;
797
769
  }
798
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodesSearchReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
799
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodesSearchReducer }); }
770
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodesSearchReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
771
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodesSearchReducer }); }
800
772
  }
801
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodesSearchReducer, decorators: [{
773
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodesSearchReducer, decorators: [{
802
774
  type: Injectable
803
775
  }] });
804
776
 
@@ -842,10 +814,10 @@ class TreeNodesReducer {
842
814
  }
843
815
  return state;
844
816
  }
845
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodesReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
846
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodesReducer }); }
817
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodesReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
818
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodesReducer }); }
847
819
  }
848
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodesReducer, decorators: [{
820
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodesReducer, decorators: [{
849
821
  type: Injectable
850
822
  }] });
851
823
 
@@ -884,10 +856,10 @@ let TreesReducer$1 = class TreesReducer {
884
856
  }
885
857
  return state;
886
858
  }
887
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreesReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
888
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreesReducer }); }
859
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreesReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
860
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreesReducer }); }
889
861
  };
890
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreesReducer$1, decorators: [{
862
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreesReducer$1, decorators: [{
891
863
  type: Injectable
892
864
  }] });
893
865
 
@@ -1092,10 +1064,10 @@ class TreesReducer {
1092
1064
  }
1093
1065
  return state;
1094
1066
  }
1095
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreesReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1096
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreesReducer }); }
1067
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreesReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1068
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreesReducer }); }
1097
1069
  }
1098
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreesReducer, decorators: [{
1070
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreesReducer, decorators: [{
1099
1071
  type: Injectable
1100
1072
  }] });
1101
1073
 
@@ -1177,10 +1149,10 @@ class TreeNodeExpandReducer {
1177
1149
  }
1178
1150
  });
1179
1151
  }
1180
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodeExpandReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1181
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodeExpandReducer }); }
1152
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodeExpandReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1153
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodeExpandReducer }); }
1182
1154
  }
1183
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodeExpandReducer, decorators: [{
1155
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodeExpandReducer, decorators: [{
1184
1156
  type: Injectable
1185
1157
  }] });
1186
1158
 
@@ -1299,10 +1271,10 @@ class TreeNodeEditionReducer {
1299
1271
  isExpanded: true
1300
1272
  });
1301
1273
  }
1302
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodeEditionReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1303
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodeEditionReducer }); }
1274
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodeEditionReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1275
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodeEditionReducer }); }
1304
1276
  }
1305
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: TreeNodeEditionReducer, decorators: [{
1277
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreeNodeEditionReducer, decorators: [{
1306
1278
  type: Injectable
1307
1279
  }] });
1308
1280
 
@@ -1407,10 +1379,10 @@ class CutAndPasteReducer {
1407
1379
  }
1408
1380
  });
1409
1381
  }
1410
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: CutAndPasteReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1411
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: CutAndPasteReducer }); }
1382
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CutAndPasteReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1383
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CutAndPasteReducer }); }
1412
1384
  }
1413
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: CutAndPasteReducer, decorators: [{
1385
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CutAndPasteReducer, decorators: [{
1414
1386
  type: Injectable
1415
1387
  }] });
1416
1388
 
@@ -1425,277 +1397,213 @@ const getDefaultCutAndPaste = () => ({
1425
1397
  canPasteInside: false,
1426
1398
  canPasteAfter: false
1427
1399
  });
1428
- class NgssmExpressionTreeNodeComponent extends NgSsmComponent {
1429
- constructor(store) {
1430
- super(store);
1431
- this._nodeId$ = new BehaviorSubject(undefined);
1432
- this._treeConfig$ = new BehaviorSubject(undefined);
1433
- this._nodeLabel$ = new BehaviorSubject('');
1434
- this._nodeCssIcon$ = new BehaviorSubject(undefined);
1435
- this._nodeDescription$ = new BehaviorSubject(undefined);
1436
- this._componentAction$ = new BehaviorSubject(undefined);
1437
- this._componentToDisplay$ = new BehaviorSubject(undefined);
1438
- this._cutAndPaste$ = new BehaviorSubject(getDefaultCutAndPaste());
1439
- combineLatest([this._nodeId$, this._treeConfig$])
1440
- .pipe(filter((v) => v[0] !== undefined && v[1] !== undefined), takeUntil(this.unsubscribeAll$), switchMap((v) => combineLatest([
1441
- this.watch((s) => selectNgssmExpressionTreeState(s).trees[v[1]?.treeId ?? 'unknown']?.data[v[0] ?? 'unknown']),
1442
- this.watch((s) => selectNgssmExpressionTreeState(s).trees[v[1]?.treeId ?? 'unknown']?.nodes),
1443
- this.watch((s) => selectNgssmExpressionTreeState(s).trees[v[1]?.treeId ?? 'unknown']?.nodeCut)
1444
- ])), takeUntil(this.unsubscribeAll$))
1445
- .subscribe((values) => {
1446
- const node = (values[1] ?? []).find((v) => v.data.id === this._nodeId$.getValue());
1447
- const treeConfig = this._treeConfig$.getValue();
1448
- const nodeValue = values[0];
1400
+ class NgssmExpressionTreeNodeComponent {
1401
+ constructor() {
1402
+ this.store = inject(Store);
1403
+ this.trees = createSignal((state) => selectNgssmExpressionTreeState(state).trees);
1404
+ this.tree = signal(undefined);
1405
+ this.nodeId = input();
1406
+ this.treeConfig = input(undefined);
1407
+ this.nodeLabel = signal('');
1408
+ this.nodeCssIcon = signal(undefined);
1409
+ this.nodeDescription = signal(undefined);
1410
+ this.cutAndPaste = signal(getDefaultCutAndPaste());
1411
+ this.componentAction = signal(undefined);
1412
+ this.componentToDisplay = signal(undefined);
1413
+ effect(() => {
1414
+ const currentNodeId = this.nodeId();
1415
+ const config = this.treeConfig();
1416
+ if (!currentNodeId || !config) {
1417
+ this.tree.set(undefined);
1418
+ return;
1419
+ }
1420
+ this.tree.set(this.trees()[config.treeId]);
1421
+ });
1422
+ effect(() => {
1423
+ const currentNodeId = this.nodeId();
1424
+ const config = this.treeConfig();
1425
+ if (!currentNodeId || !config) {
1426
+ return;
1427
+ }
1428
+ this.componentAction.set((c) => c.setup(config.treeId, currentNodeId));
1429
+ this.componentToDisplay.set(config.nodeDescriptionComponent);
1430
+ });
1431
+ effect(() => {
1432
+ const currentTree = this.tree();
1433
+ const currentNodeId = untracked(() => this.nodeId());
1434
+ const currentConfig = untracked(() => this.treeConfig());
1435
+ if (!currentNodeId || !currentTree || !currentConfig) {
1436
+ return;
1437
+ }
1438
+ const node = currentTree.nodes.find((v) => v.data.id === currentNodeId);
1439
+ const nodeValue = currentTree.data[currentNodeId];
1449
1440
  const cutAndPaste = getDefaultCutAndPaste();
1450
- if (node && treeConfig && nodeValue) {
1451
- this._nodeLabel$.next(treeConfig.getNodeLabel?.(node, nodeValue) ?? '');
1452
- this._nodeCssIcon$.next(treeConfig.getNodeCssIcon?.(node, nodeValue) ?? undefined);
1453
- this._nodeDescription$.next(treeConfig.getNodeDescription?.(node, nodeValue));
1454
- cutAndPaste.canCut = treeConfig.canCut?.(node) ?? true;
1455
- if (values[2]) {
1456
- cutAndPaste.isPartOfCut = values[2].data.id === node.data.id || node.path.includes(values[2].data.id);
1441
+ const nodeCut = currentTree.nodeCut;
1442
+ if (node && currentConfig && nodeValue) {
1443
+ this.nodeLabel.set(currentConfig.getNodeLabel?.(node, nodeValue) ?? '');
1444
+ this.nodeCssIcon.set(currentConfig.getNodeCssIcon?.(node, nodeValue) ?? undefined);
1445
+ this.nodeDescription.set(currentConfig.getNodeDescription?.(node, nodeValue));
1446
+ cutAndPaste.canCut = currentConfig.canCut?.(node) ?? true;
1447
+ if (nodeCut) {
1448
+ cutAndPaste.isPartOfCut = nodeCut.data.id === node.data.id || node.path.includes(nodeCut.data.id);
1457
1449
  if (!cutAndPaste.isPartOfCut) {
1458
- cutAndPaste.canPasteInside = treeConfig.canPaste?.(values[2], node, 'Inside') ?? false;
1459
- cutAndPaste.canPasteAfter = treeConfig.canPaste?.(values[2], node, 'After') ?? false;
1450
+ cutAndPaste.canPasteInside = currentConfig.canPaste?.(nodeCut, node, 'Inside') ?? false;
1451
+ cutAndPaste.canPasteAfter = currentConfig.canPaste?.(nodeCut, node, 'After') ?? false;
1460
1452
  }
1461
1453
  }
1462
1454
  }
1463
- cutAndPaste.isCutAndPasteInProgress = !!values[2];
1464
- this._cutAndPaste$.next(cutAndPaste);
1455
+ cutAndPaste.isCutAndPasteInProgress = !!nodeCut;
1456
+ this.cutAndPaste.set(cutAndPaste);
1465
1457
  });
1466
- combineLatest([this._nodeId$, this._treeConfig$])
1467
- .pipe(takeUntil(this.unsubscribeAll$))
1468
- .subscribe((values) => {
1469
- const treeConfig = values[1];
1470
- const nodeId = values[0];
1471
- if (treeConfig && nodeId) {
1472
- this._componentAction$.next((c) => c.setup(treeConfig.treeId, nodeId));
1473
- this._componentToDisplay$.next(treeConfig.nodeDescriptionComponent);
1474
- }
1475
- });
1476
- }
1477
- set nodeId(value) {
1478
- if (!value) {
1479
- return;
1480
- }
1481
- this._nodeId$.next(value);
1482
- }
1483
- set treeConfig(value) {
1484
- if (!value) {
1485
- return;
1486
- }
1487
- this._treeConfig$.next(value);
1488
- }
1489
- get treeConfig() {
1490
- return this._treeConfig$.getValue();
1491
- }
1492
- get nodeLabel$() {
1493
- return this._nodeLabel$.asObservable();
1494
- }
1495
- get nodeCssIcon$() {
1496
- return this._nodeCssIcon$.asObservable();
1497
- }
1498
- get nodeDescription$() {
1499
- return this._nodeDescription$.asObservable();
1500
- }
1501
- get componentAction$() {
1502
- return this._componentAction$.asObservable();
1503
- }
1504
- get componentToDisplay$() {
1505
- return this._componentToDisplay$.asObservable();
1506
- }
1507
- get cutAndPaste$() {
1508
- return this._cutAndPaste$.asObservable();
1509
1458
  }
1510
1459
  expandAll() {
1511
- const treeId = this._treeConfig$.getValue()?.treeId;
1460
+ const treeId = this.treeConfig()?.treeId;
1512
1461
  if (treeId) {
1513
- this.dispatchAction(new NgssmExpandAllExpressionTreeNodesAction(treeId));
1462
+ this.store.dispatchAction(new NgssmExpandAllExpressionTreeNodesAction(treeId));
1514
1463
  }
1515
1464
  }
1516
1465
  collapseAll() {
1517
- const treeId = this._treeConfig$.getValue()?.treeId;
1466
+ const treeId = this.treeConfig()?.treeId;
1518
1467
  if (treeId) {
1519
- this.dispatchAction(new NgssmCollapseAllExpressionTreeNodesAction(treeId));
1468
+ this.store.dispatchAction(new NgssmCollapseAllExpressionTreeNodesAction(treeId));
1520
1469
  }
1521
1470
  }
1522
1471
  cut() {
1523
- const treeId = this._treeConfig$.getValue()?.treeId;
1524
- const nodeId = this._nodeId$.getValue();
1472
+ const treeId = this.treeConfig()?.treeId;
1473
+ const nodeId = this.nodeId();
1525
1474
  if (treeId && nodeId) {
1526
- this.dispatchAction(new NgssmCutExpressionTreeNodeAction(treeId, nodeId));
1475
+ this.store.dispatchAction(new NgssmCutExpressionTreeNodeAction(treeId, nodeId));
1527
1476
  }
1528
1477
  }
1529
1478
  cancelCut() {
1530
- const treeId = this._treeConfig$.getValue()?.treeId;
1479
+ const treeId = this.treeConfig()?.treeId;
1531
1480
  if (treeId) {
1532
- this.dispatchAction(new NgssmCancelCutExpressionTreeNodeAction(treeId));
1481
+ this.store.dispatchAction(new NgssmCancelCutExpressionTreeNodeAction(treeId));
1533
1482
  }
1534
1483
  }
1535
1484
  paste(target) {
1536
- const treeId = this._treeConfig$.getValue()?.treeId;
1537
- const nodeId = this._nodeId$.getValue();
1485
+ const treeId = this.treeConfig()?.treeId;
1486
+ const nodeId = this.nodeId();
1538
1487
  if (treeId && nodeId) {
1539
- this.dispatchAction(new NgssmPasteExpressionTreeNodeAction(treeId, nodeId, target));
1488
+ this.store.dispatchAction(new NgssmPasteExpressionTreeNodeAction(treeId, nodeId, target));
1540
1489
  }
1541
1490
  }
1542
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: NgssmExpressionTreeNodeComponent, deps: [{ token: i1.Store }], target: i0.ɵɵFactoryTarget.Component }); }
1543
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: NgssmExpressionTreeNodeComponent, isStandalone: true, selector: "ngssm-expression-tree-node", inputs: { nodeId: "nodeId", treeConfig: "treeConfig" }, usesInheritance: true, ngImport: i0, template: "<div class=\"ngssm-expression-tree-node-icon\" *ngIf=\"(nodeCssIcon$ | async) !== undefined\" id=\"treeNodeIcon\">\n <mat-icon class=\"{{ nodeCssIcon$ | async }}\"></mat-icon>\n</div>\n\n<div\n class=\"ngssm-expression-tree-node-label\"\n [matMenuTriggerFor]=\"contextMenu\"\n [class.ngssm-expression-tree-node-to-cut]=\"(cutAndPaste$ | async)?.isPartOfCut === true\"\n id=\"treeNodeLabel\">\n {{ nodeLabel$ | async }}\n</div>\n\n<div class=\"ngssm-expression-tree-node-description\" [innerHTML]=\"nodeDescription$ | async\"></div>\n\n@let component = componentToDisplay$ | async;\n@if (component) {\n <div\n class=\"ngssm-expression-tree-node-description-component\"\n [ngssmComponentDisplay]=\"component\"\n [ngssmComponentAction]=\"componentAction$ | async\"></div>\n}\n\n<mat-menu #contextMenu=\"matMenu\" [class]=\"'ngssm-expression-tree-popup-menu'\">\n <div class=\"flex-column-stretch\" *ngIf=\"treeConfig?.displayCutAndPasteMenus === true && (cutAndPaste$ | async) as cutAndPasteSetup\">\n <button\n mat-menu-item\n (click)=\"cut()\"\n *ngIf=\"cutAndPasteSetup.isCutAndPasteInProgress === false\"\n [disabled]=\"cutAndPasteSetup.canCut !== true\">\n <mat-icon class=\"fa-solid fa-scissors\"></mat-icon>\n <span>Cut</span>\n </button>\n <button mat-menu-item *ngIf=\"cutAndPasteSetup.isCutAndPasteInProgress === true\" (click)=\"cancelCut()\">\n <mat-icon class=\"fa-solid fa-slash\"></mat-icon>\n <span>Cancel cut</span>\n </button>\n <button mat-menu-item [disabled]=\"cutAndPasteSetup.canPasteInside !== true\" (click)=\"paste('Inside')\">\n <mat-icon class=\"fa-solid fa-paste\"></mat-icon>\n <span>Paste inside</span>\n </button>\n <button mat-menu-item [disabled]=\"cutAndPasteSetup.canPasteAfter !== true\" (click)=\"paste('After')\">\n <mat-icon class=\"fa-solid fa-paste\"></mat-icon>\n <span>Paste after</span>\n </button>\n <mat-divider></mat-divider>\n </div>\n\n <button mat-menu-item (click)=\"expandAll()\">\n <mat-icon class=\"fa-solid fa-up-right-and-down-left-from-center\"></mat-icon>\n <span>Expand all</span>\n </button>\n <button mat-menu-item (click)=\"collapseAll()\">\n <mat-icon class=\"fa-solid fa-down-left-and-up-right-to-center\"></mat-icon>\n <span>Collapse all</span>\n </button>\n</mat-menu>\n", styles: [":host{display:flex;flex-direction:row;align-items:center;flex:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i4$3.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i4$3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i4$3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i5$1.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: NgssmComponentDisplayDirective, selector: "[ngssmComponentDisplay]", inputs: ["ngssmComponentDisplay", "ngssmComponentAction"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1491
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: NgssmExpressionTreeNodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1492
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: NgssmExpressionTreeNodeComponent, isStandalone: true, selector: "ngssm-expression-tree-node", inputs: { nodeId: { classPropertyName: "nodeId", publicName: "nodeId", isSignal: true, isRequired: false, transformFunction: null }, treeConfig: { classPropertyName: "treeConfig", publicName: "treeConfig", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (nodeCssIcon(); as css) {\n <div class=\"ngssm-expression-tree-node-icon\" id=\"treeNodeIcon\">\n <mat-icon class=\"{{ css }}\"></mat-icon>\n </div>\n}\n\n<div\n class=\"ngssm-expression-tree-node-label\"\n [matMenuTriggerFor]=\"contextMenu\"\n [class.ngssm-expression-tree-node-to-cut]=\"cutAndPaste().isPartOfCut === true\"\n id=\"treeNodeLabel\">\n {{ nodeLabel() }}\n</div>\n\n<div class=\"ngssm-expression-tree-node-description\" [innerHTML]=\"nodeDescription()\"></div>\n\n@let component = componentToDisplay();\n@if (component) {\n <div\n class=\"ngssm-expression-tree-node-description-component\"\n [ngssmComponentDisplay]=\"component\"\n [ngssmComponentAction]=\"componentAction()\"></div>\n}\n\n<mat-menu #contextMenu=\"matMenu\" [class]=\"'ngssm-expression-tree-popup-menu'\">\n @let cutAndPasteSetup = cutAndPaste();\n @if (treeConfig()?.displayCutAndPasteMenus === true && cutAndPasteSetup) {\n <div class=\"flex-column-stretch\">\n @if (cutAndPasteSetup.isCutAndPasteInProgress === false) {\n <button mat-menu-item (click)=\"cut()\" [disabled]=\"cutAndPasteSetup.canCut !== true\">\n <mat-icon class=\"fa-solid fa-scissors\"></mat-icon>\n <span>Cut</span>\n </button>\n } @else {\n <button mat-menu-item (click)=\"cancelCut()\">\n <mat-icon class=\"fa-solid fa-slash\"></mat-icon>\n <span>Cancel cut</span>\n </button>\n }\n\n <button mat-menu-item [disabled]=\"cutAndPasteSetup.canPasteInside !== true\" (click)=\"paste('Inside')\">\n <mat-icon class=\"fa-solid fa-paste\"></mat-icon>\n <span>Paste inside</span>\n </button>\n <button mat-menu-item [disabled]=\"cutAndPasteSetup.canPasteAfter !== true\" (click)=\"paste('After')\">\n <mat-icon class=\"fa-solid fa-paste\"></mat-icon>\n <span>Paste after</span>\n </button>\n <mat-divider></mat-divider>\n </div>\n }\n\n <button mat-menu-item (click)=\"expandAll()\">\n <mat-icon class=\"fa-solid fa-up-right-and-down-left-from-center\"></mat-icon>\n <span>Expand all</span>\n </button>\n <button mat-menu-item (click)=\"collapseAll()\">\n <mat-icon class=\"fa-solid fa-down-left-and-up-right-to-center\"></mat-icon>\n <span>Collapse all</span>\n </button>\n</mat-menu>\n", styles: [":host{display:flex;flex-direction:row;align-items:center;flex:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2$3.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2$3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2$3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i3$1.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: NgssmComponentDisplayDirective, selector: "[ngssmComponentDisplay]", inputs: ["ngssmComponentDisplay", "ngssmComponentAction"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1544
1493
  }
1545
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: NgssmExpressionTreeNodeComponent, decorators: [{
1494
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: NgssmExpressionTreeNodeComponent, decorators: [{
1546
1495
  type: Component,
1547
- args: [{ selector: 'ngssm-expression-tree-node', imports: [CommonModule, MatIconModule, MatMenuModule, MatDividerModule, NgssmComponentDisplayDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ngssm-expression-tree-node-icon\" *ngIf=\"(nodeCssIcon$ | async) !== undefined\" id=\"treeNodeIcon\">\n <mat-icon class=\"{{ nodeCssIcon$ | async }}\"></mat-icon>\n</div>\n\n<div\n class=\"ngssm-expression-tree-node-label\"\n [matMenuTriggerFor]=\"contextMenu\"\n [class.ngssm-expression-tree-node-to-cut]=\"(cutAndPaste$ | async)?.isPartOfCut === true\"\n id=\"treeNodeLabel\">\n {{ nodeLabel$ | async }}\n</div>\n\n<div class=\"ngssm-expression-tree-node-description\" [innerHTML]=\"nodeDescription$ | async\"></div>\n\n@let component = componentToDisplay$ | async;\n@if (component) {\n <div\n class=\"ngssm-expression-tree-node-description-component\"\n [ngssmComponentDisplay]=\"component\"\n [ngssmComponentAction]=\"componentAction$ | async\"></div>\n}\n\n<mat-menu #contextMenu=\"matMenu\" [class]=\"'ngssm-expression-tree-popup-menu'\">\n <div class=\"flex-column-stretch\" *ngIf=\"treeConfig?.displayCutAndPasteMenus === true && (cutAndPaste$ | async) as cutAndPasteSetup\">\n <button\n mat-menu-item\n (click)=\"cut()\"\n *ngIf=\"cutAndPasteSetup.isCutAndPasteInProgress === false\"\n [disabled]=\"cutAndPasteSetup.canCut !== true\">\n <mat-icon class=\"fa-solid fa-scissors\"></mat-icon>\n <span>Cut</span>\n </button>\n <button mat-menu-item *ngIf=\"cutAndPasteSetup.isCutAndPasteInProgress === true\" (click)=\"cancelCut()\">\n <mat-icon class=\"fa-solid fa-slash\"></mat-icon>\n <span>Cancel cut</span>\n </button>\n <button mat-menu-item [disabled]=\"cutAndPasteSetup.canPasteInside !== true\" (click)=\"paste('Inside')\">\n <mat-icon class=\"fa-solid fa-paste\"></mat-icon>\n <span>Paste inside</span>\n </button>\n <button mat-menu-item [disabled]=\"cutAndPasteSetup.canPasteAfter !== true\" (click)=\"paste('After')\">\n <mat-icon class=\"fa-solid fa-paste\"></mat-icon>\n <span>Paste after</span>\n </button>\n <mat-divider></mat-divider>\n </div>\n\n <button mat-menu-item (click)=\"expandAll()\">\n <mat-icon class=\"fa-solid fa-up-right-and-down-left-from-center\"></mat-icon>\n <span>Expand all</span>\n </button>\n <button mat-menu-item (click)=\"collapseAll()\">\n <mat-icon class=\"fa-solid fa-down-left-and-up-right-to-center\"></mat-icon>\n <span>Collapse all</span>\n </button>\n</mat-menu>\n", styles: [":host{display:flex;flex-direction:row;align-items:center;flex:1}\n"] }]
1548
- }], ctorParameters: () => [{ type: i1.Store }], propDecorators: { nodeId: [{
1549
- type: Input
1550
- }], treeConfig: [{
1551
- type: Input
1552
- }] } });
1496
+ args: [{ selector: 'ngssm-expression-tree-node', imports: [CommonModule, MatIconModule, MatMenuModule, MatDividerModule, NgssmComponentDisplayDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (nodeCssIcon(); as css) {\n <div class=\"ngssm-expression-tree-node-icon\" id=\"treeNodeIcon\">\n <mat-icon class=\"{{ css }}\"></mat-icon>\n </div>\n}\n\n<div\n class=\"ngssm-expression-tree-node-label\"\n [matMenuTriggerFor]=\"contextMenu\"\n [class.ngssm-expression-tree-node-to-cut]=\"cutAndPaste().isPartOfCut === true\"\n id=\"treeNodeLabel\">\n {{ nodeLabel() }}\n</div>\n\n<div class=\"ngssm-expression-tree-node-description\" [innerHTML]=\"nodeDescription()\"></div>\n\n@let component = componentToDisplay();\n@if (component) {\n <div\n class=\"ngssm-expression-tree-node-description-component\"\n [ngssmComponentDisplay]=\"component\"\n [ngssmComponentAction]=\"componentAction()\"></div>\n}\n\n<mat-menu #contextMenu=\"matMenu\" [class]=\"'ngssm-expression-tree-popup-menu'\">\n @let cutAndPasteSetup = cutAndPaste();\n @if (treeConfig()?.displayCutAndPasteMenus === true && cutAndPasteSetup) {\n <div class=\"flex-column-stretch\">\n @if (cutAndPasteSetup.isCutAndPasteInProgress === false) {\n <button mat-menu-item (click)=\"cut()\" [disabled]=\"cutAndPasteSetup.canCut !== true\">\n <mat-icon class=\"fa-solid fa-scissors\"></mat-icon>\n <span>Cut</span>\n </button>\n } @else {\n <button mat-menu-item (click)=\"cancelCut()\">\n <mat-icon class=\"fa-solid fa-slash\"></mat-icon>\n <span>Cancel cut</span>\n </button>\n }\n\n <button mat-menu-item [disabled]=\"cutAndPasteSetup.canPasteInside !== true\" (click)=\"paste('Inside')\">\n <mat-icon class=\"fa-solid fa-paste\"></mat-icon>\n <span>Paste inside</span>\n </button>\n <button mat-menu-item [disabled]=\"cutAndPasteSetup.canPasteAfter !== true\" (click)=\"paste('After')\">\n <mat-icon class=\"fa-solid fa-paste\"></mat-icon>\n <span>Paste after</span>\n </button>\n <mat-divider></mat-divider>\n </div>\n }\n\n <button mat-menu-item (click)=\"expandAll()\">\n <mat-icon class=\"fa-solid fa-up-right-and-down-left-from-center\"></mat-icon>\n <span>Expand all</span>\n </button>\n <button mat-menu-item (click)=\"collapseAll()\">\n <mat-icon class=\"fa-solid fa-down-left-and-up-right-to-center\"></mat-icon>\n <span>Collapse all</span>\n </button>\n</mat-menu>\n", styles: [":host{display:flex;flex-direction:row;align-items:center;flex:1}\n"] }]
1497
+ }], ctorParameters: () => [] });
1553
1498
 
1554
- class NgssmExpressionTreeNodeDetailsComponent extends NgSsmComponent {
1555
- constructor(store, elementRef) {
1556
- super(store);
1557
- this.elementRef = elementRef;
1558
- this._nodeId$ = new Subject();
1559
- this._treeConfig$ = new Subject();
1560
- this._componentAction$ = new BehaviorSubject(undefined);
1561
- this._componentToDisplay$ = new BehaviorSubject(undefined);
1562
- this.initialized = false;
1563
- this.heightChanged = new EventEmitter();
1564
- combineLatest([this._nodeId$, this._treeConfig$])
1565
- .pipe(take(1))
1566
- .subscribe((values) => {
1567
- this.initialized = true;
1568
- this._componentAction$.next((c) => c.setup(values[1].treeId, values[0]));
1569
- this._componentToDisplay$.next(values[1].nodeDetailComponent);
1499
+ class NgssmExpressionTreeNodeDetailsComponent {
1500
+ constructor() {
1501
+ this.elementRef = inject(ElementRef);
1502
+ this.nodeId = input();
1503
+ this.treeConfig = input();
1504
+ this.heightChanged = output();
1505
+ this.componentAction = signal(undefined);
1506
+ this.componentToDisplay = signal(undefined);
1507
+ effect(() => {
1508
+ const currentNodeId = this.nodeId();
1509
+ const currentConfig = this.treeConfig();
1510
+ if (!currentNodeId || !currentConfig) {
1511
+ return;
1512
+ }
1513
+ this.componentAction.set((c) => c.setup(currentConfig.treeId, currentNodeId));
1514
+ this.componentToDisplay.set(currentConfig.nodeDetailComponent);
1570
1515
  setTimeout(() => {
1571
1516
  this.heightChanged.emit(this.elementRef?.nativeElement.getBoundingClientRect().height ?? 0);
1572
1517
  });
1573
1518
  });
1574
1519
  }
1575
- set nodeId(value) {
1576
- if (!value) {
1577
- return;
1578
- }
1579
- if (this.initialized) {
1580
- throw new Error('Component NgssmExpressionTreeNodeDetailsComponent is already initialized.');
1581
- }
1582
- this._nodeId$.next(value);
1583
- }
1584
- set treeConfig(value) {
1585
- if (!value) {
1586
- return;
1587
- }
1588
- if (this.initialized) {
1589
- throw new Error('Component NgssmExpressionTreeNodeDetailsComponent is already initialized.');
1590
- }
1591
- this._treeConfig$.next(value);
1592
- }
1593
- get componentAction$() {
1594
- return this._componentAction$.asObservable();
1595
- }
1596
- get componentToDisplay$() {
1597
- return this._componentToDisplay$.asObservable();
1598
- }
1599
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: NgssmExpressionTreeNodeDetailsComponent, deps: [{ token: i1.Store }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
1600
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: NgssmExpressionTreeNodeDetailsComponent, isStandalone: true, selector: "ngssm-expression-tree-node-details", inputs: { nodeId: "nodeId", treeConfig: "treeConfig" }, outputs: { heightChanged: "heightChanged" }, usesInheritance: true, ngImport: i0, template: "@let component = componentToDisplay$ | async;\n@if (component){\n <div [ngssmComponentDisplay]=\"component\" [ngssmComponentAction]=\"componentAction$ | async\"></div>\n}\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "directive", type: NgssmComponentDisplayDirective, selector: "[ngssmComponentDisplay]", inputs: ["ngssmComponentDisplay", "ngssmComponentAction"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1520
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: NgssmExpressionTreeNodeDetailsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1521
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: NgssmExpressionTreeNodeDetailsComponent, isStandalone: true, selector: "ngssm-expression-tree-node-details", inputs: { nodeId: { classPropertyName: "nodeId", publicName: "nodeId", isSignal: true, isRequired: false, transformFunction: null }, treeConfig: { classPropertyName: "treeConfig", publicName: "treeConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { heightChanged: "heightChanged" }, ngImport: i0, template: "@if (componentToDisplay(); as component) {\n <div [ngssmComponentDisplay]=\"component\" [ngssmComponentAction]=\"componentAction()\"></div>\n}\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: NgssmComponentDisplayDirective, selector: "[ngssmComponentDisplay]", inputs: ["ngssmComponentDisplay", "ngssmComponentAction"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1601
1522
  }
1602
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: NgssmExpressionTreeNodeDetailsComponent, decorators: [{
1523
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: NgssmExpressionTreeNodeDetailsComponent, decorators: [{
1603
1524
  type: Component,
1604
- args: [{ selector: 'ngssm-expression-tree-node-details', imports: [CommonModule, NgssmComponentDisplayDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let component = componentToDisplay$ | async;\n@if (component){\n <div [ngssmComponentDisplay]=\"component\" [ngssmComponentAction]=\"componentAction$ | async\"></div>\n}\n" }]
1605
- }], ctorParameters: () => [{ type: i1.Store }, { type: i0.ElementRef }], propDecorators: { heightChanged: [{
1606
- type: Output
1607
- }], nodeId: [{
1608
- type: Input
1609
- }], treeConfig: [{
1610
- type: Input
1611
- }] } });
1525
+ args: [{ selector: 'ngssm-expression-tree-node-details', imports: [CommonModule, NgssmComponentDisplayDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (componentToDisplay(); as component) {\n <div [ngssmComponentDisplay]=\"component\" [ngssmComponentAction]=\"componentAction()\"></div>\n}\n" }]
1526
+ }], ctorParameters: () => [] });
1612
1527
 
1613
- class NgssmExpressionTreeComponent extends NgSsmComponent {
1614
- constructor(store, changeDetectorRef) {
1615
- super(store);
1616
- this.changeDetectorRef = changeDetectorRef;
1617
- this._tree$ = new BehaviorSubject(undefined);
1618
- this._displayedNodes$ = new BehaviorSubject([]);
1619
- this._treeConfig$ = new BehaviorSubject(undefined);
1620
- this._tree$.pipe(takeUntil(this.unsubscribeAll$)).subscribe((tree) => {
1621
- const displayedNodes = [];
1528
+ class NgssmExpressionTreeComponent {
1529
+ constructor() {
1530
+ this.store = inject(Store);
1531
+ this.changeDetectorRef = inject(ChangeDetectorRef);
1532
+ this.trees = createSignal((state) => selectNgssmExpressionTreeState(state).trees);
1533
+ this.treeConfig = input(undefined, {
1534
+ transform: (value) => {
1535
+ if (!value) {
1536
+ return value;
1537
+ }
1538
+ const config = {
1539
+ ...value
1540
+ };
1541
+ if (!config.getNodeLabel) {
1542
+ config.getNodeLabel = (node) => node.data.id;
1543
+ }
1544
+ if (!config.expandIconClass) {
1545
+ config.expandIconClass = 'fa-solid fa-chevron-right';
1546
+ }
1547
+ if (!config.collapseIconClass) {
1548
+ config.collapseIconClass = 'fa-solid fa-chevron-down';
1549
+ }
1550
+ return config;
1551
+ }
1552
+ });
1553
+ this.displayedNodes = signal([]);
1554
+ effect(() => {
1555
+ const config = this.treeConfig();
1556
+ if (!config) {
1557
+ this.displayedNodes.set([]);
1558
+ return;
1559
+ }
1560
+ const nodes = [];
1622
1561
  const collapsedNodes = new Set();
1623
- (tree?.nodes ?? []).forEach((node) => {
1562
+ (this.trees()[config.treeId]?.nodes ?? []).forEach((node) => {
1624
1563
  if (node.data.isExpandable === true && node.isExpanded === false) {
1625
1564
  collapsedNodes.add(node.data.id);
1626
1565
  }
1627
1566
  if (!node.data.parentId || node.path.findIndex((p) => collapsedNodes.has(p)) === -1) {
1628
- displayedNodes.push(node);
1567
+ nodes.push(node);
1629
1568
  }
1630
1569
  });
1631
- this._displayedNodes$.next(displayedNodes);
1570
+ this.displayedNodes.set(nodes);
1632
1571
  });
1633
1572
  }
1634
- set treeConfig(value) {
1635
- this._treeSubscription?.unsubscribe();
1636
- if (!value) {
1637
- this._treeConfig$.next(undefined);
1638
- return;
1639
- }
1640
- const config = {
1641
- ...value
1642
- };
1643
- if (!config.getNodeLabel) {
1644
- config.getNodeLabel = (node) => node.data.id;
1645
- }
1646
- if (!config.expandIconClass) {
1647
- config.expandIconClass = 'fa-solid fa-chevron-right';
1648
- }
1649
- if (!config.collapseIconClass) {
1650
- config.collapseIconClass = 'fa-solid fa-chevron-down';
1651
- }
1652
- this._treeConfig$.next(config);
1653
- this._treeSubscription = this.watch((s) => selectNgssmExpressionTreeState(s).trees[value.treeId]).subscribe((tree) => this._tree$.next(tree));
1654
- }
1655
- get treeConfig$() {
1656
- return this._treeConfig$.asObservable();
1657
- }
1658
- get displayedNodes$() {
1659
- return this._displayedNodes$.asObservable();
1660
- }
1661
1573
  getItemId(_, node) {
1662
1574
  return node.data.id;
1663
1575
  }
1664
- getDefaultPadding() {
1665
- return this._treeConfig$.getValue()?.nodePadding ?? 20;
1666
- }
1667
1576
  expand(node) {
1668
- const treeId = this._treeConfig$.getValue()?.treeId;
1577
+ const treeId = this.treeConfig()?.treeId;
1669
1578
  if (treeId) {
1670
- this.dispatchAction(new NgssmExpandExpressionTreeNodeAction(treeId, node.data.id));
1579
+ this.store.dispatchAction(new NgssmExpandExpressionTreeNodeAction(treeId, node.data.id));
1671
1580
  }
1672
1581
  }
1673
1582
  collapse(node) {
1674
- const treeId = this._treeConfig$.getValue()?.treeId;
1583
+ const treeId = this.treeConfig()?.treeId;
1675
1584
  if (treeId) {
1676
- this.dispatchAction(new NgssmCollapseExpressionTreeNodeAction(treeId, node.data.id));
1585
+ this.store.dispatchAction(new NgssmCollapseExpressionTreeNodeAction(treeId, node.data.id));
1677
1586
  }
1678
1587
  }
1679
1588
  forceRefresh() {
1680
1589
  this.changeDetectorRef.markForCheck();
1681
1590
  }
1682
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: NgssmExpressionTreeComponent, deps: [{ token: i1.Store }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
1683
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.5", type: NgssmExpressionTreeComponent, isStandalone: true, selector: "ngssm-expression-tree", inputs: { treeConfig: "treeConfig" }, usesInheritance: true, ngImport: i0, template: "<mat-card class=\"flex-column-stretch fxFlex ngssm-expression-tree\">\n <mat-card-content class=\"flex-column-stretch fxFlex ngssm-expression-tree-content\"\n *ngIf=\"(treeConfig$ | async) as treeConfig\">\n <cdk-virtual-scroll-viewport [itemSize]=\"treeConfig.rowSize ?? 30\" class=\"fxFlex\"\n *ngIf=\"treeConfig.disableVirtualization !== true\">\n <div *cdkVirtualFor=\"let item of displayedNodes$ | async; trackBy: getItemId\"\n class=\"ngssm-expression-tree-node\" id=\"{{'node_' + item.data.id}}\">\n <ng-container *ngTemplateOutlet=\"nodeTemplate;context: {treeConfig, item}\"></ng-container>\n </div>\n </cdk-virtual-scroll-viewport>\n <div class=\"ngssm-expression-tree-nodes-container\" *ngIf=\"treeConfig.disableVirtualization === true\">\n <div *ngFor=\"let item of displayedNodes$ | async; trackBy: getItemId\" class=\"ngssm-expression-tree-node\"\n id=\"{{'node_' + item.data.id}}\">\n <ng-container *ngTemplateOutlet=\"nodeTemplate;context: {treeConfig, item}\"></ng-container>\n </div>\n </div>\n </mat-card-content>\n</mat-card>\n\n<ng-template #nodeTemplate let-treeConfig=\"treeConfig\" let-item=\"item\">\n <div class=\"flex-row-center fxFlex\" [style.height.px]=\"treeConfig.rowSize ?? 30\">\n <mat-divider [vertical]=\"true\" class=\"ngssm-expression-tree-node-divider\"\n [style.height.px]=\"treeConfig.rowSize ?? 30\" *ngFor=\"let part of item.path\"\n [style.margin-right.px]=\"getDefaultPadding()\">\n </mat-divider>\n <mat-icon class=\"{{treeConfig.expandIconClass}}\"\n *ngIf=\"(item.data.isExpandable || item.data.hasRowDetail) && item.isExpanded === false\"\n (click)=\"$event.stopPropagation();expand(item);\" id=\"expandIcon\">\n </mat-icon>\n <mat-icon class=\"{{treeConfig.collapseIconClass}}\"\n *ngIf=\"(item.data.isExpandable || item.data.hasRowDetail) && item.isExpanded === true\"\n (click)=\"$event.stopPropagation();collapse(item);\" id=\"collapseIcon\">\n </mat-icon>\n <ngssm-expression-tree-node [nodeId]=\"item.data.id\" [treeConfig]=\"treeConfig\">\n </ngssm-expression-tree-node>\n </div>\n <div *ngIf=\"item.data.hasRowDetail === true && item.isExpanded === true\" class=\"flex-row-center fxFlex\">\n <mat-divider [vertical]=\"true\" class=\"ngssm-expression-tree-node-divider\"\n [style.height.px]=\"detailContainer.getBoundingClientRect().height\" *ngFor=\" let part of item.path\"\n [style.margin-right.px]=\"getDefaultPadding()\">\n </mat-divider>\n\n <div #detailContainer class=\"ngssm-expression-tree-node-detail-component\">\n <ngssm-expression-tree-node-details [nodeId]=\"item.data.id\" [treeConfig]=\"treeConfig\"\n (heightChanged)=\"forceRefresh()\">\n </ngssm-expression-tree-node-details>\n </div>\n </div>\n</ng-template>\n", styles: [":host{display:flex;flex-direction:column}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i3.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i3.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i3.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i4.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i4.MatCardContent, selector: "mat-card-content" }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i5$1.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: NgssmExpressionTreeNodeComponent, selector: "ngssm-expression-tree-node", inputs: ["nodeId", "treeConfig"] }, { kind: "component", type: NgssmExpressionTreeNodeDetailsComponent, selector: "ngssm-expression-tree-node-details", inputs: ["nodeId", "treeConfig"], outputs: ["heightChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1591
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: NgssmExpressionTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1592
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: NgssmExpressionTreeComponent, isStandalone: true, selector: "ngssm-expression-tree", inputs: { treeConfig: { classPropertyName: "treeConfig", publicName: "treeConfig", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@let defaultPadding = treeConfig()?.nodePadding ?? 20;\n\n<mat-card class=\"flex-column-stretch fxFlex ngssm-expression-tree\">\n @if (treeConfig(); as config) {\n <mat-card-content class=\"flex-column-stretch fxFlex ngssm-expression-tree-content\">\n @if (config.disableVirtualization) {\n <div class=\"ngssm-expression-tree-nodes-container\">\n @for (item of displayedNodes(); track item.data.id) {\n <div class=\"ngssm-expression-tree-node\" id=\"{{ 'node_' + item.data.id }}\">\n <ng-container *ngTemplateOutlet=\"nodeTemplate; context: { config, item }\"></ng-container>\n </div>\n }\n </div>\n } @else {\n <cdk-virtual-scroll-viewport [itemSize]=\"config.rowSize ?? 30\" class=\"fxFlex\">\n <div\n *cdkVirtualFor=\"let item of displayedNodes(); trackBy: getItemId\"\n class=\"ngssm-expression-tree-node\"\n id=\"{{ 'node_' + item.data.id }}\">\n <ng-container *ngTemplateOutlet=\"nodeTemplate; context: { config, item }\"></ng-container>\n </div>\n </cdk-virtual-scroll-viewport>\n }\n </mat-card-content>\n }\n</mat-card>\n\n<ng-template #nodeTemplate let-config=\"config\" let-item=\"item\">\n <div class=\"flex-row-center fxFlex\" [style.height.px]=\"config.rowSize ?? 30\">\n @for (part of item.path; track part) {\n <mat-divider\n [vertical]=\"true\"\n class=\"ngssm-expression-tree-node-divider\"\n [style.height.px]=\"config.rowSize ?? 30\"\n [style.margin-right.px]=\"defaultPadding\">\n </mat-divider>\n }\n @if ((item.data.isExpandable || item.data.hasRowDetail) && item.isExpanded === false) {\n <mat-icon class=\"{{ config.expandIconClass }}\" (click)=\"$event.stopPropagation(); expand(item)\" id=\"expandIcon\"> </mat-icon>\n }\n\n @if ((item.data.isExpandable || item.data.hasRowDetail) && item.isExpanded === true) {\n <mat-icon class=\"{{ config.collapseIconClass }}\" (click)=\"$event.stopPropagation(); collapse(item)\" id=\"collapseIcon\"> </mat-icon>\n }\n\n <ngssm-expression-tree-node [nodeId]=\"item.data.id\" [treeConfig]=\"config\"> </ngssm-expression-tree-node>\n </div>\n @if (item.data.hasRowDetail === true && item.isExpanded === true) {\n <div class=\"flex-row-center fxFlex\">\n @for (part of item.path; track part) {\n <mat-divider\n [vertical]=\"true\"\n class=\"ngssm-expression-tree-node-divider\"\n [style.height.px]=\"detailContainer.getBoundingClientRect().height\"\n [style.margin-right.px]=\"defaultPadding\">\n </mat-divider>\n }\n\n <div #detailContainer class=\"ngssm-expression-tree-node-detail-component\">\n <ngssm-expression-tree-node-details [nodeId]=\"item.data.id\" [treeConfig]=\"config\" (heightChanged)=\"forceRefresh()\">\n </ngssm-expression-tree-node-details>\n </div>\n </div>\n }\n</ng-template>\n", styles: [":host{display:flex;flex-direction:column}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { 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: "component", type: MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: MatCardContent, selector: "mat-card-content" }, { kind: "component", type: MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: NgssmExpressionTreeNodeComponent, selector: "ngssm-expression-tree-node", inputs: ["nodeId", "treeConfig"] }, { kind: "component", type: NgssmExpressionTreeNodeDetailsComponent, selector: "ngssm-expression-tree-node-details", inputs: ["nodeId", "treeConfig"], outputs: ["heightChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1684
1593
  }
1685
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: NgssmExpressionTreeComponent, decorators: [{
1594
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: NgssmExpressionTreeComponent, decorators: [{
1686
1595
  type: Component,
1687
1596
  args: [{ selector: 'ngssm-expression-tree', imports: [
1688
1597
  CommonModule,
1689
1598
  ScrollingModule,
1690
- MatCardModule,
1691
- MatDividerModule,
1692
- MatIconModule,
1599
+ MatCard,
1600
+ MatCardContent,
1601
+ MatDivider,
1602
+ MatIcon,
1693
1603
  NgssmExpressionTreeNodeComponent,
1694
1604
  NgssmExpressionTreeNodeDetailsComponent
1695
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<mat-card class=\"flex-column-stretch fxFlex ngssm-expression-tree\">\n <mat-card-content class=\"flex-column-stretch fxFlex ngssm-expression-tree-content\"\n *ngIf=\"(treeConfig$ | async) as treeConfig\">\n <cdk-virtual-scroll-viewport [itemSize]=\"treeConfig.rowSize ?? 30\" class=\"fxFlex\"\n *ngIf=\"treeConfig.disableVirtualization !== true\">\n <div *cdkVirtualFor=\"let item of displayedNodes$ | async; trackBy: getItemId\"\n class=\"ngssm-expression-tree-node\" id=\"{{'node_' + item.data.id}}\">\n <ng-container *ngTemplateOutlet=\"nodeTemplate;context: {treeConfig, item}\"></ng-container>\n </div>\n </cdk-virtual-scroll-viewport>\n <div class=\"ngssm-expression-tree-nodes-container\" *ngIf=\"treeConfig.disableVirtualization === true\">\n <div *ngFor=\"let item of displayedNodes$ | async; trackBy: getItemId\" class=\"ngssm-expression-tree-node\"\n id=\"{{'node_' + item.data.id}}\">\n <ng-container *ngTemplateOutlet=\"nodeTemplate;context: {treeConfig, item}\"></ng-container>\n </div>\n </div>\n </mat-card-content>\n</mat-card>\n\n<ng-template #nodeTemplate let-treeConfig=\"treeConfig\" let-item=\"item\">\n <div class=\"flex-row-center fxFlex\" [style.height.px]=\"treeConfig.rowSize ?? 30\">\n <mat-divider [vertical]=\"true\" class=\"ngssm-expression-tree-node-divider\"\n [style.height.px]=\"treeConfig.rowSize ?? 30\" *ngFor=\"let part of item.path\"\n [style.margin-right.px]=\"getDefaultPadding()\">\n </mat-divider>\n <mat-icon class=\"{{treeConfig.expandIconClass}}\"\n *ngIf=\"(item.data.isExpandable || item.data.hasRowDetail) && item.isExpanded === false\"\n (click)=\"$event.stopPropagation();expand(item);\" id=\"expandIcon\">\n </mat-icon>\n <mat-icon class=\"{{treeConfig.collapseIconClass}}\"\n *ngIf=\"(item.data.isExpandable || item.data.hasRowDetail) && item.isExpanded === true\"\n (click)=\"$event.stopPropagation();collapse(item);\" id=\"collapseIcon\">\n </mat-icon>\n <ngssm-expression-tree-node [nodeId]=\"item.data.id\" [treeConfig]=\"treeConfig\">\n </ngssm-expression-tree-node>\n </div>\n <div *ngIf=\"item.data.hasRowDetail === true && item.isExpanded === true\" class=\"flex-row-center fxFlex\">\n <mat-divider [vertical]=\"true\" class=\"ngssm-expression-tree-node-divider\"\n [style.height.px]=\"detailContainer.getBoundingClientRect().height\" *ngFor=\" let part of item.path\"\n [style.margin-right.px]=\"getDefaultPadding()\">\n </mat-divider>\n\n <div #detailContainer class=\"ngssm-expression-tree-node-detail-component\">\n <ngssm-expression-tree-node-details [nodeId]=\"item.data.id\" [treeConfig]=\"treeConfig\"\n (heightChanged)=\"forceRefresh()\">\n </ngssm-expression-tree-node-details>\n </div>\n </div>\n</ng-template>\n", styles: [":host{display:flex;flex-direction:column}\n"] }]
1696
- }], ctorParameters: () => [{ type: i1.Store }, { type: i0.ChangeDetectorRef }], propDecorators: { treeConfig: [{
1697
- type: Input
1698
- }] } });
1605
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let defaultPadding = treeConfig()?.nodePadding ?? 20;\n\n<mat-card class=\"flex-column-stretch fxFlex ngssm-expression-tree\">\n @if (treeConfig(); as config) {\n <mat-card-content class=\"flex-column-stretch fxFlex ngssm-expression-tree-content\">\n @if (config.disableVirtualization) {\n <div class=\"ngssm-expression-tree-nodes-container\">\n @for (item of displayedNodes(); track item.data.id) {\n <div class=\"ngssm-expression-tree-node\" id=\"{{ 'node_' + item.data.id }}\">\n <ng-container *ngTemplateOutlet=\"nodeTemplate; context: { config, item }\"></ng-container>\n </div>\n }\n </div>\n } @else {\n <cdk-virtual-scroll-viewport [itemSize]=\"config.rowSize ?? 30\" class=\"fxFlex\">\n <div\n *cdkVirtualFor=\"let item of displayedNodes(); trackBy: getItemId\"\n class=\"ngssm-expression-tree-node\"\n id=\"{{ 'node_' + item.data.id }}\">\n <ng-container *ngTemplateOutlet=\"nodeTemplate; context: { config, item }\"></ng-container>\n </div>\n </cdk-virtual-scroll-viewport>\n }\n </mat-card-content>\n }\n</mat-card>\n\n<ng-template #nodeTemplate let-config=\"config\" let-item=\"item\">\n <div class=\"flex-row-center fxFlex\" [style.height.px]=\"config.rowSize ?? 30\">\n @for (part of item.path; track part) {\n <mat-divider\n [vertical]=\"true\"\n class=\"ngssm-expression-tree-node-divider\"\n [style.height.px]=\"config.rowSize ?? 30\"\n [style.margin-right.px]=\"defaultPadding\">\n </mat-divider>\n }\n @if ((item.data.isExpandable || item.data.hasRowDetail) && item.isExpanded === false) {\n <mat-icon class=\"{{ config.expandIconClass }}\" (click)=\"$event.stopPropagation(); expand(item)\" id=\"expandIcon\"> </mat-icon>\n }\n\n @if ((item.data.isExpandable || item.data.hasRowDetail) && item.isExpanded === true) {\n <mat-icon class=\"{{ config.collapseIconClass }}\" (click)=\"$event.stopPropagation(); collapse(item)\" id=\"collapseIcon\"> </mat-icon>\n }\n\n <ngssm-expression-tree-node [nodeId]=\"item.data.id\" [treeConfig]=\"config\"> </ngssm-expression-tree-node>\n </div>\n @if (item.data.hasRowDetail === true && item.isExpanded === true) {\n <div class=\"flex-row-center fxFlex\">\n @for (part of item.path; track part) {\n <mat-divider\n [vertical]=\"true\"\n class=\"ngssm-expression-tree-node-divider\"\n [style.height.px]=\"detailContainer.getBoundingClientRect().height\"\n [style.margin-right.px]=\"defaultPadding\">\n </mat-divider>\n }\n\n <div #detailContainer class=\"ngssm-expression-tree-node-detail-component\">\n <ngssm-expression-tree-node-details [nodeId]=\"item.data.id\" [treeConfig]=\"config\" (heightChanged)=\"forceRefresh()\">\n </ngssm-expression-tree-node-details>\n </div>\n </div>\n }\n</ng-template>\n", styles: [":host{display:flex;flex-direction:column}\n"] }]
1606
+ }], ctorParameters: () => [] });
1699
1607
 
1700
1608
  /*
1701
1609
  * Public API Surface of ngssm-tree