@planeasyinc/le-angular 0.0.19 → 0.0.21

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
- import { InjectionToken, inject, signal, Injectable, computed, effect, untracked, Directive, input, ChangeDetectionStrategy, Component, output, forwardRef, ViewContainerRef, Injector, Renderer2, ElementRef, DestroyRef, ChangeDetectorRef, viewChild } from '@angular/core';
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, 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,245 +599,50 @@ 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];
613
- }
614
- connect() {
615
- return this.data;
616
- }
617
- disconnect() { }
618
- }
619
-
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;
633
- return {
634
- start: rangeStart,
635
- end: rangeEnd > count ? count : rangeEnd,
636
- };
637
- });
638
- constructor() {
639
- this.setEffects();
640
- }
641
- onPageSizeChange(option) {
642
- this.selectedPageSize.set(option);
643
- }
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
- });
654
- }
655
- canNavigatePrev(index = this.selectedPageIndex()) {
656
- return index > 0;
657
- }
658
- canNavigateNext(index = this.selectedPageIndex()) {
659
- return index < this.getLastPageIndex();
660
- }
661
- setEffects() {
662
- effect(() => {
663
- const pageSize = this.pageSize();
664
- untracked(() => {
665
- this.selectedPageSize.set(pageSize);
666
- });
667
- });
668
- effect(() => {
669
- const pageSize = this.selectedPageSize();
670
- untracked(() => {
671
- const selectedPageIndex = this.selectedPageIndex();
672
- const pageIndex = this.getPageIndexOnPageSizeChange();
673
- if (selectedPageIndex !== pageIndex) {
674
- this.selectedPageIndex.set(pageIndex);
675
- }
676
- else {
677
- this.pageChange.emit({
678
- pageSize: pageSize,
679
- pageIndex: pageIndex,
680
- });
681
- }
682
- });
683
- });
684
- effect(() => {
685
- const index = this.selectedPageIndex();
686
- untracked(() => {
687
- this.pageChange.emit({
688
- pageSize: this.selectedPageSize(),
689
- pageIndex: index,
690
- });
691
- });
692
- });
693
- }
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 });
713
- }
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" }]
717
- }], ctorParameters: () => [] });
718
-
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;
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
+ }
757
609
  }
758
- return requestContext;
610
+ return flattenedNodes;
759
611
  };
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;
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 };
773
618
  }
774
- return body;
619
+ return { label, value: obj };
775
620
  };
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));
789
- }
790
- return query.filter((item) => !!item).join('&');
621
+ const mapObjectToTree = (data) => {
622
+ return Object.entries(data).map((item) => toTree(item[1], item[0]));
791
623
  };
792
624
 
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);
625
+ class TreeViewComponent {
626
+ treeControl = new NestedTreeControl((node) => node.leafs);
627
+ data = input();
628
+ source = computed(() => {
629
+ return new ArrayDataSource(mapObjectToTree(this.data() ?? {}));
799
630
  });
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"] });
802
- }
803
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LoadingViewComponent, decorators: [{
804
- 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"] }]
806
- }] });
807
-
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>
820
- }
821
- `, isInline: true });
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 });
822
634
  }
823
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewActions, decorators: [{
635
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TreeViewComponent, decorators: [{
824
636
  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>
835
- }
836
- `,
837
- host: {
838
- '[class.le-table-view-actions]': 'true',
839
- },
840
- }]
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" }]
841
646
  }] });
842
647
 
843
648
  class StringTemplate {
@@ -995,57 +800,11 @@ class TableViewCellDirective {
995
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 });
996
801
  }
997
802
  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
- }
1011
- }
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 };
1020
- }
1021
- return { label, value: obj };
1022
- };
1023
- const mapObjectToTree = (data) => {
1024
- return Object.entries(data).map((item) => toTree(item[1], item[0]));
1025
- };
1026
-
1027
- class TreeViewComponent {
1028
- treeControl = new NestedTreeControl((node) => node.leafs);
1029
- data = input();
1030
- source = computed(() => {
1031
- return new ArrayDataSource(mapObjectToTree(this.data() ?? {}));
1032
- });
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 });
1036
- }
1037
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TreeViewComponent, decorators: [{
1038
- 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" }]
1048
- }] });
803
+ type: Directive,
804
+ args: [{
805
+ selector: '[tableViewCell]',
806
+ }]
807
+ }], ctorParameters: () => [] });
1049
808
 
1050
809
  class BlockViewComponent {
1051
810
  data = input.required();
@@ -1216,6 +975,247 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
1216
975
  }]
1217
976
  }] });
1218
977
 
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
+ });
996
+ constructor() {
997
+ this.setEffects();
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
+ }
1019
+ setEffects() {
1020
+ effect(() => {
1021
+ const pageSize = this.pageSize();
1022
+ untracked(() => {
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);
1033
+ }
1034
+ else {
1035
+ this.pageChange.emit({
1036
+ pageSize: pageSize,
1037
+ pageIndex: pageIndex,
1038
+ });
1039
+ }
1040
+ });
1041
+ });
1042
+ effect(() => {
1043
+ const index = this.selectedPageIndex();
1044
+ untracked(() => {
1045
+ this.pageChange.emit({
1046
+ pageSize: this.selectedPageSize(),
1047
+ pageIndex: index,
1048
+ });
1049
+ });
1050
+ });
1051
+ }
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;
1059
+ }
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;
1068
+ }
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: () => [] });
1076
+
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);
1083
+ });
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"] });
1086
+ }
1087
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LoadingViewComponent, decorators: [{
1088
+ type: Component,
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"] }]
1090
+ }] });
1091
+
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>
1104
+ }
1105
+ `, isInline: true });
1106
+ }
1107
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewActions, decorators: [{
1108
+ type: Component,
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>
1119
+ }
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;
1131
+ }
1132
+ constructor(data = []) {
1133
+ super();
1134
+ this.data = new BehaviorSubject(data);
1135
+ }
1136
+ getValueByIndex(index) {
1137
+ return this.data.value[index];
1138
+ }
1139
+ connect() {
1140
+ return this.data;
1141
+ }
1142
+ disconnect() { }
1143
+ }
1144
+
1145
+ const isPlaceholder$1 = (value) => {
1146
+ return value.startsWith('{') && value.endsWith('}');
1147
+ };
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;
1177
+ }
1178
+ if (ctx.isSortable && params.sort) {
1179
+ requestContext['sort'] = params.sort;
1180
+ }
1181
+ if (params.filters && Object.keys(params.filters).length > 0) {
1182
+ requestContext['filters'] = params.filters;
1183
+ }
1184
+ return requestContext;
1185
+ };
1186
+ const buildRequestBody = (params) => {
1187
+ const body = {};
1188
+ if (params.sort?.length) {
1189
+ body['ordering'] = params.sort;
1190
+ }
1191
+ if (params.filters && Object.keys(params.filters).length > 0) {
1192
+ body['filters'] = params.filters;
1193
+ }
1194
+ if (params.pageIndex !== undefined) {
1195
+ body['page'] = params.pageIndex + 1;
1196
+ }
1197
+ if (params.pageSize) {
1198
+ body['page_size'] = params.pageSize;
1199
+ }
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
+
1219
1219
  class TableViewComponent {
1220
1220
  apiService = inject(LEApiService);
1221
1221
  dataService = inject(LEDataService);
@@ -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);
@@ -1727,12 +1727,13 @@ const isTabJSON = (control) => {
1727
1727
  };
1728
1728
  /**
1729
1729
  *
1730
- * @param source Control Config
1731
- * @param target Control Config
1730
+ * @param source Control Config with nested controls
1731
+ * @param target Control Config with json value
1732
1732
  * @param engine Form Engine
1733
1733
  *
1734
- * @description traverse source control tree, get latest value from state,
1735
- * if no value found in state, set target control initial value
1734
+ * @description
1735
+ * Traverse source Control Config tree, get latest value from state.
1736
+ * If no value found in state, set target Control Config initial value
1736
1737
  */
1737
1738
  const getTabFormValues = (source, target, engine) => {
1738
1739
  const result = {};
@@ -1741,7 +1742,10 @@ const getTabFormValues = (source, target, engine) => {
1741
1742
  if (!ctrl.id) {
1742
1743
  return;
1743
1744
  }
1744
- const value = engine.values.get(ctrl.id) ?? targetValueObject[ctrl.id];
1745
+ let value = engine.values.get(ctrl.id);
1746
+ if (value === undefined) {
1747
+ value = targetValueObject[ctrl.id];
1748
+ }
1745
1749
  if (value === undefined) {
1746
1750
  return;
1747
1751
  }
@@ -1753,10 +1757,20 @@ const mapFormValuesToJSON = (values) => {
1753
1757
  return JSON.stringify(values, null, 2);
1754
1758
  };
1755
1759
  const mapJSONToFormValues = (json) => {
1760
+ // Check if it's a string and try to parse it
1756
1761
  if (typeof json === 'string') {
1757
- 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
+ }
1758
1768
  }
1759
- throw new Error('The `json` parameter is not a valid JSON');
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;
1772
+ }
1773
+ throw new Error('The json parameter is not a valid JSON object');
1760
1774
  };
1761
1775
  const getTabJSONControl = (control, engine) => {
1762
1776
  let result;
@@ -2031,7 +2045,6 @@ class FormViewComponent {
2031
2045
  attachmentService = inject(FormViewAttachmentService);
2032
2046
  viewportScroller = inject(ViewportScroller);
2033
2047
  toastService = inject(LeToastService);
2034
- cdr = inject(ChangeDetectorRef);
2035
2048
  _isLoading = signal(false);
2036
2049
  _form = signal(null);
2037
2050
  _sections = signal([]);
@@ -2128,15 +2141,20 @@ class FormViewComponent {
2128
2141
  const engine = this._engine();
2129
2142
  try {
2130
2143
  if (isTabJSON(action.source)) {
2131
- const values = mapJSONToFormValues(getTabJSONControl(action.source, engine).value);
2132
- Object.entries(values).forEach(({ 0: key, 1: value }) => {
2133
- engine.values.set(key, value);
2134
- });
2144
+ const jsonTabControl = getTabJSONControl(action.source, engine);
2145
+ if (jsonTabControl) {
2146
+ const values = mapJSONToFormValues(jsonTabControl.value);
2147
+ Object.entries(values).forEach(({ 0: key, 1: value }) => {
2148
+ engine.values.set(key, value);
2149
+ });
2150
+ }
2135
2151
  }
2136
2152
  else {
2137
- const target = getTabJSONControl(action.target, engine);
2138
- const value = mapFormValuesToJSON(getTabFormValues(action.source, target, engine));
2139
- engine.values.set(target.id, value);
2153
+ const jsonTabControl = getTabJSONControl(action.target, engine);
2154
+ if (jsonTabControl) {
2155
+ const value = mapFormValuesToJSON(getTabFormValues(action.source, jsonTabControl, engine));
2156
+ engine.values.set(jsonTabControl.id, value);
2157
+ }
2140
2158
  }
2141
2159
  }
2142
2160
  catch (e) {