@planeasyinc/le-angular 0.0.20 → 0.0.22

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,9 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { InjectionToken, inject, signal, Injectable, computed, effect, untracked, Directive, input, ChangeDetectionStrategy, Component, output, forwardRef, ViewContainerRef, Injector, Renderer2, ElementRef, DestroyRef, viewChild } from '@angular/core';
3
3
  import { HttpContextToken, HttpClient, HttpContext, HttpRequest, HttpEventType } from '@angular/common/http';
4
- import { map, filter, distinctUntilChanged, BehaviorSubject, Subject, takeUntil, firstValueFrom, of, tap, catchError, from, concatMap, finalize, fromEvent, startWith } from 'rxjs';
4
+ import { map, filter, distinctUntilChanged, Subject, takeUntil, BehaviorSubject, firstValueFrom, of, tap, catchError, switchMap, from, concatMap, finalize, fromEvent, startWith } from 'rxjs';
5
5
  import { decodeJwt, UrlFragmentBuilder, normalizeConfig } from '@planeasyinc/le-core';
6
- import { Location, JsonPipe, UpperCasePipe, DatePipe, ViewportScroller } from '@angular/common';
6
+ import { Location, UpperCasePipe, JsonPipe, DatePipe, ViewportScroller } from '@angular/common';
7
7
  import { CdkDrag } from '@angular/cdk/drag-drop';
8
8
  import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
9
9
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@@ -11,11 +11,11 @@ import { coerceNumberProperty } from '@angular/cdk/coercion';
11
11
  import { ComponentPortal, CdkPortalOutlet, TemplatePortal } from '@angular/cdk/portal';
12
12
  import { DataSource, CdkTable, CdkColumnDef, CdkHeaderCell, CdkHeaderCellDef, CdkCell, CdkCellDef, CdkHeaderRowDef, CdkHeaderRow, CdkRow, CdkRowDef } from '@angular/cdk/table';
13
13
  import { DialogModule } from '@angular/cdk/dialog';
14
- import { CdkMenuTrigger, CdkMenu, CdkMenuItem } from '@angular/cdk/menu';
15
- import { A11yModule } from '@angular/cdk/a11y';
16
14
  import { Overlay } from '@angular/cdk/overlay';
17
15
  import { NestedTreeControl, CdkTree, CdkNestedTreeNode, CdkTreeNodeDef, CdkTreeNodeOutlet, CdkTreeNodeToggle } from '@angular/cdk/tree';
18
16
  import { ArrayDataSource, SelectionModel } from '@angular/cdk/collections';
17
+ import { CdkMenuTrigger, CdkMenu, CdkMenuItem } from '@angular/cdk/menu';
18
+ import { A11yModule } from '@angular/cdk/a11y';
19
19
  import { adaptOld } from '@planeasyinc/fe-adapters-old';
20
20
  import { adaptSections } from '@planeasyinc/fe-adapters-sections';
21
21
  import { createEngine } from '@planeasyinc/fe-core';
@@ -599,622 +599,622 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
599
599
  }, template: "@for (child of node().children; track child.id) {\n <le-node [node]=\"child\" [config]=\"config()\" (event)=\"event.emit($event)\"></le-node>\n}\n" }]
600
600
  }] });
601
601
 
602
- class TableDataSource extends DataSource {
603
- data;
604
- get count() {
605
- return this.data.value.length;
606
- }
607
- constructor(data = []) {
608
- super();
609
- this.data = new BehaviorSubject(data);
610
- }
611
- getValueByIndex(index) {
612
- return this.data.value[index];
602
+ const flattenNodes = (nodes) => {
603
+ const flattenedNodes = [];
604
+ for (const node of nodes) {
605
+ flattenedNodes.push(node);
606
+ if (node.leafs) {
607
+ flattenedNodes.push(...flattenNodes(node.leafs));
608
+ }
613
609
  }
614
- connect() {
615
- return this.data;
610
+ return flattenedNodes;
611
+ };
612
+ const toTree = (obj, label) => {
613
+ if (obj !== null && typeof obj === 'object') {
614
+ const entries = Array.isArray(obj)
615
+ ? obj.map((v, i) => toTree(v, String(i)))
616
+ : Object.entries(obj).map((item) => toTree(item[1], item[0]));
617
+ return { label, leafs: entries };
616
618
  }
617
- disconnect() { }
619
+ return { label, value: obj };
620
+ };
621
+ const mapObjectToTree = (data) => {
622
+ return Object.entries(data).map((item) => toTree(item[1], item[0]));
623
+ };
624
+
625
+ class TreeViewComponent {
626
+ treeControl = new NestedTreeControl((node) => node.leafs);
627
+ data = input();
628
+ source = computed(() => {
629
+ return new ArrayDataSource(mapObjectToTree(this.data() ?? {}));
630
+ });
631
+ hasChild = (_, node) => !!node.leafs && node.leafs.length > 0;
632
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TreeViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
633
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.21", type: TreeViewComponent, isStandalone: true, selector: "le-tree-view", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<cdk-tree [dataSource]=\"source()\" [treeControl]=\"treeControl\">\n <!-- Tree node template for leaf nodes -->\n <cdk-nested-tree-node *cdkTreeNodeDef=\"let node\" class=\"le-tree-node\">\n <div class=\"le-tree-row\">\n <b>{{node.label | uppercase}}</b>: &nbsp;&nbsp;&nbsp; {{node.value}}\n </div>\n </cdk-nested-tree-node>\n\n <!-- Tree node template for expandable nodes -->\n <cdk-nested-tree-node *cdkTreeNodeDef=\"let node; when: hasChild\" class=\"le-tree-node\">\n\n <a class=\"le-tree-row\" [class.le-tree-row--expanded]=\"treeControl.isExpanded(node)\" [attr.aria-label]=\"'Toggle ' + node.label\" cdkTreeNodeToggle>\n <b>{{node.label | uppercase}}</b>:\n\n <le-icon class=\"le-tree-chevron\" name=\"chevron\"></le-icon>\n </a>\n\n <div [class.le-tree-invisible]=\"!treeControl.isExpanded(node)\">\n <ng-container cdkTreeNodeOutlet></ng-container>\n </div>\n </cdk-nested-tree-node>\n</cdk-tree>\n", dependencies: [{ kind: "component", type: CdkTree, selector: "cdk-tree", inputs: ["dataSource", "treeControl", "trackBy"], exportAs: ["cdkTree"] }, { kind: "directive", type: CdkNestedTreeNode, selector: "cdk-nested-tree-node", exportAs: ["cdkNestedTreeNode"] }, { kind: "directive", type: CdkTreeNodeDef, selector: "[cdkTreeNodeDef]", inputs: ["cdkTreeNodeDefWhen"] }, { kind: "directive", type: CdkTreeNodeOutlet, selector: "[cdkTreeNodeOutlet]" }, { kind: "component", type: LeIconComponent, selector: "le-icon", inputs: ["name", "size"] }, { kind: "directive", type: CdkTreeNodeToggle, selector: "[cdkTreeNodeToggle]", inputs: ["cdkTreeNodeToggleRecursive"] }, { kind: "pipe", type: UpperCasePipe, name: "uppercase" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
618
634
  }
635
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TreeViewComponent, decorators: [{
636
+ type: Component,
637
+ args: [{ selector: 'le-tree-view', imports: [
638
+ CdkTree,
639
+ CdkNestedTreeNode,
640
+ CdkTreeNodeDef,
641
+ CdkTreeNodeOutlet,
642
+ LeIconComponent,
643
+ CdkTreeNodeToggle,
644
+ UpperCasePipe,
645
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<cdk-tree [dataSource]=\"source()\" [treeControl]=\"treeControl\">\n <!-- Tree node template for leaf nodes -->\n <cdk-nested-tree-node *cdkTreeNodeDef=\"let node\" class=\"le-tree-node\">\n <div class=\"le-tree-row\">\n <b>{{node.label | uppercase}}</b>: &nbsp;&nbsp;&nbsp; {{node.value}}\n </div>\n </cdk-nested-tree-node>\n\n <!-- Tree node template for expandable nodes -->\n <cdk-nested-tree-node *cdkTreeNodeDef=\"let node; when: hasChild\" class=\"le-tree-node\">\n\n <a class=\"le-tree-row\" [class.le-tree-row--expanded]=\"treeControl.isExpanded(node)\" [attr.aria-label]=\"'Toggle ' + node.label\" cdkTreeNodeToggle>\n <b>{{node.label | uppercase}}</b>:\n\n <le-icon class=\"le-tree-chevron\" name=\"chevron\"></le-icon>\n </a>\n\n <div [class.le-tree-invisible]=\"!treeControl.isExpanded(node)\">\n <ng-container cdkTreeNodeOutlet></ng-container>\n </div>\n </cdk-nested-tree-node>\n</cdk-tree>\n" }]
646
+ }] });
619
647
 
620
- class TableViewPaginationComponent {
621
- pageSize = input.required();
622
- pageSizeOptions = input.required();
623
- entriesCount = input.required();
624
- pageChange = output();
625
- selectedPageSize = signal(0);
626
- selectedPageIndex = signal(0);
627
- entriesRange = computed(() => {
628
- const selectedPageIndex = this.selectedPageIndex();
629
- const pageSize = this.pageSize();
630
- const count = this.entriesCount();
631
- const rangeStart = selectedPageIndex * pageSize;
632
- const rangeEnd = rangeStart + pageSize;
648
+ class StringTemplate {
649
+ data = input.required();
650
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: StringTemplate, deps: [], target: i0.ɵɵFactoryTarget.Component });
651
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.21", type: StringTemplate, isStandalone: true, selector: "ng-component", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `<span class="le-table-template le-template-string">{{ data() ?? '–' }}</span>`, isInline: true });
652
+ }
653
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: StringTemplate, decorators: [{
654
+ type: Component,
655
+ args: [{
656
+ template: `<span class="le-table-template le-template-string">{{ data() ?? '–' }}</span>`,
657
+ }]
658
+ }] });
659
+
660
+ class ReferenceTemplate {
661
+ data = input.required();
662
+ attribute = input.required();
663
+ metadata = input.required();
664
+ clicked = output();
665
+ reference = computed(() => {
666
+ const ref = this.data()?.ref;
633
667
  return {
634
- start: rangeStart,
635
- end: rangeEnd > count ? count : rangeEnd,
668
+ text: this.generateText(ref),
669
+ href: this.generateLink(ref),
636
670
  };
637
671
  });
638
- constructor() {
639
- this.setEffects();
640
- }
641
- onPageSizeChange(option) {
642
- this.selectedPageSize.set(option);
672
+ onClick(event) {
673
+ event.preventDefault();
674
+ event.stopImmediatePropagation();
675
+ this.clicked.emit(this.data());
643
676
  }
644
- onNavigateClick(param) {
645
- this.selectedPageIndex.update((index) => {
646
- if (param === 'prev' && this.canNavigatePrev(index)) {
647
- return index - 1;
648
- }
649
- if (param === 'next' && this.canNavigateNext(index)) {
650
- return index + 1;
651
- }
652
- return index;
653
- });
677
+ generateText(ref) {
678
+ if (ref) {
679
+ return ref.display_name || ref.object_id;
680
+ }
681
+ return '';
654
682
  }
655
- canNavigatePrev(index = this.selectedPageIndex()) {
656
- return index > 0;
683
+ generateLink(ref) {
684
+ if (ref) {
685
+ // statedb%23Tag%3ALATEST%3Atag_01%3ALATEST
686
+ const href = `/details/object/${ref.class_name}/${ref.resource}%2523${ref.class_name}%253A${ref.class_version}%253A${ref.object_id}%253A${ref.object_version}`;
687
+ return ref?.address ? `${href}?address=${ref.address}` : href;
688
+ }
657
689
  }
658
- canNavigateNext(index = this.selectedPageIndex()) {
659
- return index < this.getLastPageIndex();
690
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ReferenceTemplate, deps: [], target: i0.ɵɵFactoryTarget.Component });
691
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ReferenceTemplate, isStandalone: true, selector: "ng-component", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, attribute: { classPropertyName: "attribute", publicName: "attribute", isSignal: true, isRequired: true, transformFunction: null }, metadata: { classPropertyName: "metadata", publicName: "metadata", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { clicked: "clicked" }, ngImport: i0, template: `
692
+ <span class="le-table-template le-template-reference">
693
+ @if (reference(); as reference) {
694
+ @if (reference.href) {
695
+ <a
696
+ [href]="reference.href"
697
+ [attr.aria-label]="reference.text"
698
+ (click)="onClick($event)"
699
+ target="_blank"
700
+ >{{ reference.text }}</a
701
+ >
702
+ } @else {
703
+ {{ reference.text }}
704
+ }
705
+ }
706
+ </span>
707
+ `, isInline: true });
708
+ }
709
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ReferenceTemplate, decorators: [{
710
+ type: Component,
711
+ args: [{
712
+ template: `
713
+ <span class="le-table-template le-template-reference">
714
+ @if (reference(); as reference) {
715
+ @if (reference.href) {
716
+ <a
717
+ [href]="reference.href"
718
+ [attr.aria-label]="reference.text"
719
+ (click)="onClick($event)"
720
+ target="_blank"
721
+ >{{ reference.text }}</a
722
+ >
723
+ } @else {
724
+ {{ reference.text }}
725
+ }
726
+ }
727
+ </span>
728
+ `,
729
+ }]
730
+ }] });
731
+
732
+ class JSONTemplate {
733
+ data = input.required();
734
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: JSONTemplate, deps: [], target: i0.ɵɵFactoryTarget.Component });
735
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.21", type: JSONTemplate, isStandalone: true, selector: "ng-component", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `<pre class="le-table-template le-template-json">{{
736
+ data() ? (data() | json) : '–'
737
+ }}</pre>`, isInline: true, dependencies: [{ kind: "pipe", type: JsonPipe, name: "json" }] });
738
+ }
739
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: JSONTemplate, decorators: [{
740
+ type: Component,
741
+ args: [{
742
+ template: `<pre class="le-table-template le-template-json">{{
743
+ data() ? (data() | json) : '–'
744
+ }}</pre>`,
745
+ imports: [JsonPipe],
746
+ }]
747
+ }] });
748
+
749
+ const TABLE_SELL_TEMPLATE_NAMES = {
750
+ StringTemplate: 'StringTemplate',
751
+ ReferenceTemplate: 'ReferenceTemplate',
752
+ JsonTemplate: 'JsonTemplate',
753
+ };
754
+ const TABLE_CELL_TEMPLATES = {
755
+ StringTemplate: StringTemplate,
756
+ ReferenceTemplate: ReferenceTemplate,
757
+ JsonTemplate: JSONTemplate,
758
+ };
759
+
760
+ class TableViewCellDirective {
761
+ vcr = inject(ViewContainerRef);
762
+ componentRef;
763
+ type = input();
764
+ data = input.required();
765
+ column = input();
766
+ metadata = input();
767
+ clicked = output();
768
+ constructor() {
769
+ this.setEffects();
660
770
  }
661
771
  setEffects() {
662
772
  effect(() => {
663
- const pageSize = this.pageSize();
664
- untracked(() => {
665
- this.selectedPageSize.set(pageSize);
666
- });
667
- });
668
- effect(() => {
669
- const pageSize = this.selectedPageSize();
773
+ const type = this.type();
774
+ const data = this.data();
775
+ const column = this.column();
776
+ const metadata = this.metadata();
670
777
  untracked(() => {
671
- const selectedPageIndex = this.selectedPageIndex();
672
- const pageIndex = this.getPageIndexOnPageSizeChange();
673
- if (selectedPageIndex !== pageIndex) {
674
- this.selectedPageIndex.set(pageIndex);
778
+ const component = (type && TABLE_CELL_TEMPLATES[type]) || TABLE_CELL_TEMPLATES['StringTemplate'];
779
+ if (this.componentRef) {
780
+ this.componentRef.destroy();
675
781
  }
676
- else {
677
- this.pageChange.emit({
678
- pageSize: pageSize,
679
- pageIndex: pageIndex,
782
+ this.componentRef = this.vcr.createComponent(component);
783
+ this.componentRef?.setInput('data', data);
784
+ if (type === 'ReferenceTemplate') {
785
+ if (column) {
786
+ this.componentRef?.setInput('attribute', column);
787
+ }
788
+ if (metadata) {
789
+ this.componentRef?.setInput('metadata', metadata);
790
+ }
791
+ const sub = (this.componentRef?.instance).clicked.subscribe(data => {
792
+ this.clicked.emit(data);
680
793
  });
794
+ this.componentRef?.onDestroy(() => sub.unsubscribe());
681
795
  }
682
796
  });
683
797
  });
684
- effect(() => {
685
- const index = this.selectedPageIndex();
686
- untracked(() => {
687
- this.pageChange.emit({
688
- pageSize: this.selectedPageSize(),
689
- pageIndex: index,
690
- });
691
- });
692
- });
693
798
  }
694
- /**
695
- * @return page index or last available page index for selected page size
696
- */
697
- getPageIndexOnPageSizeChange() {
698
- const selectedPageIndex = this.selectedPageIndex();
699
- const lasPageIndex = this.getLastPageIndex();
700
- return selectedPageIndex > lasPageIndex ? lasPageIndex : selectedPageIndex;
701
- }
702
- /**
703
- * @return last available page index
704
- */
705
- getLastPageIndex() {
706
- const count = this.entriesCount();
707
- if (count === 0)
708
- return 0;
709
- return Math.ceil(count / this.selectedPageSize()) - 1;
710
- }
711
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewPaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
712
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: TableViewPaginationComponent, isStandalone: true, selector: "table-view-pagination", inputs: { pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: true, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: true, transformFunction: null }, entriesCount: { classPropertyName: "entriesCount", publicName: "entriesCount", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { pageChange: "pageChange" }, ngImport: i0, template: "<div class=\"le-pagination\">\n <div class=\"le-pagination-options\">\n <span>Items per page:</span>\n\n <button [cdkMenuTriggerFor]=\"optionsMenu\" class=\"le-button\">\n {{ selectedPageSize() }}\n\n <le-icon name=\"arrow-down\"></le-icon>\n </button>\n\n <ng-template #optionsMenu>\n <div class=\"le-pagination-option-list\" cdkMenu>\n @for (option of pageSizeOptions(); track option) {\n <button cdkMenuItem class=\"le-pagination-option-item\" (click)=\"onPageSizeChange(option)\">\n {{ option }}\n </button>\n }\n </div>\n </ng-template>\n </div>\n\n <div class=\"spacer\"></div>\n\n <div class=\"le-pagination-range\">\n {{ entriesRange().start }} - {{ entriesRange().end }} of {{ entriesCount() }}\n </div>\n\n <div class=\"le-pagination-navigation\">\n <button\n class=\"le-navigation le-navigation-prev\"\n [tabindex]=\"canNavigatePrev() ? 0 : -1\"\n [disabled]=\"!canNavigatePrev()\"\n (click)=\"onNavigateClick('prev')\"\n >\n <le-icon class=\"le-chevron le-chevron--left\" name=\"chevron\"></le-icon>\n </button>\n\n <button\n class=\"le-navigation le-navigation-next\"\n [tabindex]=\"canNavigateNext() ? 0 : -1\"\n [disabled]=\"!canNavigateNext()\"\n (click)=\"onNavigateClick('next')\"\n >\n <le-icon class=\"le-chevron le-chevron--right\" name=\"chevron\"></le-icon>\n </button>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: CdkMenuTrigger, selector: "[cdkMenuTriggerFor]", inputs: ["cdkMenuTriggerFor", "cdkMenuPosition", "cdkMenuTriggerData"], outputs: ["cdkMenuOpened", "cdkMenuClosed"], exportAs: ["cdkMenuTriggerFor"] }, { kind: "directive", type: CdkMenu, selector: "[cdkMenu]", outputs: ["closed"], exportAs: ["cdkMenu"] }, { kind: "directive", type: CdkMenuItem, selector: "[cdkMenuItem]", inputs: ["cdkMenuItemDisabled", "cdkMenuitemTypeaheadLabel"], outputs: ["cdkMenuItemTriggered"], exportAs: ["cdkMenuItem"] }, { kind: "ngmodule", type: A11yModule }, { kind: "component", type: LeIconComponent, selector: "le-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
799
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewCellDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
800
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.21", type: TableViewCellDirective, isStandalone: true, selector: "[tableViewCell]", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: false, transformFunction: null }, metadata: { classPropertyName: "metadata", publicName: "metadata", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, ngImport: i0 });
713
801
  }
714
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewPaginationComponent, decorators: [{
715
- type: Component,
716
- args: [{ selector: 'table-view-pagination', imports: [CdkMenuTrigger, CdkMenu, CdkMenuItem, A11yModule, LeIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"le-pagination\">\n <div class=\"le-pagination-options\">\n <span>Items per page:</span>\n\n <button [cdkMenuTriggerFor]=\"optionsMenu\" class=\"le-button\">\n {{ selectedPageSize() }}\n\n <le-icon name=\"arrow-down\"></le-icon>\n </button>\n\n <ng-template #optionsMenu>\n <div class=\"le-pagination-option-list\" cdkMenu>\n @for (option of pageSizeOptions(); track option) {\n <button cdkMenuItem class=\"le-pagination-option-item\" (click)=\"onPageSizeChange(option)\">\n {{ option }}\n </button>\n }\n </div>\n </ng-template>\n </div>\n\n <div class=\"spacer\"></div>\n\n <div class=\"le-pagination-range\">\n {{ entriesRange().start }} - {{ entriesRange().end }} of {{ entriesCount() }}\n </div>\n\n <div class=\"le-pagination-navigation\">\n <button\n class=\"le-navigation le-navigation-prev\"\n [tabindex]=\"canNavigatePrev() ? 0 : -1\"\n [disabled]=\"!canNavigatePrev()\"\n (click)=\"onNavigateClick('prev')\"\n >\n <le-icon class=\"le-chevron le-chevron--left\" name=\"chevron\"></le-icon>\n </button>\n\n <button\n class=\"le-navigation le-navigation-next\"\n [tabindex]=\"canNavigateNext() ? 0 : -1\"\n [disabled]=\"!canNavigateNext()\"\n (click)=\"onNavigateClick('next')\"\n >\n <le-icon class=\"le-chevron le-chevron--right\" name=\"chevron\"></le-icon>\n </button>\n </div>\n</div>\n" }]
802
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewCellDirective, decorators: [{
803
+ type: Directive,
804
+ args: [{
805
+ selector: '[tableViewCell]',
806
+ }]
717
807
  }], ctorParameters: () => [] });
718
808
 
719
- const isPlaceholder$1 = (value) => {
720
- return value.startsWith('{') && value.endsWith('}');
721
- };
722
- const mapSortStringToSort = (sort) => {
723
- return sort.startsWith('-') ? [sort.slice(1), 'desc'] : [sort, 'desc'];
724
- };
725
- const mapSortStringListToSortMap = (sortList) => {
726
- return sortList.reduce((acc, sort) => {
727
- const { 0: key, 1: value } = mapSortStringToSort(sort);
728
- acc.set(key, value);
729
- return acc;
730
- }, new Map());
731
- };
732
- const mapSortMapToSortStringList = (sortMap) => {
733
- return [...sortMap].reduce((acc, sort) => {
734
- const prefix = sort[1] === 'asc' ? '' : '-';
735
- acc.push(`${prefix}${sort[0]}`);
736
- return acc;
737
- }, []);
738
- };
739
- const mapFiltersToFilterString = (filters) => {
740
- return Object.entries(filters)
741
- .reduce((acc, filter) => {
742
- return acc.concat(`filter[${filter[0]}]=${filter[1]}`);
743
- }, [])
744
- .join('&');
745
- };
746
- const buildRequestContext = (params, ctx) => {
747
- const requestContext = {};
748
- if (ctx.hasPagination && params.pageIndex !== undefined) {
749
- requestContext['pageIndex'] = params.pageIndex;
750
- requestContext['pageSize'] = params.pageSize;
751
- }
752
- if (ctx.isSortable && params.sort) {
753
- requestContext['sort'] = params.sort;
754
- }
755
- if (params.filters && Object.keys(params.filters).length > 0) {
756
- requestContext['filters'] = params.filters;
757
- }
758
- return requestContext;
759
- };
760
- const buildRequestBody = (params) => {
761
- const body = {};
762
- if (params.sort?.length) {
763
- body['ordering'] = params.sort;
764
- }
765
- if (params.filters && Object.keys(params.filters).length > 0) {
766
- body['filters'] = params.filters;
767
- }
768
- if (params.pageIndex !== undefined) {
769
- body['page'] = params.pageIndex + 1;
770
- }
771
- if (params.pageSize) {
772
- body['page_size'] = params.pageSize;
773
- }
774
- return body;
775
- };
776
- const buildQueryString = (params) => {
777
- const query = [];
778
- if (params.pageIndex !== undefined) {
779
- query.push(`page=${params.pageIndex + 1}`);
780
- }
781
- if (params.pageSize) {
782
- query.push(`page_size=${params.pageSize}`);
783
- }
784
- if (params.sort?.length) {
785
- query.push(`ordering=${params.sort.join(',')}`);
786
- }
787
- if (params.filters && Object.keys(params.filters).length > 0) {
788
- query.push(mapFiltersToFilterString(params.filters));
809
+ class BlockViewComponent {
810
+ data = input.required();
811
+ columns = input.required();
812
+ event = output();
813
+ onCellClicked(data) {
814
+ this.event.emit({ type: 'cell_clicked', data });
815
+ this.event.emit({ type: 'close' });
789
816
  }
790
- return query.filter((item) => !!item).join('&');
791
- };
792
-
793
- class LoadingViewComponent {
794
- headerHeight = input(0);
795
- rowHeight = input(40);
796
- rowCount = input(1);
797
- rows = computed(() => {
798
- return new Array(this.rowCount()).fill(null).map((_, i) => i);
799
- });
800
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LoadingViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
801
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: LoadingViewComponent, isStandalone: true, selector: "app-loading-view", inputs: { headerHeight: { classPropertyName: "headerHeight", publicName: "headerHeight", isSignal: true, isRequired: false, transformFunction: null }, rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: false, transformFunction: null }, rowCount: { classPropertyName: "rowCount", publicName: "rowCount", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"preloader\">\n @if (headerHeight()) {\n <div class=\"preloader-row\" [style.height.px]=\"headerHeight()\"></div>\n }\n\n @for (row of rows(); track row) {\n <div class=\"preloader-row\" [style.height.px]=\"rowHeight()\"></div>\n }\n</div>\n", styles: [".preloader{display:flex;flex-direction:column;width:100%;gap:8px}.preloader-row{background:#f5f5f5 no-repeat;animation:pulse 1.5s cubic-bezier(.4,0,.2,1) infinite;animation-delay:.5s}@keyframes pulse{0%{opacity:1}50%{opacity:.5}to{opacity:1}}\n"] });
817
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: BlockViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
818
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: BlockViewComponent, isStandalone: true, selector: "le-block-view", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { event: "event" }, ngImport: i0, template: "<div class=\"block-view\">\n @for (column of columns(); track column) {\n <div class=\"block-view-item\">\n <div class=\"block-view-label\">\n {{column.label}}\n </div>\n\n <div class=\"block-view-value\">\n @if (data(); as row) {\n <ng-template\n tableViewCell\n [data]=\"row[column.key]\"\n [type]=\"column.column_format?.cellTemplate\"\n [column]=\"column\"\n [metadata]=\"row._metadata\"\n (clicked)=\"onCellClicked($event)\"\n ></ng-template>\n }\n </div>\n </div>\n }\n</div>\n", dependencies: [{ kind: "directive", type: TableViewCellDirective, selector: "[tableViewCell]", inputs: ["type", "data", "column", "metadata"], outputs: ["clicked"] }] });
802
819
  }
803
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LoadingViewComponent, decorators: [{
820
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: BlockViewComponent, decorators: [{
804
821
  type: Component,
805
- args: [{ selector: 'app-loading-view', template: "<div class=\"preloader\">\n @if (headerHeight()) {\n <div class=\"preloader-row\" [style.height.px]=\"headerHeight()\"></div>\n }\n\n @for (row of rows(); track row) {\n <div class=\"preloader-row\" [style.height.px]=\"rowHeight()\"></div>\n }\n</div>\n", styles: [".preloader{display:flex;flex-direction:column;width:100%;gap:8px}.preloader-row{background:#f5f5f5 no-repeat;animation:pulse 1.5s cubic-bezier(.4,0,.2,1) infinite;animation-delay:.5s}@keyframes pulse{0%{opacity:1}50%{opacity:.5}to{opacity:1}}\n"] }]
822
+ args: [{ selector: 'le-block-view', imports: [TableViewCellDirective], template: "<div class=\"block-view\">\n @for (column of columns(); track column) {\n <div class=\"block-view-item\">\n <div class=\"block-view-label\">\n {{column.label}}\n </div>\n\n <div class=\"block-view-value\">\n @if (data(); as row) {\n <ng-template\n tableViewCell\n [data]=\"row[column.key]\"\n [type]=\"column.column_format?.cellTemplate\"\n [column]=\"column\"\n [metadata]=\"row._metadata\"\n (clicked)=\"onCellClicked($event)\"\n ></ng-template>\n }\n </div>\n </div>\n }\n</div>\n" }]
806
823
  }] });
807
824
 
808
- class TableViewActions {
809
- actions = input();
810
- actionClicked = output();
811
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewActions, deps: [], target: i0.ɵɵFactoryTarget.Component });
812
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: TableViewActions, isStandalone: true, selector: "table-view-actions", inputs: { actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionClicked: "actionClicked" }, host: { properties: { "class.le-table-view-actions": "true" } }, ngImport: i0, template: `
813
- @for (action of actions(); track action) {
814
- <button
815
- class="le-button le-button-flat le-button--success"
816
- (click)="actionClicked.emit(action)"
817
- >
818
- {{ action.label }}
819
- </button>
825
+ class SidePanelComponent {
826
+ dataService = inject(LEDataService);
827
+ _selectedTab = signal(0);
828
+ data = input.required();
829
+ config = input();
830
+ event = output();
831
+ node = this.dataService.view;
832
+ tabs = computed(() => {
833
+ const data = this.data();
834
+ return data.tabs.length ? data.tabs : undefined;
835
+ });
836
+ selectedTabIndex = this._selectedTab.asReadonly();
837
+ selectedTab = computed(() => {
838
+ return this.tabs()?.[this.selectedTabIndex()];
839
+ });
840
+ constructor() {
841
+ effect(() => {
842
+ const data = this.data();
843
+ untracked(() => {
844
+ if (data.node) {
845
+ this.dataService.setView(data.node, true);
846
+ }
847
+ });
848
+ });
820
849
  }
821
- `, isInline: true });
822
- }
823
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewActions, decorators: [{
824
- type: Component,
825
- args: [{
826
- selector: 'table-view-actions',
827
- template: `
828
- @for (action of actions(); track action) {
829
- <button
830
- class="le-button le-button-flat le-button--success"
831
- (click)="actionClicked.emit(action)"
832
- >
833
- {{ action.label }}
834
- </button>
850
+ onEvent(event) {
851
+ this.event.emit(event);
835
852
  }
836
- `,
837
- host: {
838
- '[class.le-table-view-actions]': 'true',
839
- },
840
- }]
841
- }] });
842
-
843
- class StringTemplate {
844
- data = input.required();
845
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: StringTemplate, deps: [], target: i0.ɵɵFactoryTarget.Component });
846
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.21", type: StringTemplate, isStandalone: true, selector: "ng-component", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `<span class="le-table-template le-template-string">{{ data() ?? '–' }}</span>`, isInline: true });
853
+ onTabClick(index) {
854
+ this._selectedTab.set(index);
855
+ }
856
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidePanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
857
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SidePanelComponent, isStandalone: true, selector: "ng-component", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { event: "event" }, host: { properties: { "style.width": "\"100%\"", "style.overflow": "\"auto\"", "style.padding": "\"0 16px\"" } }, providers: [LEDataService, LEFiltersService], ngImport: i0, template: "@if (node(); as node) {\n <le-node [node]=\"node\" [config]=\"data()?.config\" (event)=\"onEvent($event)\"></le-node>\n}\n\n@if (tabs(); as tabs) {\n <div class=\"le-tabs-nav\">\n @for (tab of tabs; track tab.type; let idx = $index) {\n <button\n class=\"le-button le-button-flat le-button--success\"\n [attr.aria-label]=\"'Select ' + tab.type\"\n [class.le-button--success]=\"selectedTabIndex() === idx\"\n (click)=\"onTabClick(idx)\"\n >\n {{ tab.label }}\n </button>\n }\n <span class=\"spacer\"></span>\n\n <button\n aria-label=\"Close side panel\"\n class=\"le-button le-button-flat\"\n (click)=\"event.emit({ type: 'close' })\"\n >Close</button>\n </div>\n}\n\n@if (selectedTab(); as selectedTab) {\n <div class=\"le-tabs-content\">\n @switch (selectedTab.type) {\n @case ('tree') {\n <le-tree-view [data]=\"selectedTab.data\"></le-tree-view>\n }\n @case ('table') {\n <le-node\n [node]=\"selectedTab.data\"\n [config]=\"data()?.config\"\n (event)=\"onEvent($event)\"\n ></le-node>\n }\n @case ('block') {\n <le-block-view\n [data]=\"selectedTab.data\"\n [columns]=\"selectedTab.columns\"\n (event)=\"onEvent($event)\"\n ></le-block-view>\n }\n }\n </div>\n}\n", dependencies: [{ kind: "component", type: i0.forwardRef(() => NodeComponent), selector: "le-node", inputs: ["node", "config"], outputs: ["event"] }, { kind: "component", type: i0.forwardRef(() => TreeViewComponent), selector: "le-tree-view", inputs: ["data"] }, { kind: "component", type: i0.forwardRef(() => BlockViewComponent), selector: "le-block-view", inputs: ["data", "columns"], outputs: ["event"] }] });
847
858
  }
848
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: StringTemplate, decorators: [{
859
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidePanelComponent, decorators: [{
849
860
  type: Component,
850
- args: [{
851
- template: `<span class="le-table-template le-template-string">{{ data() ?? '–' }}</span>`,
852
- }]
853
- }] });
861
+ args: [{ host: {
862
+ '[style.width]': '"100%"',
863
+ '[style.overflow]': '"auto"',
864
+ '[style.padding]': '"0 16px"',
865
+ }, imports: [forwardRef(() => NodeComponent), TreeViewComponent, BlockViewComponent], providers: [LEDataService, LEFiltersService], template: "@if (node(); as node) {\n <le-node [node]=\"node\" [config]=\"data()?.config\" (event)=\"onEvent($event)\"></le-node>\n}\n\n@if (tabs(); as tabs) {\n <div class=\"le-tabs-nav\">\n @for (tab of tabs; track tab.type; let idx = $index) {\n <button\n class=\"le-button le-button-flat le-button--success\"\n [attr.aria-label]=\"'Select ' + tab.type\"\n [class.le-button--success]=\"selectedTabIndex() === idx\"\n (click)=\"onTabClick(idx)\"\n >\n {{ tab.label }}\n </button>\n }\n <span class=\"spacer\"></span>\n\n <button\n aria-label=\"Close side panel\"\n class=\"le-button le-button-flat\"\n (click)=\"event.emit({ type: 'close' })\"\n >Close</button>\n </div>\n}\n\n@if (selectedTab(); as selectedTab) {\n <div class=\"le-tabs-content\">\n @switch (selectedTab.type) {\n @case ('tree') {\n <le-tree-view [data]=\"selectedTab.data\"></le-tree-view>\n }\n @case ('table') {\n <le-node\n [node]=\"selectedTab.data\"\n [config]=\"data()?.config\"\n (event)=\"onEvent($event)\"\n ></le-node>\n }\n @case ('block') {\n <le-block-view\n [data]=\"selectedTab.data\"\n [columns]=\"selectedTab.columns\"\n (event)=\"onEvent($event)\"\n ></le-block-view>\n }\n }\n </div>\n}\n" }]
866
+ }], ctorParameters: () => [] });
854
867
 
855
- class ReferenceTemplate {
856
- data = input.required();
857
- attribute = input.required();
858
- metadata = input.required();
859
- clicked = output();
860
- reference = computed(() => {
861
- const ref = this.data()?.ref;
862
- return {
863
- text: this.generateText(ref),
864
- href: this.generateLink(ref),
865
- };
866
- });
867
- onClick(event) {
868
- event.preventDefault();
869
- event.stopImmediatePropagation();
870
- this.clicked.emit(this.data());
868
+ const positionMap = {
869
+ right: (position) => position.right().top('0'),
870
+ left: (position) => position.left().top('0'),
871
+ top: (position) => position.top('0'),
872
+ bottom: (position) => position.bottom('0'),
873
+ };
874
+ class LeSidePanelService {
875
+ overlay = inject(Overlay);
876
+ breakpointObserver = inject(BreakpointObserver);
877
+ overlayRef;
878
+ output = new Subject();
879
+ show(data, config) {
880
+ if (this.overlayRef)
881
+ this.hide();
882
+ const destroy$ = new Subject();
883
+ this.overlayRef = this.overlay.create({
884
+ width: this.getWidth(config),
885
+ height: this.getHeight(config),
886
+ panelClass: 'le-side-panel',
887
+ hasBackdrop: config.hasBackdrop ?? true,
888
+ positionStrategy: this.getPositionStrategy(config),
889
+ scrollStrategy: this.overlay.scrollStrategies.reposition(),
890
+ });
891
+ this.overlayRef.addPanelClass(this.getClosedClass(config));
892
+ this.overlayRef?.outsidePointerEvents().subscribe({
893
+ next: () => {
894
+ this.overlayRef?.addPanelClass(this.getClosedClass(config));
895
+ this.delayed(() => this.hide());
896
+ },
897
+ });
898
+ const componentRef = this.overlayRef.attach(new ComponentPortal(SidePanelComponent, null, config.injector));
899
+ componentRef.setInput('data', data);
900
+ this.delayed(() => this.overlayRef?.removePanelClass(this.getClosedClass(config)));
901
+ const sub = componentRef.instance.event.subscribe((event) => {
902
+ this.output.next(event);
903
+ if (event.type === 'close') {
904
+ this.overlayRef?.addPanelClass(this.getClosedClass(config));
905
+ this.delayed(() => this.hide());
906
+ }
907
+ });
908
+ componentRef.onDestroy(() => {
909
+ sub.unsubscribe();
910
+ destroy$.next();
911
+ destroy$.complete();
912
+ });
913
+ return this.output.pipe(takeUntil(destroy$));
871
914
  }
872
- generateText(ref) {
873
- if (ref) {
874
- return ref.display_name || ref.object_id;
875
- }
876
- return '';
915
+ hide() {
916
+ this.overlayRef?.dispose();
917
+ this.overlayRef = undefined;
877
918
  }
878
- generateLink(ref) {
879
- if (ref) {
880
- // statedb%23Tag%3ALATEST%3Atag_01%3ALATEST
881
- const href = `/details/object/${ref.class_name}/${ref.resource}%2523${ref.class_name}%253A${ref.class_version}%253A${ref.object_id}%253A${ref.object_version}`;
882
- return ref?.address ? `${href}?address=${ref.address}` : href;
919
+ delayed(fn) {
920
+ setTimeout(() => fn(), 300);
921
+ }
922
+ getHeight(config) {
923
+ if (config.height) {
924
+ return config.height;
925
+ }
926
+ if (config.position === 'top' || config.position === 'bottom') {
927
+ if (this.breakpointObserver.isMatched(Breakpoints.XSmall)) {
928
+ return '80vh';
929
+ }
930
+ else if (this.breakpointObserver.isMatched(Breakpoints.Small)) {
931
+ return '60vh';
932
+ }
933
+ else {
934
+ return '40vh';
935
+ }
883
936
  }
937
+ return '100vh';
884
938
  }
885
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ReferenceTemplate, deps: [], target: i0.ɵɵFactoryTarget.Component });
886
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ReferenceTemplate, isStandalone: true, selector: "ng-component", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, attribute: { classPropertyName: "attribute", publicName: "attribute", isSignal: true, isRequired: true, transformFunction: null }, metadata: { classPropertyName: "metadata", publicName: "metadata", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { clicked: "clicked" }, ngImport: i0, template: `
887
- <span class="le-table-template le-template-reference">
888
- @if (reference(); as reference) {
889
- @if (reference.href) {
890
- <a
891
- [href]="reference.href"
892
- [attr.aria-label]="reference.text"
893
- (click)="onClick($event)"
894
- target="_blank"
895
- >{{ reference.text }}</a
896
- >
897
- } @else {
898
- {{ reference.text }}
939
+ getWidth(config) {
940
+ if (config.width) {
941
+ return config.width;
899
942
  }
900
- }
901
- </span>
902
- `, isInline: true });
903
- }
904
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ReferenceTemplate, decorators: [{
905
- type: Component,
906
- args: [{
907
- template: `
908
- <span class="le-table-template le-template-reference">
909
- @if (reference(); as reference) {
910
- @if (reference.href) {
911
- <a
912
- [href]="reference.href"
913
- [attr.aria-label]="reference.text"
914
- (click)="onClick($event)"
915
- target="_blank"
916
- >{{ reference.text }}</a
917
- >
918
- } @else {
919
- {{ reference.text }}
943
+ if (config.position === 'left' || config.position === 'right') {
944
+ if (this.breakpointObserver.isMatched(Breakpoints.XSmall)) {
945
+ return '80vw';
946
+ }
947
+ else if (this.breakpointObserver.isMatched(Breakpoints.Small)) {
948
+ return '60vw';
949
+ }
950
+ else {
951
+ return '40vw';
952
+ }
920
953
  }
921
- }
922
- </span>
923
- `,
924
- }]
925
- }] });
926
-
927
- class JSONTemplate {
928
- data = input.required();
929
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: JSONTemplate, deps: [], target: i0.ɵɵFactoryTarget.Component });
930
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.21", type: JSONTemplate, isStandalone: true, selector: "ng-component", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `<pre class="le-table-template le-template-json">{{
931
- data() ? (data() | json) : '–'
932
- }}</pre>`, isInline: true, dependencies: [{ kind: "pipe", type: JsonPipe, name: "json" }] });
954
+ else {
955
+ return '100vw';
956
+ }
957
+ }
958
+ getClosedClass(config) {
959
+ return `le-side-panel--${config.position}`;
960
+ }
961
+ getPositionStrategy({ position }) {
962
+ let positionStrategy = this.overlay.position().global();
963
+ if (positionMap[position]) {
964
+ return positionMap[position](positionStrategy);
965
+ }
966
+ return positionStrategy;
967
+ }
968
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeSidePanelService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
969
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeSidePanelService, providedIn: 'root' });
933
970
  }
934
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: JSONTemplate, decorators: [{
935
- type: Component,
971
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeSidePanelService, decorators: [{
972
+ type: Injectable,
936
973
  args: [{
937
- template: `<pre class="le-table-template le-template-json">{{
938
- data() ? (data() | json) : '–'
939
- }}</pre>`,
940
- imports: [JsonPipe],
974
+ providedIn: 'root',
941
975
  }]
942
976
  }] });
943
977
 
944
- const TABLE_SELL_TEMPLATE_NAMES = {
945
- StringTemplate: 'StringTemplate',
946
- ReferenceTemplate: 'ReferenceTemplate',
947
- JsonTemplate: 'JsonTemplate',
948
- };
949
- const TABLE_CELL_TEMPLATES = {
950
- StringTemplate: StringTemplate,
951
- ReferenceTemplate: ReferenceTemplate,
952
- JsonTemplate: JSONTemplate,
953
- };
954
-
955
- class TableViewCellDirective {
956
- vcr = inject(ViewContainerRef);
957
- componentRef;
958
- type = input();
959
- data = input.required();
960
- column = input();
961
- metadata = input();
962
- clicked = output();
978
+ class TableViewPaginationComponent {
979
+ pageSize = input.required();
980
+ pageSizeOptions = input.required();
981
+ entriesCount = input.required();
982
+ pageChange = output();
983
+ selectedPageSize = signal(0);
984
+ selectedPageIndex = signal(0);
985
+ entriesRange = computed(() => {
986
+ const selectedPageIndex = this.selectedPageIndex();
987
+ const pageSize = this.pageSize();
988
+ const count = this.entriesCount();
989
+ const rangeStart = selectedPageIndex * pageSize;
990
+ const rangeEnd = rangeStart + pageSize;
991
+ return {
992
+ start: rangeStart,
993
+ end: rangeEnd > count ? count : rangeEnd,
994
+ };
995
+ });
963
996
  constructor() {
964
997
  this.setEffects();
965
998
  }
999
+ onPageSizeChange(option) {
1000
+ this.selectedPageSize.set(option);
1001
+ }
1002
+ onNavigateClick(param) {
1003
+ this.selectedPageIndex.update((index) => {
1004
+ if (param === 'prev' && this.canNavigatePrev(index)) {
1005
+ return index - 1;
1006
+ }
1007
+ if (param === 'next' && this.canNavigateNext(index)) {
1008
+ return index + 1;
1009
+ }
1010
+ return index;
1011
+ });
1012
+ }
1013
+ canNavigatePrev(index = this.selectedPageIndex()) {
1014
+ return index > 0;
1015
+ }
1016
+ canNavigateNext(index = this.selectedPageIndex()) {
1017
+ return index < this.getLastPageIndex();
1018
+ }
966
1019
  setEffects() {
967
1020
  effect(() => {
968
- const type = this.type();
969
- const data = this.data();
970
- const column = this.column();
971
- const metadata = this.metadata();
1021
+ const pageSize = this.pageSize();
972
1022
  untracked(() => {
973
- const component = (type && TABLE_CELL_TEMPLATES[type]) || TABLE_CELL_TEMPLATES['StringTemplate'];
974
- if (this.componentRef) {
975
- this.componentRef.destroy();
1023
+ this.selectedPageSize.set(pageSize);
1024
+ });
1025
+ });
1026
+ effect(() => {
1027
+ const pageSize = this.selectedPageSize();
1028
+ untracked(() => {
1029
+ const selectedPageIndex = this.selectedPageIndex();
1030
+ const pageIndex = this.getPageIndexOnPageSizeChange();
1031
+ if (selectedPageIndex !== pageIndex) {
1032
+ this.selectedPageIndex.set(pageIndex);
976
1033
  }
977
- this.componentRef = this.vcr.createComponent(component);
978
- this.componentRef?.setInput('data', data);
979
- if (type === 'ReferenceTemplate') {
980
- if (column) {
981
- this.componentRef?.setInput('attribute', column);
982
- }
983
- if (metadata) {
984
- this.componentRef?.setInput('metadata', metadata);
985
- }
986
- const sub = (this.componentRef?.instance).clicked.subscribe(data => {
987
- this.clicked.emit(data);
1034
+ else {
1035
+ this.pageChange.emit({
1036
+ pageSize: pageSize,
1037
+ pageIndex: pageIndex,
988
1038
  });
989
- this.componentRef?.onDestroy(() => sub.unsubscribe());
990
1039
  }
991
1040
  });
992
1041
  });
1042
+ effect(() => {
1043
+ const index = this.selectedPageIndex();
1044
+ untracked(() => {
1045
+ this.pageChange.emit({
1046
+ pageSize: this.selectedPageSize(),
1047
+ pageIndex: index,
1048
+ });
1049
+ });
1050
+ });
993
1051
  }
994
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewCellDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
995
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.21", type: TableViewCellDirective, isStandalone: true, selector: "[tableViewCell]", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: false, transformFunction: null }, metadata: { classPropertyName: "metadata", publicName: "metadata", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, ngImport: i0 });
996
- }
997
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewCellDirective, decorators: [{
998
- type: Directive,
999
- args: [{
1000
- selector: '[tableViewCell]',
1001
- }]
1002
- }], ctorParameters: () => [] });
1003
-
1004
- const flattenNodes = (nodes) => {
1005
- const flattenedNodes = [];
1006
- for (const node of nodes) {
1007
- flattenedNodes.push(node);
1008
- if (node.leafs) {
1009
- flattenedNodes.push(...flattenNodes(node.leafs));
1010
- }
1052
+ /**
1053
+ * @return page index or last available page index for selected page size
1054
+ */
1055
+ getPageIndexOnPageSizeChange() {
1056
+ const selectedPageIndex = this.selectedPageIndex();
1057
+ const lasPageIndex = this.getLastPageIndex();
1058
+ return selectedPageIndex > lasPageIndex ? lasPageIndex : selectedPageIndex;
1011
1059
  }
1012
- return flattenedNodes;
1013
- };
1014
- const toTree = (obj, label) => {
1015
- if (obj !== null && typeof obj === 'object') {
1016
- const entries = Array.isArray(obj)
1017
- ? obj.map((v, i) => toTree(v, String(i)))
1018
- : Object.entries(obj).map((item) => toTree(item[1], item[0]));
1019
- return { label, leafs: entries };
1060
+ /**
1061
+ * @return last available page index
1062
+ */
1063
+ getLastPageIndex() {
1064
+ const count = this.entriesCount();
1065
+ if (count === 0)
1066
+ return 0;
1067
+ return Math.ceil(count / this.selectedPageSize()) - 1;
1020
1068
  }
1021
- return { label, value: obj };
1022
- };
1023
- const mapObjectToTree = (data) => {
1024
- return Object.entries(data).map((item) => toTree(item[1], item[0]));
1025
- };
1069
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewPaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1070
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: TableViewPaginationComponent, isStandalone: true, selector: "table-view-pagination", inputs: { pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: true, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: true, transformFunction: null }, entriesCount: { classPropertyName: "entriesCount", publicName: "entriesCount", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { pageChange: "pageChange" }, ngImport: i0, template: "<div class=\"le-pagination\">\n <div class=\"le-pagination-options\">\n <span>Items per page:</span>\n\n <button [cdkMenuTriggerFor]=\"optionsMenu\" class=\"le-button\">\n {{ selectedPageSize() }}\n\n <le-icon name=\"arrow-down\"></le-icon>\n </button>\n\n <ng-template #optionsMenu>\n <div class=\"le-pagination-option-list\" cdkMenu>\n @for (option of pageSizeOptions(); track option) {\n <button cdkMenuItem class=\"le-pagination-option-item\" (click)=\"onPageSizeChange(option)\">\n {{ option }}\n </button>\n }\n </div>\n </ng-template>\n </div>\n\n <div class=\"spacer\"></div>\n\n <div class=\"le-pagination-range\">\n {{ entriesRange().start }} - {{ entriesRange().end }} of {{ entriesCount() }}\n </div>\n\n <div class=\"le-pagination-navigation\">\n <button\n class=\"le-navigation le-navigation-prev\"\n [tabindex]=\"canNavigatePrev() ? 0 : -1\"\n [disabled]=\"!canNavigatePrev()\"\n (click)=\"onNavigateClick('prev')\"\n >\n <le-icon class=\"le-chevron le-chevron--left\" name=\"chevron\"></le-icon>\n </button>\n\n <button\n class=\"le-navigation le-navigation-next\"\n [tabindex]=\"canNavigateNext() ? 0 : -1\"\n [disabled]=\"!canNavigateNext()\"\n (click)=\"onNavigateClick('next')\"\n >\n <le-icon class=\"le-chevron le-chevron--right\" name=\"chevron\"></le-icon>\n </button>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: CdkMenuTrigger, selector: "[cdkMenuTriggerFor]", inputs: ["cdkMenuTriggerFor", "cdkMenuPosition", "cdkMenuTriggerData"], outputs: ["cdkMenuOpened", "cdkMenuClosed"], exportAs: ["cdkMenuTriggerFor"] }, { kind: "directive", type: CdkMenu, selector: "[cdkMenu]", outputs: ["closed"], exportAs: ["cdkMenu"] }, { kind: "directive", type: CdkMenuItem, selector: "[cdkMenuItem]", inputs: ["cdkMenuItemDisabled", "cdkMenuitemTypeaheadLabel"], outputs: ["cdkMenuItemTriggered"], exportAs: ["cdkMenuItem"] }, { kind: "ngmodule", type: A11yModule }, { kind: "component", type: LeIconComponent, selector: "le-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1071
+ }
1072
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewPaginationComponent, decorators: [{
1073
+ type: Component,
1074
+ args: [{ selector: 'table-view-pagination', imports: [CdkMenuTrigger, CdkMenu, CdkMenuItem, A11yModule, LeIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"le-pagination\">\n <div class=\"le-pagination-options\">\n <span>Items per page:</span>\n\n <button [cdkMenuTriggerFor]=\"optionsMenu\" class=\"le-button\">\n {{ selectedPageSize() }}\n\n <le-icon name=\"arrow-down\"></le-icon>\n </button>\n\n <ng-template #optionsMenu>\n <div class=\"le-pagination-option-list\" cdkMenu>\n @for (option of pageSizeOptions(); track option) {\n <button cdkMenuItem class=\"le-pagination-option-item\" (click)=\"onPageSizeChange(option)\">\n {{ option }}\n </button>\n }\n </div>\n </ng-template>\n </div>\n\n <div class=\"spacer\"></div>\n\n <div class=\"le-pagination-range\">\n {{ entriesRange().start }} - {{ entriesRange().end }} of {{ entriesCount() }}\n </div>\n\n <div class=\"le-pagination-navigation\">\n <button\n class=\"le-navigation le-navigation-prev\"\n [tabindex]=\"canNavigatePrev() ? 0 : -1\"\n [disabled]=\"!canNavigatePrev()\"\n (click)=\"onNavigateClick('prev')\"\n >\n <le-icon class=\"le-chevron le-chevron--left\" name=\"chevron\"></le-icon>\n </button>\n\n <button\n class=\"le-navigation le-navigation-next\"\n [tabindex]=\"canNavigateNext() ? 0 : -1\"\n [disabled]=\"!canNavigateNext()\"\n (click)=\"onNavigateClick('next')\"\n >\n <le-icon class=\"le-chevron le-chevron--right\" name=\"chevron\"></le-icon>\n </button>\n </div>\n</div>\n" }]
1075
+ }], ctorParameters: () => [] });
1026
1076
 
1027
- class TreeViewComponent {
1028
- treeControl = new NestedTreeControl((node) => node.leafs);
1029
- data = input();
1030
- source = computed(() => {
1031
- return new ArrayDataSource(mapObjectToTree(this.data() ?? {}));
1077
+ class LoadingViewComponent {
1078
+ headerHeight = input(0);
1079
+ rowHeight = input(40);
1080
+ rowCount = input(1);
1081
+ rows = computed(() => {
1082
+ return new Array(this.rowCount()).fill(null).map((_, i) => i);
1032
1083
  });
1033
- hasChild = (_, node) => !!node.leafs && node.leafs.length > 0;
1034
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TreeViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1035
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.21", type: TreeViewComponent, isStandalone: true, selector: "le-tree-view", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<cdk-tree [dataSource]=\"source()\" [treeControl]=\"treeControl\">\n <!-- Tree node template for leaf nodes -->\n <cdk-nested-tree-node *cdkTreeNodeDef=\"let node\" class=\"le-tree-node\">\n <div class=\"le-tree-row\">\n <b>{{node.label | uppercase}}</b>: &nbsp;&nbsp;&nbsp; {{node.value}}\n </div>\n </cdk-nested-tree-node>\n\n <!-- Tree node template for expandable nodes -->\n <cdk-nested-tree-node *cdkTreeNodeDef=\"let node; when: hasChild\" class=\"le-tree-node\">\n\n <a class=\"le-tree-row\" [class.le-tree-row--expanded]=\"treeControl.isExpanded(node)\" [attr.aria-label]=\"'Toggle ' + node.label\" cdkTreeNodeToggle>\n <b>{{node.label | uppercase}}</b>:\n\n <le-icon class=\"le-tree-chevron\" name=\"chevron\"></le-icon>\n </a>\n\n <div [class.le-tree-invisible]=\"!treeControl.isExpanded(node)\">\n <ng-container cdkTreeNodeOutlet></ng-container>\n </div>\n </cdk-nested-tree-node>\n</cdk-tree>\n", dependencies: [{ kind: "component", type: CdkTree, selector: "cdk-tree", inputs: ["dataSource", "treeControl", "trackBy"], exportAs: ["cdkTree"] }, { kind: "directive", type: CdkNestedTreeNode, selector: "cdk-nested-tree-node", exportAs: ["cdkNestedTreeNode"] }, { kind: "directive", type: CdkTreeNodeDef, selector: "[cdkTreeNodeDef]", inputs: ["cdkTreeNodeDefWhen"] }, { kind: "directive", type: CdkTreeNodeOutlet, selector: "[cdkTreeNodeOutlet]" }, { kind: "component", type: LeIconComponent, selector: "le-icon", inputs: ["name", "size"] }, { kind: "directive", type: CdkTreeNodeToggle, selector: "[cdkTreeNodeToggle]", inputs: ["cdkTreeNodeToggleRecursive"] }, { kind: "pipe", type: UpperCasePipe, name: "uppercase" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1084
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LoadingViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1085
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: LoadingViewComponent, isStandalone: true, selector: "app-loading-view", inputs: { headerHeight: { classPropertyName: "headerHeight", publicName: "headerHeight", isSignal: true, isRequired: false, transformFunction: null }, rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: false, transformFunction: null }, rowCount: { classPropertyName: "rowCount", publicName: "rowCount", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"preloader\">\n @if (headerHeight()) {\n <div class=\"preloader-row\" [style.height.px]=\"headerHeight()\"></div>\n }\n\n @for (row of rows(); track row) {\n <div class=\"preloader-row\" [style.height.px]=\"rowHeight()\"></div>\n }\n</div>\n", styles: [".preloader{display:flex;flex-direction:column;width:100%;gap:8px}.preloader-row{background:#f5f5f5 no-repeat;animation:pulse 1.5s cubic-bezier(.4,0,.2,1) infinite;animation-delay:.5s}@keyframes pulse{0%{opacity:1}50%{opacity:.5}to{opacity:1}}\n"] });
1036
1086
  }
1037
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TreeViewComponent, decorators: [{
1087
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LoadingViewComponent, decorators: [{
1038
1088
  type: Component,
1039
- args: [{ selector: 'le-tree-view', imports: [
1040
- CdkTree,
1041
- CdkNestedTreeNode,
1042
- CdkTreeNodeDef,
1043
- CdkTreeNodeOutlet,
1044
- LeIconComponent,
1045
- CdkTreeNodeToggle,
1046
- UpperCasePipe,
1047
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<cdk-tree [dataSource]=\"source()\" [treeControl]=\"treeControl\">\n <!-- Tree node template for leaf nodes -->\n <cdk-nested-tree-node *cdkTreeNodeDef=\"let node\" class=\"le-tree-node\">\n <div class=\"le-tree-row\">\n <b>{{node.label | uppercase}}</b>: &nbsp;&nbsp;&nbsp; {{node.value}}\n </div>\n </cdk-nested-tree-node>\n\n <!-- Tree node template for expandable nodes -->\n <cdk-nested-tree-node *cdkTreeNodeDef=\"let node; when: hasChild\" class=\"le-tree-node\">\n\n <a class=\"le-tree-row\" [class.le-tree-row--expanded]=\"treeControl.isExpanded(node)\" [attr.aria-label]=\"'Toggle ' + node.label\" cdkTreeNodeToggle>\n <b>{{node.label | uppercase}}</b>:\n\n <le-icon class=\"le-tree-chevron\" name=\"chevron\"></le-icon>\n </a>\n\n <div [class.le-tree-invisible]=\"!treeControl.isExpanded(node)\">\n <ng-container cdkTreeNodeOutlet></ng-container>\n </div>\n </cdk-nested-tree-node>\n</cdk-tree>\n" }]
1089
+ args: [{ selector: 'app-loading-view', template: "<div class=\"preloader\">\n @if (headerHeight()) {\n <div class=\"preloader-row\" [style.height.px]=\"headerHeight()\"></div>\n }\n\n @for (row of rows(); track row) {\n <div class=\"preloader-row\" [style.height.px]=\"rowHeight()\"></div>\n }\n</div>\n", styles: [".preloader{display:flex;flex-direction:column;width:100%;gap:8px}.preloader-row{background:#f5f5f5 no-repeat;animation:pulse 1.5s cubic-bezier(.4,0,.2,1) infinite;animation-delay:.5s}@keyframes pulse{0%{opacity:1}50%{opacity:.5}to{opacity:1}}\n"] }]
1048
1090
  }] });
1049
1091
 
1050
- class BlockViewComponent {
1051
- data = input.required();
1052
- columns = input.required();
1053
- event = output();
1054
- onCellClicked(data) {
1055
- this.event.emit({ type: 'cell_clicked', data });
1056
- this.event.emit({ type: 'close' });
1092
+ class TableViewActions {
1093
+ actions = input();
1094
+ actionClicked = output();
1095
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewActions, deps: [], target: i0.ɵɵFactoryTarget.Component });
1096
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: TableViewActions, isStandalone: true, selector: "table-view-actions", inputs: { actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionClicked: "actionClicked" }, host: { properties: { "class.le-table-view-actions": "true" } }, ngImport: i0, template: `
1097
+ @for (action of actions(); track action) {
1098
+ <button
1099
+ class="le-button le-button-flat le-button--success"
1100
+ (click)="actionClicked.emit(action)"
1101
+ >
1102
+ {{ action.label }}
1103
+ </button>
1057
1104
  }
1058
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: BlockViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1059
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: BlockViewComponent, isStandalone: true, selector: "le-block-view", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { event: "event" }, ngImport: i0, template: "<div class=\"block-view\">\n @for (column of columns(); track column) {\n <div class=\"block-view-item\">\n <div class=\"block-view-label\">\n {{column.label}}\n </div>\n\n <div class=\"block-view-value\">\n @if (data(); as row) {\n <ng-template\n tableViewCell\n [data]=\"row[column.key]\"\n [type]=\"column.column_format?.cellTemplate\"\n [column]=\"column\"\n [metadata]=\"row._metadata\"\n (clicked)=\"onCellClicked($event)\"\n ></ng-template>\n }\n </div>\n </div>\n }\n</div>\n", dependencies: [{ kind: "directive", type: TableViewCellDirective, selector: "[tableViewCell]", inputs: ["type", "data", "column", "metadata"], outputs: ["clicked"] }] });
1105
+ `, isInline: true });
1060
1106
  }
1061
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: BlockViewComponent, decorators: [{
1107
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewActions, decorators: [{
1062
1108
  type: Component,
1063
- args: [{ selector: 'le-block-view', imports: [TableViewCellDirective], template: "<div class=\"block-view\">\n @for (column of columns(); track column) {\n <div class=\"block-view-item\">\n <div class=\"block-view-label\">\n {{column.label}}\n </div>\n\n <div class=\"block-view-value\">\n @if (data(); as row) {\n <ng-template\n tableViewCell\n [data]=\"row[column.key]\"\n [type]=\"column.column_format?.cellTemplate\"\n [column]=\"column\"\n [metadata]=\"row._metadata\"\n (clicked)=\"onCellClicked($event)\"\n ></ng-template>\n }\n </div>\n </div>\n }\n</div>\n" }]
1064
- }] });
1065
-
1066
- class SidePanelComponent {
1067
- dataService = inject(LEDataService);
1068
- _selectedTab = signal(0);
1069
- data = input.required();
1070
- config = input();
1071
- event = output();
1072
- node = this.dataService.view;
1073
- tabs = computed(() => {
1074
- const data = this.data();
1075
- return data.tabs.length ? data.tabs : undefined;
1076
- });
1077
- selectedTabIndex = this._selectedTab.asReadonly();
1078
- selectedTab = computed(() => {
1079
- return this.tabs()?.[this.selectedTabIndex()];
1080
- });
1081
- constructor() {
1082
- effect(() => {
1083
- const data = this.data();
1084
- untracked(() => {
1085
- if (data.node) {
1086
- this.dataService.setView(data.node, true);
1087
- }
1088
- });
1089
- });
1109
+ args: [{
1110
+ selector: 'table-view-actions',
1111
+ template: `
1112
+ @for (action of actions(); track action) {
1113
+ <button
1114
+ class="le-button le-button-flat le-button--success"
1115
+ (click)="actionClicked.emit(action)"
1116
+ >
1117
+ {{ action.label }}
1118
+ </button>
1090
1119
  }
1091
- onEvent(event) {
1092
- this.event.emit(event);
1120
+ `,
1121
+ host: {
1122
+ '[class.le-table-view-actions]': 'true',
1123
+ },
1124
+ }]
1125
+ }] });
1126
+
1127
+ class TableDataSource extends DataSource {
1128
+ data;
1129
+ get count() {
1130
+ return this.data.value.length;
1093
1131
  }
1094
- onTabClick(index) {
1095
- this._selectedTab.set(index);
1132
+ constructor(data = []) {
1133
+ super();
1134
+ this.data = new BehaviorSubject(data);
1096
1135
  }
1097
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidePanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1098
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SidePanelComponent, isStandalone: true, selector: "ng-component", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { event: "event" }, host: { properties: { "style.width": "\"100%\"", "style.overflow": "\"auto\"", "style.padding": "\"0 16px\"" } }, providers: [LEDataService, LEFiltersService], ngImport: i0, template: "@if (node(); as node) {\n <le-node [node]=\"node\" [config]=\"data()?.config\" (event)=\"onEvent($event)\"></le-node>\n}\n\n@if (tabs(); as tabs) {\n <div class=\"le-tabs-nav\">\n @for (tab of tabs; track tab.type; let idx = $index) {\n <button\n class=\"le-button le-button-flat le-button--success\"\n [attr.aria-label]=\"'Select ' + tab.type\"\n [class.le-button--success]=\"selectedTabIndex() === idx\"\n (click)=\"onTabClick(idx)\"\n >\n {{ tab.label }}\n </button>\n }\n <span class=\"spacer\"></span>\n\n <button\n aria-label=\"Close side panel\"\n class=\"le-button le-button-flat\"\n (click)=\"event.emit({ type: 'close' })\"\n >Close</button>\n </div>\n}\n\n@if (selectedTab(); as selectedTab) {\n <div class=\"le-tabs-content\">\n @switch (selectedTab.type) {\n @case ('tree') {\n <le-tree-view [data]=\"selectedTab.data\"></le-tree-view>\n }\n @case ('table') {\n <le-node\n [node]=\"selectedTab.data\"\n [config]=\"data()?.config\"\n (event)=\"onEvent($event)\"\n ></le-node>\n }\n @case ('block') {\n <le-block-view\n [data]=\"selectedTab.data\"\n [columns]=\"selectedTab.columns\"\n (event)=\"onEvent($event)\"\n ></le-block-view>\n }\n }\n </div>\n}\n", dependencies: [{ kind: "component", type: i0.forwardRef(() => NodeComponent), selector: "le-node", inputs: ["node", "config"], outputs: ["event"] }, { kind: "component", type: i0.forwardRef(() => TreeViewComponent), selector: "le-tree-view", inputs: ["data"] }, { kind: "component", type: i0.forwardRef(() => BlockViewComponent), selector: "le-block-view", inputs: ["data", "columns"], outputs: ["event"] }] });
1136
+ getValueByIndex(index) {
1137
+ return this.data.value[index];
1138
+ }
1139
+ connect() {
1140
+ return this.data;
1141
+ }
1142
+ disconnect() { }
1099
1143
  }
1100
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidePanelComponent, decorators: [{
1101
- type: Component,
1102
- args: [{ host: {
1103
- '[style.width]': '"100%"',
1104
- '[style.overflow]': '"auto"',
1105
- '[style.padding]': '"0 16px"',
1106
- }, imports: [forwardRef(() => NodeComponent), TreeViewComponent, BlockViewComponent], providers: [LEDataService, LEFiltersService], template: "@if (node(); as node) {\n <le-node [node]=\"node\" [config]=\"data()?.config\" (event)=\"onEvent($event)\"></le-node>\n}\n\n@if (tabs(); as tabs) {\n <div class=\"le-tabs-nav\">\n @for (tab of tabs; track tab.type; let idx = $index) {\n <button\n class=\"le-button le-button-flat le-button--success\"\n [attr.aria-label]=\"'Select ' + tab.type\"\n [class.le-button--success]=\"selectedTabIndex() === idx\"\n (click)=\"onTabClick(idx)\"\n >\n {{ tab.label }}\n </button>\n }\n <span class=\"spacer\"></span>\n\n <button\n aria-label=\"Close side panel\"\n class=\"le-button le-button-flat\"\n (click)=\"event.emit({ type: 'close' })\"\n >Close</button>\n </div>\n}\n\n@if (selectedTab(); as selectedTab) {\n <div class=\"le-tabs-content\">\n @switch (selectedTab.type) {\n @case ('tree') {\n <le-tree-view [data]=\"selectedTab.data\"></le-tree-view>\n }\n @case ('table') {\n <le-node\n [node]=\"selectedTab.data\"\n [config]=\"data()?.config\"\n (event)=\"onEvent($event)\"\n ></le-node>\n }\n @case ('block') {\n <le-block-view\n [data]=\"selectedTab.data\"\n [columns]=\"selectedTab.columns\"\n (event)=\"onEvent($event)\"\n ></le-block-view>\n }\n }\n </div>\n}\n" }]
1107
- }], ctorParameters: () => [] });
1108
1144
 
1109
- const positionMap = {
1110
- right: (position) => position.right().top('0'),
1111
- left: (position) => position.left().top('0'),
1112
- top: (position) => position.top('0'),
1113
- bottom: (position) => position.bottom('0'),
1145
+ const isPlaceholder$1 = (value) => {
1146
+ return value.startsWith('{') && value.endsWith('}');
1114
1147
  };
1115
- class LeSidePanelService {
1116
- overlay = inject(Overlay);
1117
- breakpointObserver = inject(BreakpointObserver);
1118
- overlayRef;
1119
- output = new Subject();
1120
- show(data, config) {
1121
- if (this.overlayRef)
1122
- this.hide();
1123
- const destroy$ = new Subject();
1124
- this.overlayRef = this.overlay.create({
1125
- width: this.getWidth(config),
1126
- height: this.getHeight(config),
1127
- panelClass: 'le-side-panel',
1128
- hasBackdrop: config.hasBackdrop ?? true,
1129
- positionStrategy: this.getPositionStrategy(config),
1130
- scrollStrategy: this.overlay.scrollStrategies.reposition(),
1131
- });
1132
- this.overlayRef.addPanelClass(this.getClosedClass(config));
1133
- this.overlayRef?.outsidePointerEvents().subscribe({
1134
- next: () => {
1135
- this.overlayRef?.addPanelClass(this.getClosedClass(config));
1136
- this.delayed(() => this.hide());
1137
- },
1138
- });
1139
- const componentRef = this.overlayRef.attach(new ComponentPortal(SidePanelComponent, null, config.injector));
1140
- componentRef.setInput('data', data);
1141
- this.delayed(() => this.overlayRef?.removePanelClass(this.getClosedClass(config)));
1142
- const sub = componentRef.instance.event.subscribe((event) => {
1143
- this.output.next(event);
1144
- if (event.type === 'close') {
1145
- this.overlayRef?.addPanelClass(this.getClosedClass(config));
1146
- this.delayed(() => this.hide());
1147
- }
1148
- });
1149
- componentRef.onDestroy(() => {
1150
- sub.unsubscribe();
1151
- destroy$.next();
1152
- destroy$.complete();
1153
- });
1154
- return this.output.pipe(takeUntil(destroy$));
1148
+ const mapSortStringToSort = (sort) => {
1149
+ return sort.startsWith('-') ? [sort.slice(1), 'desc'] : [sort, 'desc'];
1150
+ };
1151
+ const mapSortStringListToSortMap = (sortList) => {
1152
+ return sortList.reduce((acc, sort) => {
1153
+ const { 0: key, 1: value } = mapSortStringToSort(sort);
1154
+ acc.set(key, value);
1155
+ return acc;
1156
+ }, new Map());
1157
+ };
1158
+ const mapSortMapToSortStringList = (sortMap) => {
1159
+ return [...sortMap].reduce((acc, sort) => {
1160
+ const prefix = sort[1] === 'asc' ? '' : '-';
1161
+ acc.push(`${prefix}${sort[0]}`);
1162
+ return acc;
1163
+ }, []);
1164
+ };
1165
+ const mapFiltersToFilterString = (filters) => {
1166
+ return Object.entries(filters)
1167
+ .reduce((acc, filter) => {
1168
+ return acc.concat(`filter[${filter[0]}]=${filter[1]}`);
1169
+ }, [])
1170
+ .join('&');
1171
+ };
1172
+ const buildRequestContext = (params, ctx) => {
1173
+ const requestContext = {};
1174
+ if (ctx.hasPagination && params.pageIndex !== undefined) {
1175
+ requestContext['pageIndex'] = params.pageIndex;
1176
+ requestContext['pageSize'] = params.pageSize;
1155
1177
  }
1156
- hide() {
1157
- this.overlayRef?.dispose();
1158
- this.overlayRef = undefined;
1178
+ if (ctx.isSortable && params.sort) {
1179
+ requestContext['sort'] = params.sort;
1159
1180
  }
1160
- delayed(fn) {
1161
- setTimeout(() => fn(), 300);
1181
+ if (params.filters && Object.keys(params.filters).length > 0) {
1182
+ requestContext['filters'] = params.filters;
1162
1183
  }
1163
- getHeight(config) {
1164
- if (config.height) {
1165
- return config.height;
1166
- }
1167
- if (config.position === 'top' || config.position === 'bottom') {
1168
- if (this.breakpointObserver.isMatched(Breakpoints.XSmall)) {
1169
- return '80vh';
1170
- }
1171
- else if (this.breakpointObserver.isMatched(Breakpoints.Small)) {
1172
- return '60vh';
1173
- }
1174
- else {
1175
- return '40vh';
1176
- }
1177
- }
1178
- return '100vh';
1184
+ return requestContext;
1185
+ };
1186
+ const buildRequestBody = (params) => {
1187
+ const body = {};
1188
+ if (params.sort?.length) {
1189
+ body['ordering'] = params.sort;
1179
1190
  }
1180
- getWidth(config) {
1181
- if (config.width) {
1182
- return config.width;
1183
- }
1184
- if (config.position === 'left' || config.position === 'right') {
1185
- if (this.breakpointObserver.isMatched(Breakpoints.XSmall)) {
1186
- return '80vw';
1187
- }
1188
- else if (this.breakpointObserver.isMatched(Breakpoints.Small)) {
1189
- return '60vw';
1190
- }
1191
- else {
1192
- return '40vw';
1193
- }
1194
- }
1195
- else {
1196
- return '100vw';
1197
- }
1191
+ if (params.filters && Object.keys(params.filters).length > 0) {
1192
+ body['filters'] = params.filters;
1198
1193
  }
1199
- getClosedClass(config) {
1200
- return `le-side-panel--${config.position}`;
1194
+ if (params.pageIndex !== undefined) {
1195
+ body['page'] = params.pageIndex + 1;
1201
1196
  }
1202
- getPositionStrategy({ position }) {
1203
- let positionStrategy = this.overlay.position().global();
1204
- if (positionMap[position]) {
1205
- return positionMap[position](positionStrategy);
1206
- }
1207
- return positionStrategy;
1197
+ if (params.pageSize) {
1198
+ body['page_size'] = params.pageSize;
1208
1199
  }
1209
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeSidePanelService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1210
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeSidePanelService, providedIn: 'root' });
1211
- }
1212
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeSidePanelService, decorators: [{
1213
- type: Injectable,
1214
- args: [{
1215
- providedIn: 'root',
1216
- }]
1217
- }] });
1200
+ return body;
1201
+ };
1202
+ const buildQueryString = (params) => {
1203
+ const query = [];
1204
+ if (params.pageIndex !== undefined) {
1205
+ query.push(`page=${params.pageIndex + 1}`);
1206
+ }
1207
+ if (params.pageSize) {
1208
+ query.push(`page_size=${params.pageSize}`);
1209
+ }
1210
+ if (params.sort?.length) {
1211
+ query.push(`ordering=${params.sort.join(',')}`);
1212
+ }
1213
+ if (params.filters && Object.keys(params.filters).length > 0) {
1214
+ query.push(mapFiltersToFilterString(params.filters));
1215
+ }
1216
+ return query.filter((item) => !!item).join('&');
1217
+ };
1218
1218
 
1219
1219
  class TableViewComponent {
1220
1220
  apiService = inject(LEApiService);
@@ -1243,7 +1243,7 @@ class TableViewComponent {
1243
1243
  const firstRow = this.data().getValueByIndex(0);
1244
1244
  const columnKeys = this.columns().map((column) => column.key);
1245
1245
  const hasVersion = !!(firstRow && firstRow._metadata && firstRow._metadata.object_version);
1246
- if (!this.config()?.hideInfo) {
1246
+ if (firstRow && !this.config()?.hideInfo) {
1247
1247
  result.push('info');
1248
1248
  }
1249
1249
  result.push(...columnKeys);
@@ -1757,10 +1757,20 @@ const mapFormValuesToJSON = (values) => {
1757
1757
  return JSON.stringify(values, null, 2);
1758
1758
  };
1759
1759
  const mapJSONToFormValues = (json) => {
1760
+ // Check if it's a string and try to parse it
1760
1761
  if (typeof json === 'string') {
1761
- return JSON.parse(json);
1762
+ try {
1763
+ return JSON.parse(json);
1764
+ }
1765
+ catch {
1766
+ throw new Error('The json string is not valid JSON');
1767
+ }
1768
+ }
1769
+ // Check if it's a plain object (not null, not array, not other types)
1770
+ if (json !== null && typeof json === 'object' && !Array.isArray(json)) {
1771
+ return json;
1762
1772
  }
1763
- throw new Error('The `json` parameter is not a valid JSON');
1773
+ throw new Error('The json parameter is not a valid JSON object');
1764
1774
  };
1765
1775
  const getTabJSONControl = (control, engine) => {
1766
1776
  let result;
@@ -1774,19 +1784,69 @@ const getTabJSONControl = (control, engine) => {
1774
1784
  });
1775
1785
  return result;
1776
1786
  };
1787
+ const mapValueToString = (value) => {
1788
+ if (typeof value === 'object' && value !== null) {
1789
+ if (Array.isArray(value)) {
1790
+ return value.map((chunk) => mapValueToString(chunk)).join('\n');
1791
+ }
1792
+ else {
1793
+ return mapValueToString(Object.entries(value));
1794
+ }
1795
+ }
1796
+ return `${value}`;
1797
+ };
1798
+
1799
+ class ToastListItemComponent {
1800
+ _engine = signal(null);
1801
+ _sections = signal([]);
1802
+ controls = input.required();
1803
+ actions = output();
1804
+ engine = this._engine.asReadonly();
1805
+ sections = this._sections.asReadonly();
1806
+ constructor() {
1807
+ effect((onCleanup) => {
1808
+ const controls = this.controls();
1809
+ const form = adaptForm(controls);
1810
+ const engine = createEngine(form);
1811
+ let cleanup = () => { };
1812
+ untracked(() => {
1813
+ this._engine.set(engine);
1814
+ this._sections.set(form.sections ?? []);
1815
+ cleanup = engine.on('action', ({ action }) => {
1816
+ const actionObj = action;
1817
+ this.actions.emit(actionObj.actions);
1818
+ });
1819
+ });
1820
+ onCleanup(() => {
1821
+ cleanup();
1822
+ });
1823
+ });
1824
+ }
1825
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ToastListItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1826
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ToastListItemComponent, isStandalone: true, selector: "le-toast-list-item", inputs: { controls: { classPropertyName: "controls", publicName: "controls", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { actions: "actions" }, ngImport: i0, template: "@if (engine(); as engine) {\n @for (section of sections(); track section) {\n @for (control of section.controls; track control) {\n <fe-field [engine]=\"engine\" [control]=\"control\"></fe-field>\n }\n }\n}\n", dependencies: [{ kind: "component", type: FeFieldHost, selector: "fe-field", inputs: ["engine", "control"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1827
+ }
1828
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ToastListItemComponent, decorators: [{
1829
+ type: Component,
1830
+ args: [{ selector: 'le-toast-list-item', imports: [FeFieldHost], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (engine(); as engine) {\n @for (section of sections(); track section) {\n @for (control of section.controls; track control) {\n <fe-field [engine]=\"engine\" [control]=\"control\"></fe-field>\n }\n }\n}\n" }]
1831
+ }], ctorParameters: () => [] });
1777
1832
 
1778
1833
  class ToastListComponent {
1779
1834
  toastService = inject(LeToastService);
1780
1835
  toasts = this.toastService.toasts;
1781
- onButtonClick(actions) {
1782
- actions.forEach((action) => this.toastService.processAction(action));
1836
+ onActions(actions) {
1837
+ actions.forEach((action) => {
1838
+ this.toastService.action$.next(action);
1839
+ if (action.type === 'close_popup') {
1840
+ this.toastService.remove(action.target_id);
1841
+ }
1842
+ });
1783
1843
  }
1784
1844
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ToastListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1785
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ToastListComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: "@if (toasts().length) {\n <div class=\"le-toast-list\">\n @for (toast of toasts(); track toast.id) {\n <div\n class=\"le-toast\"\n [class.le-toast--success]=\"toast.type === 'success'\"\n [class.le-toast--info]=\"toast.type === 'info'\"\n [class.le-toast--warning]=\"toast.type === 'warning'\"\n [class.le-toast--error]=\"toast.type === 'error'\"\n >\n <div class=\"le-toast-text-list\">\n @for (control of toast.controls; track control) {\n @if (control.type === 'text') {\n <p class=\"le-toast-text\">\n {{ control.value }}\n </p>\n }\n }\n </div>\n\n <div class=\"le-toast-button-list\">\n @for (control of toast.controls; track control) {\n @if (control.type === 'button') {\n <button\n class=\"le-button le-button-stroked\"\n [class.le-button--success]=\"toast.type === 'success'\"\n [class.le-button--info]=\"toast.type === 'info'\"\n [class.le-button--warning]=\"toast.type === 'warning'\"\n [class.le-button--error]=\"toast.type === 'error'\"\n (click)=\"onButtonClick(control.actions)\"\n >\n {{ control.label }}\n </button>\n }\n }\n </div>\n </div>\n }\n </div>\n}\n" });
1845
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ToastListComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: "@if (toasts().length) {\n <div class=\"le-toast-list\">\n @for (toast of toasts(); track toast.id) {\n <div\n class=\"le-toast\"\n [class.le-toast--success]=\"toast.type === 'success'\"\n [class.le-toast--info]=\"toast.type === 'info'\"\n [class.le-toast--warning]=\"toast.type === 'warning'\"\n [class.le-toast--error]=\"toast.type === 'error'\"\n >\n <le-toast-list-item\n [controls]=\"toast.controls\"\n (actions)=\"onActions($event)\"\n ></le-toast-list-item>\n </div>\n }\n </div>\n}\n", dependencies: [{ kind: "component", type: ToastListItemComponent, selector: "le-toast-list-item", inputs: ["controls"], outputs: ["actions"] }] });
1786
1846
  }
1787
1847
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ToastListComponent, decorators: [{
1788
1848
  type: Component,
1789
- args: [{ template: "@if (toasts().length) {\n <div class=\"le-toast-list\">\n @for (toast of toasts(); track toast.id) {\n <div\n class=\"le-toast\"\n [class.le-toast--success]=\"toast.type === 'success'\"\n [class.le-toast--info]=\"toast.type === 'info'\"\n [class.le-toast--warning]=\"toast.type === 'warning'\"\n [class.le-toast--error]=\"toast.type === 'error'\"\n >\n <div class=\"le-toast-text-list\">\n @for (control of toast.controls; track control) {\n @if (control.type === 'text') {\n <p class=\"le-toast-text\">\n {{ control.value }}\n </p>\n }\n }\n </div>\n\n <div class=\"le-toast-button-list\">\n @for (control of toast.controls; track control) {\n @if (control.type === 'button') {\n <button\n class=\"le-button le-button-stroked\"\n [class.le-button--success]=\"toast.type === 'success'\"\n [class.le-button--info]=\"toast.type === 'info'\"\n [class.le-button--warning]=\"toast.type === 'warning'\"\n [class.le-button--error]=\"toast.type === 'error'\"\n (click)=\"onButtonClick(control.actions)\"\n >\n {{ control.label }}\n </button>\n }\n }\n </div>\n </div>\n }\n </div>\n}\n" }]
1849
+ args: [{ imports: [ToastListItemComponent], template: "@if (toasts().length) {\n <div class=\"le-toast-list\">\n @for (toast of toasts(); track toast.id) {\n <div\n class=\"le-toast\"\n [class.le-toast--success]=\"toast.type === 'success'\"\n [class.le-toast--info]=\"toast.type === 'info'\"\n [class.le-toast--warning]=\"toast.type === 'warning'\"\n [class.le-toast--error]=\"toast.type === 'error'\"\n >\n <le-toast-list-item\n [controls]=\"toast.controls\"\n (actions)=\"onActions($event)\"\n ></le-toast-list-item>\n </div>\n }\n </div>\n}\n" }]
1790
1850
  }] });
1791
1851
 
1792
1852
  let ID = 100_000_000;
@@ -1795,6 +1855,7 @@ class LeToastService {
1795
1855
  overlay = inject(Overlay);
1796
1856
  _toasts = signal([]);
1797
1857
  toasts = this._toasts.asReadonly();
1858
+ action$ = new Subject();
1798
1859
  constructor() {
1799
1860
  effect(() => {
1800
1861
  const toasts = this._toasts();
@@ -1824,11 +1885,6 @@ class LeToastService {
1824
1885
  remove(id) {
1825
1886
  this._toasts.update((toasts) => toasts.filter((toast) => toast.id !== id));
1826
1887
  }
1827
- processAction(action) {
1828
- if (action.type === 'close_popup') {
1829
- this.remove(action.target);
1830
- }
1831
- }
1832
1888
  show() {
1833
1889
  if (this.overlayRef)
1834
1890
  return;
@@ -1844,19 +1900,26 @@ class LeToastService {
1844
1900
  }
1845
1901
  buildToast(type, messages) {
1846
1902
  const id = `${type}_${ID++}`;
1847
- const textControls = messages.map((message) => ({
1848
- type: 'text',
1903
+ return {
1904
+ id,
1905
+ type,
1906
+ controls: [...this.buildTextControls(id, messages), this.buildButtonControl(id)],
1907
+ };
1908
+ }
1909
+ buildTextControls(id, messages) {
1910
+ return messages.map((message, index) => ({
1911
+ type: 'paragraph',
1849
1912
  value: message,
1913
+ name: `${id}_${index}`
1850
1914
  }));
1851
- const buttonControl = {
1915
+ }
1916
+ buildButtonControl(id) {
1917
+ return {
1852
1918
  type: 'button',
1853
1919
  label: 'Ok',
1854
- actions: [{ type: 'close_popup', target: id }],
1855
- };
1856
- return {
1857
- id,
1858
- type,
1859
- controls: [...textControls, buttonControl],
1920
+ hideLabel: true,
1921
+ name: `${id}_button`,
1922
+ actions: [{ type: 'close_popup', target_id: id }],
1860
1923
  };
1861
1924
  }
1862
1925
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeToastService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
@@ -2108,13 +2171,18 @@ class FormViewComponent {
2108
2171
  this.viewportScroller.scrollToPosition([0, 0]);
2109
2172
  return of(null);
2110
2173
  },
2111
- show_popup: (action) => {
2174
+ show_popup: (action, response) => {
2112
2175
  this.toastService.notify({
2113
- ...action.item,
2176
+ controls: this.populatePopupControlsWithResponse(action.controls, response),
2177
+ id: action.id,
2114
2178
  type: 'success',
2115
2179
  });
2116
2180
  return of(null);
2117
2181
  },
2182
+ close_popup: (action) => {
2183
+ this.toastService.remove(action.target_id);
2184
+ return of(null);
2185
+ },
2118
2186
  open_url: (action) => {
2119
2187
  window.open(action.url, '_blank');
2120
2188
  return of(null);
@@ -2131,15 +2199,20 @@ class FormViewComponent {
2131
2199
  const engine = this._engine();
2132
2200
  try {
2133
2201
  if (isTabJSON(action.source)) {
2134
- const values = mapJSONToFormValues(getTabJSONControl(action.source, engine).value);
2135
- Object.entries(values).forEach(({ 0: key, 1: value }) => {
2136
- engine.values.set(key, value);
2137
- });
2202
+ const jsonTabControl = getTabJSONControl(action.source, engine);
2203
+ if (jsonTabControl) {
2204
+ const values = mapJSONToFormValues(jsonTabControl.value);
2205
+ Object.entries(values).forEach(({ 0: key, 1: value }) => {
2206
+ engine.values.set(key, value);
2207
+ });
2208
+ }
2138
2209
  }
2139
2210
  else {
2140
- const target = getTabJSONControl(action.target, engine);
2141
- const value = mapFormValuesToJSON(getTabFormValues(action.source, target, engine));
2142
- engine.values.set(target.id, value);
2211
+ const jsonTabControl = getTabJSONControl(action.target, engine);
2212
+ if (jsonTabControl) {
2213
+ const value = mapFormValuesToJSON(getTabFormValues(action.source, jsonTabControl, engine));
2214
+ engine.values.set(jsonTabControl.id, value);
2215
+ }
2143
2216
  }
2144
2217
  }
2145
2218
  catch (e) {
@@ -2184,6 +2257,9 @@ class FormViewComponent {
2184
2257
  this.init(form);
2185
2258
  });
2186
2259
  });
2260
+ this.toastService.action$
2261
+ .pipe(switchMap((action) => this.processAction(action)), takeUntilDestroyed())
2262
+ .subscribe();
2187
2263
  }
2188
2264
  init(form) {
2189
2265
  this._sections.set(this.sortSections(form.sections));
@@ -2279,6 +2355,19 @@ class FormViewComponent {
2279
2355
  }))
2280
2356
  .subscribe();
2281
2357
  }
2358
+ populatePopupControlsWithResponse(controls, response) {
2359
+ return controls.map((control) => {
2360
+ if (isPlaceholder(control.value)) {
2361
+ const path = getPlaceholderValue(control.value);
2362
+ const value = mapValueToString(getValueByPath({ response }, path));
2363
+ return {
2364
+ ...control,
2365
+ value,
2366
+ };
2367
+ }
2368
+ return control;
2369
+ });
2370
+ }
2282
2371
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2283
2372
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: FormViewComponent, isStandalone: true, selector: "form-view", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { event: "event" }, providers: [FormViewAttachmentService], ngImport: i0, template: "<h2>{{ node()?.title }}</h2>\n\n@if (isLoading()) {\n <app-loading-view [rowCount]=\"5\"></app-loading-view>\n} @else {\n @if (data(); as data) {\n <le-form-renderer\n [config]=\"config()\"\n [engine]=\"data.engine\"\n [sections]=\"data.sections\"\n [customCss]=\"data.customCss\"\n [topLevelControls]=\"data.topLevelControls\"\n (event)=\"event.emit($event)\"\n ></le-form-renderer>\n }\n}\n", dependencies: [{ kind: "component", type: LoadingViewComponent, selector: "app-loading-view", inputs: ["headerHeight", "rowHeight", "rowCount"] }, { kind: "component", type: FormRendererComponent, selector: "le-form-renderer", inputs: ["engine", "sections", "topLevelControls", "customCss", "config"], outputs: ["event"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2284
2373
  }