@planeasyinc/le-angular 0.0.1 → 0.0.3

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,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { InjectionToken, inject, signal, Injectable, computed, Directive, input, ChangeDetectionStrategy, Component, output, forwardRef, effect, untracked, ViewContainerRef, 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, firstValueFrom, of, tap, catchError, from, concatMap, finalize } from 'rxjs';
4
+ import { map, filter, distinctUntilChanged, BehaviorSubject, Subject, firstValueFrom, of, tap, catchError, from, concatMap, finalize, fromEvent, takeUntil, startWith } from 'rxjs';
5
5
  import { decodeJwt, UrlFragmentBuilder, normalizeConfig } from '@planeasyinc/le-core';
6
6
  import { CdkDrag } from '@angular/cdk/drag-drop';
7
7
  import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
@@ -16,7 +16,10 @@ import { adaptSections } from '@planeasyinc/fe-adapters-sections';
16
16
  import { createEngine } from '@planeasyinc/fe-core';
17
17
  import { FeFieldHost } from '@planeasyinc/fe-angular';
18
18
  import { Overlay } from '@angular/cdk/overlay';
19
- import { ComponentPortal } from '@angular/cdk/portal';
19
+ import { ComponentPortal, TemplatePortal } from '@angular/cdk/portal';
20
+ import { SelectionModel } from '@angular/cdk/collections';
21
+ import * as i1 from '@angular/forms';
22
+ import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
20
23
 
21
24
  const IS_LIBRARY_REQUEST = new HttpContextToken(() => false);
22
25
 
@@ -220,6 +223,48 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
220
223
  type: Injectable
221
224
  }] });
222
225
 
226
+ class LEFiltersService {
227
+ _shown = signal(false);
228
+ _options = signal([], {
229
+ equal: (a, b) => this.isEqual(a, b),
230
+ });
231
+ _selection = signal({}, {
232
+ equal: (a, b) => this.isEqual(a, b),
233
+ });
234
+ shown = this._shown.asReadonly();
235
+ options = this._options.asReadonly();
236
+ selection = this._selection.asReadonly();
237
+ open() {
238
+ this._shown.set(true);
239
+ }
240
+ close() {
241
+ this._shown.set(false);
242
+ }
243
+ updateSelection(value) {
244
+ this._selection.set(this.filterValues(value));
245
+ }
246
+ setOptions(options) {
247
+ this._options.set(options);
248
+ }
249
+ filterValues(value) {
250
+ const clone = Object.assign({}, value);
251
+ for (const key in clone) {
252
+ if (!clone[key]) {
253
+ delete clone[key];
254
+ }
255
+ }
256
+ return clone;
257
+ }
258
+ isEqual(a, b) {
259
+ return JSON.stringify(a) === JSON.stringify(b);
260
+ }
261
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LEFiltersService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
262
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LEFiltersService });
263
+ }
264
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LEFiltersService, decorators: [{
265
+ type: Injectable
266
+ }] });
267
+
223
268
  class DrawerContentDirective {
224
269
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: DrawerContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
225
270
  static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.21", type: DrawerContentDirective, isStandalone: true, selector: "[leDrawerContent]", host: { properties: { "class.le-drawer-content": "true" } }, ngImport: i0 });
@@ -254,6 +299,7 @@ class LeDrawerDirective {
254
299
  opened = input(false);
255
300
  width = input(DRAWER_OPENED_WIDTH);
256
301
  hideOnClose = input(false);
302
+ type = input('side');
257
303
  _width = computed(() => {
258
304
  if (this.opened()) {
259
305
  return this.width();
@@ -263,8 +309,11 @@ class LeDrawerDirective {
263
309
  }
264
310
  return DRAWER_CLOSED_WIDTH;
265
311
  });
312
+ _position = computed(() => {
313
+ return this.type() === 'over' ? 'absolute' : 'relative';
314
+ });
266
315
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeDrawerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
267
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.21", type: LeDrawerDirective, isStandalone: true, selector: "[leDrawer]", inputs: { opened: { classPropertyName: "opened", publicName: "opened", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, hideOnClose: { classPropertyName: "hideOnClose", publicName: "hideOnClose", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.le-drawer": "true", "class.le-drawer--open": "opened()", "style.width.px": "_width()" } }, ngImport: i0 });
316
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.21", type: LeDrawerDirective, isStandalone: true, selector: "[leDrawer]", inputs: { opened: { classPropertyName: "opened", publicName: "opened", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, hideOnClose: { classPropertyName: "hideOnClose", publicName: "hideOnClose", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.le-drawer": "true", "class.le-drawer--open": "opened()", "style.width.px": "_width()", "style.position": "_position()", "style.min-height": "\"100%\"", "style.left": "0", "style.top": "0" } }, ngImport: i0 });
268
317
  }
269
318
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeDrawerDirective, decorators: [{
270
319
  type: Directive,
@@ -273,7 +322,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
273
322
  host: {
274
323
  '[class.le-drawer]': 'true',
275
324
  '[class.le-drawer--open]': 'opened()',
276
- '[style.width.px]': '_width()'
325
+ '[style.width.px]': '_width()',
326
+ '[style.position]': '_position()',
327
+ '[style.min-height]': '"100%"',
328
+ '[style.left]': '0',
329
+ '[style.top]': '0',
277
330
  },
278
331
  }]
279
332
  }] });
@@ -302,21 +355,32 @@ const sort = {
302
355
  ]
303
356
  };
304
357
 
358
+ const close = {
359
+ name: 'close',
360
+ viewBox: '0 -960 960 960',
361
+ content: [
362
+ 'm256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z',
363
+ ],
364
+ };
365
+
305
366
  const ICONS_MAP = {
306
- 'chevron': chevron,
367
+ chevron: chevron,
307
368
  'arrow-down': arrowDown,
308
- 'sort': sort
369
+ sort: sort,
370
+ close: close,
309
371
  };
310
372
 
311
373
  class LeIconComponent {
312
374
  name = input.required();
313
375
  size = input(24);
314
- icon = computed(() => ({
315
- ...ICONS_MAP[this.name()],
316
- size: coerceNumberProperty(this.size()),
317
- }));
376
+ icon = computed(() => {
377
+ return {
378
+ ...ICONS_MAP[this.name()],
379
+ size: coerceNumberProperty(this.size()),
380
+ };
381
+ });
318
382
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
319
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: LeIconComponent, isStandalone: true, selector: "le-icon", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.width.px": "size()", "style.height.px": "size()", "style.display": "\"block\"" } }, ngImport: i0, template: `
383
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: LeIconComponent, isStandalone: true, selector: "le-icon", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.width.px": "size()", "style.height.px": "size()", "style.display": "\"flex\"" } }, ngImport: i0, template: `
320
384
  @if (icon(); as icon) {
321
385
  <svg
322
386
  [attr.viewBox]="icon.viewBox"
@@ -353,7 +417,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
353
417
  host: {
354
418
  '[style.width.px]': 'size()',
355
419
  '[style.height.px]': 'size()',
356
- '[style.display]': '"block"',
420
+ '[style.display]': '"flex"',
357
421
  }
358
422
  }]
359
423
  }] });
@@ -424,7 +488,7 @@ class SidebarComponent {
424
488
  element.style.transform = 'none';
425
489
  }
426
490
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
427
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SidebarComponent, isStandalone: true, selector: "le-sidebar", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, ngImport: i0, template: "<div leDrawerContainer>\n <aside leDrawer [opened]=\"isDrawerOpen()\" [width]=\"width()\" [hideOnClose]=\"isSmallScreen()\">\n <h3 class=\"le-sidebar-title\">\n <button\n class=\"le-sidebar-toggle\"\n (click)=\"onDrawerToggleClick($event)\"\n (keydown.enter)=\"onDrawerToggleClick($event)\"\n >\n @if (isDrawerOpen()) {\n {{ config().title }}\n }\n\n <le-icon name=\"chevron\"></le-icon>\n </button>\n </h3>\n\n @if (isDrawerOpen()) {\n <menu>\n @for (item of menu(); track item) {\n @if (isSection(item)) {\n <a\n class=\"le-menu-item\"\n tabindex=\"0\"\n [class.le-menu-item--expanded]=\"expanded().has(item)\"\n (click)=\"toggleExpanded($event, item)\"\n (keydown.enter)=\"toggleExpanded($event, item)\"\n >\n <div class=\"le-menu-title\">\n {{ item.title }}\n </div>\n\n <le-icon class=\"le-menu-chevron\" name=\"chevron\"></le-icon>\n </a>\n\n <div class=\"le-menu-group\" [class.le-menu-group--expanded]=\"expanded().has(item)\">\n @for (child of item.children; track child) {\n <a\n [tabindex]=\"expanded().has(item) ? 0 : -1\"\n class=\"le-menu-item\"\n [class.le-menu-item--selected]=\"view().id === child.id\"\n (click)=\"onSidebarItemClick($event, child)\"\n (keydown.enter)=\"onSidebarItemClick($event, child)\"\n >\n <div class=\"le-menu-title\">\n {{ child.title }}\n </div>\n </a>\n }\n </div>\n } @else {\n <a\n tabindex=\"0\"\n class=\"le-menu-item\"\n [class.le-menu-item--selected]=\"view().id === item.id\"\n (click)=\"onSidebarItemClick($event, item)\"\n (keydown.enter)=\"onSidebarItemClick($event, item)\"\n >\n <div class=\"le-menu-title\">\n {{ item.title }}\n </div>\n </a>\n }\n }\n </menu>\n\n <div class=\"le-drawer-resizer\" cdkDrag (cdkDragMoved)=\"onDragMoved($event)\">\n <span class=\"le-drag-icon\">\u283F</span>\n </div>\n }\n </aside>\n\n <main leDrawerContent>\n <ng-content></ng-content>\n </main>\n</div>\n", dependencies: [{ kind: "directive", type: DrawerContentDirective, selector: "[leDrawerContent]" }, { kind: "directive", type: DrawerContainerDirective, selector: "[leDrawerContainer]" }, { kind: "directive", type: LeDrawerDirective, selector: "[leDrawer]", inputs: ["opened", "width", "hideOnClose"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "component", type: LeIconComponent, selector: "le-icon", inputs: ["name", "size"] }] });
491
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SidebarComponent, isStandalone: true, selector: "le-sidebar", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, ngImport: i0, template: "<div leDrawerContainer>\n <aside leDrawer [opened]=\"isDrawerOpen()\" [width]=\"width()\" [hideOnClose]=\"isSmallScreen()\">\n <h3 class=\"le-sidebar-title\">\n <button\n class=\"le-sidebar-toggle\"\n (click)=\"onDrawerToggleClick($event)\"\n (keydown.enter)=\"onDrawerToggleClick($event)\"\n >\n @if (isDrawerOpen()) {\n {{ config().title }}\n }\n\n <le-icon name=\"chevron\"></le-icon>\n </button>\n </h3>\n\n @if (isDrawerOpen()) {\n <menu>\n @for (item of menu(); track item) {\n @if (isSection(item)) {\n <a\n class=\"le-menu-item\"\n tabindex=\"0\"\n [class.le-menu-item--expanded]=\"expanded().has(item)\"\n (click)=\"toggleExpanded($event, item)\"\n (keydown.enter)=\"toggleExpanded($event, item)\"\n >\n <div class=\"le-menu-title\">\n {{ item.title }}\n </div>\n\n <le-icon class=\"le-menu-chevron\" name=\"chevron\"></le-icon>\n </a>\n\n <div class=\"le-menu-group\" [class.le-menu-group--expanded]=\"expanded().has(item)\">\n @for (child of item.children; track child) {\n <a\n [tabindex]=\"expanded().has(item) ? 0 : -1\"\n class=\"le-menu-item\"\n [class.le-menu-item--selected]=\"view().id === child.id\"\n (click)=\"onSidebarItemClick($event, child)\"\n (keydown.enter)=\"onSidebarItemClick($event, child)\"\n >\n <div class=\"le-menu-title\">\n {{ child.title }}\n </div>\n </a>\n }\n </div>\n } @else {\n <a\n tabindex=\"0\"\n class=\"le-menu-item\"\n [class.le-menu-item--selected]=\"view().id === item.id\"\n (click)=\"onSidebarItemClick($event, item)\"\n (keydown.enter)=\"onSidebarItemClick($event, item)\"\n >\n <div class=\"le-menu-title\">\n {{ item.title }}\n </div>\n </a>\n }\n }\n </menu>\n\n <div class=\"le-drawer-resizer\" cdkDrag (cdkDragMoved)=\"onDragMoved($event)\">\n <span class=\"le-drag-icon\">\u283F</span>\n </div>\n }\n </aside>\n\n <main leDrawerContent>\n <ng-content></ng-content>\n </main>\n</div>\n", dependencies: [{ kind: "directive", type: DrawerContentDirective, selector: "[leDrawerContent]" }, { kind: "directive", type: DrawerContainerDirective, selector: "[leDrawerContainer]" }, { kind: "directive", type: LeDrawerDirective, selector: "[leDrawer]", inputs: ["opened", "width", "hideOnClose", "type"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "component", type: LeIconComponent, selector: "le-icon", inputs: ["name", "size"] }] });
428
492
  }
429
493
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidebarComponent, decorators: [{
430
494
  type: Component,
@@ -444,11 +508,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
444
508
  class GridComponent {
445
509
  node = input.required();
446
510
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: GridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
447
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: GridComponent, isStandalone: true, selector: "grid-view", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@for (child of node().children; track child.id) {\n <le-node [node]=\"child\"></le-node>\n}\n", dependencies: [{ kind: "component", type: i0.forwardRef(() => NodeComponent), selector: "le-node", inputs: ["node"] }] });
511
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: GridComponent, isStandalone: true, selector: "grid-view", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "class.le-gird-view": "true", "style.grid-template-columns": "node().layout.columns ?? 1" } }, ngImport: i0, template: "@for (child of node().children; track child.id) {\n <le-node [node]=\"child\"></le-node>\n}\n", dependencies: [{ kind: "component", type: i0.forwardRef(() => NodeComponent), selector: "le-node", inputs: ["node"] }] });
448
512
  }
449
513
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: GridComponent, decorators: [{
450
514
  type: Component,
451
- args: [{ selector: 'grid-view', imports: [forwardRef(() => NodeComponent)], template: "@for (child of node().children; track child.id) {\n <le-node [node]=\"child\"></le-node>\n}\n" }]
515
+ args: [{ selector: 'grid-view', imports: [forwardRef(() => NodeComponent)], host: {
516
+ '[class.le-gird-view]': 'true',
517
+ '[style.grid-template-columns]': 'node().layout.columns ?? 1',
518
+ }, template: "@for (child of node().children; track child.id) {\n <le-node [node]=\"child\"></le-node>\n}\n" }]
452
519
  }] });
453
520
 
454
521
  class TableDataSource extends DataSource {
@@ -776,6 +843,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
776
843
  class TableViewComponent {
777
844
  apiService = inject(LEApiService);
778
845
  dataService = inject(LEDataService);
846
+ filtersService = inject(LEFiltersService);
779
847
  node = input.required();
780
848
  _columns = signal([]);
781
849
  _data = signal(new TableDataSource());
@@ -809,6 +877,7 @@ class TableViewComponent {
809
877
  hasRowClickAction = computed(() => {
810
878
  return !!this.node()?.actions?.onRowClick?.length;
811
879
  });
880
+ filters = this.filtersService.options;
812
881
  constructor() {
813
882
  this.setEffects();
814
883
  }
@@ -832,6 +901,10 @@ class TableViewComponent {
832
901
  return new Map(sortMap);
833
902
  });
834
903
  }
904
+ onFiltersClick(event) {
905
+ event.stopPropagation();
906
+ this.filtersService.open();
907
+ }
835
908
  onToolbarActionClick({ actions }) {
836
909
  actions.forEach((action) => this.processTableAction(action));
837
910
  }
@@ -887,6 +960,7 @@ class TableViewComponent {
887
960
  this._data.set(new TableDataSource(response.rows));
888
961
  this._total.set(response.total ?? response.rows.length);
889
962
  this._isLoading.set(false);
963
+ this.filtersService.setOptions(this.getFilters(response.columns));
890
964
  }
891
965
  handleTableDataErrorResponse(error) {
892
966
  console.error(error);
@@ -894,6 +968,15 @@ class TableViewComponent {
894
968
  this._data.set(new TableDataSource());
895
969
  this._total.set(0);
896
970
  this._isLoading.set(false);
971
+ // this.filtersService.setOptions(this.getFilters([]));
972
+ }
973
+ getFilters(columns) {
974
+ return columns.reduce((acc, column) => {
975
+ if (column.filters) {
976
+ acc.push(column.filters);
977
+ }
978
+ return acc;
979
+ }, []);
897
980
  }
898
981
  interpolateRowValues(body, row = {}) {
899
982
  const result = {};
@@ -913,22 +996,27 @@ class TableViewComponent {
913
996
  setEffects() {
914
997
  effect(() => {
915
998
  const node = this.node();
916
- this.setPagination(node.ui?.pagination);
917
- this._sortConfig.set(node?.ui?.sort ?? null);
918
- this._sortMap.set(mapSortStringListToSortMap(node?.ui?.sort?.default ?? []));
999
+ untracked(() => {
1000
+ this.filtersService.updateSelection({});
1001
+ this.filtersService.setOptions([]);
1002
+ this.setPagination(node.ui?.pagination);
1003
+ this._sortConfig.set(node?.ui?.sort ?? null);
1004
+ this._sortMap.set(mapSortStringListToSortMap(node?.ui?.sort?.default ?? []));
1005
+ });
919
1006
  });
920
1007
  effect(() => {
921
1008
  const node = this.node();
922
1009
  const pageSize = this.pageSize();
923
1010
  const pageIndex = this.pageIndex();
924
1011
  const sort = this._sortMap();
1012
+ const filters = this.filtersService.selection();
925
1013
  untracked(() => {
926
1014
  if (node?.dataSource) {
927
1015
  const ctx = buildRequestContext({
928
1016
  pageSize,
929
1017
  pageIndex,
930
1018
  sort: mapSortMapToSortStringList(sort),
931
- // filters,
1019
+ filters,
932
1020
  }, {
933
1021
  isSortable: this.isSortingEnabled(),
934
1022
  hasPagination: !!this.pageSize(),
@@ -949,7 +1037,7 @@ class TableViewComponent {
949
1037
  });
950
1038
  }
951
1039
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
952
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: TableViewComponent, isStandalone: true, selector: "table-view", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"le-toolbar\">\n @if (node(); as node) {\n <h2>{{ node?.title }}</h2>\n\n @if (node.actions?.tableActions) {\n <table-view-actions\n [actions]=\"node.actions!.tableActions\"\n (actionClicked)=\"onToolbarActionClick($event)\"\n ></table-view-actions>\n }\n }\n</div>\n\n@if (pageSize()) {\n <table-view-pagination\n [pageSize]=\"pageSize()\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n [entriesCount]=\"entriesCount()\"\n (pageChange)=\"onPageChange($event)\"\n ></table-view-pagination>\n}\n\n<div class=\"le-table-container\">\n @if (displayedColumns().length) {\n <table cdk-table [dataSource]=\"data()\" class=\"le-table\" [class.le-table--loading]=\"isLoading()\">\n @for (column of columns(); track column) {\n <ng-container [cdkColumnDef]=\"column.key\">\n <th\n class=\"le-table-header-cell\"\n cdk-header-cell\n *cdkHeaderCellDef\n [tabindex]=\"sortColumnKeys().has(column.key) ? 0 : -1\"\n [class.le-table-header-cell--sortable]=\"sortColumnKeys().has(column.key)\"\n (click)=\"sortColumnKeys().has(column.key) && onSortClick($event, column)\"\n >\n <div class=\"le-cell-content\">\n <ng-template\n tableViewCell\n [data]=\"column.label\"\n [type]=\"column.column_format?.headerTemplate\"\n ></ng-template>\n\n @if (sortColumnKeys().has(column.key)) {\n <div class=\"le-sort-container\">\n @if (sortMap().has(column.key)) {\n <div class=\"le-sort-icon\">\n <i\n class=\"le-sort-arrow\"\n [class.le-sort-arrow--asc]=\"sortMap().get(column.key) === 'asc'\"\n [class.le-sort-arrow--desc]=\"sortMap().get(column.key) === 'desc'\"\n ></i>\n </div>\n\n <div class=\"le-sort-order\">\n @if (sortOrder().has(column.key)) {\n <span>\n {{ sortOrder().get(column.key) }}\n </span>\n }\n </div>\n } @else {\n<!-- <div class=\"le-sort-icon le-sort-icon&#45;&#45;unfold\">-->\n<!-- <span>&#8645;</span>-->\n<!-- </div>-->\n\n <le-icon name=\"sort\" class=\"le-sort-icon le-sort-icon--unfold\"></le-icon>\n }\n </div>\n }\n </div>\n </th>\n\n <td class=\"le-table-cell\" cdk-cell *cdkCellDef=\"let row\">\n <ng-template\n tableViewCell\n [data]=\"row[column.key]\"\n [type]=\"column.column_format?.cellTemplate\"\n ></ng-template>\n </td>\n </ng-container>\n }\n\n <tr cdk-header-row class=\"le-header-row\" *cdkHeaderRowDef=\"displayedColumns()\"></tr>\n <tr\n cdk-row\n class=\"le-table-row\"\n [tabindex]=\"0\"\n [class.le-table-row--clickable]=\"hasRowClickAction()\"\n *cdkRowDef=\"let row; columns: displayedColumns()\"\n (click)=\"onRowClick(row)\"\n ></tr>\n </table>\n }\n</div>\n\n@if (data().count === 0) {\n @if (isLoading()) {\n <app-loading-view [headerHeight]=\"65\" [rowCount]=\"pageSize() || 10\"></app-loading-view>\n } @else {\n <div class=\"no-entities\">\n <span>No Entities</span>\n </div>\n }\n}\n", dependencies: [{ kind: "component", type: CdkTable, selector: "cdk-table, table[cdk-table]", inputs: ["trackBy", "dataSource", "multiTemplateDataRows", "fixedLayout"], outputs: ["contentChanged"], exportAs: ["cdkTable"] }, { kind: "directive", type: CdkColumnDef, selector: "[cdkColumnDef]", inputs: ["cdkColumnDef", "sticky", "stickyEnd"] }, { kind: "directive", type: CdkHeaderCell, selector: "cdk-header-cell, th[cdk-header-cell]" }, { kind: "directive", type: CdkHeaderCellDef, selector: "[cdkHeaderCellDef]" }, { kind: "directive", type: CdkCell, selector: "cdk-cell, td[cdk-cell]" }, { kind: "directive", type: CdkCellDef, selector: "[cdkCellDef]" }, { kind: "directive", type: CdkHeaderRowDef, selector: "[cdkHeaderRowDef]", inputs: ["cdkHeaderRowDef", "cdkHeaderRowDefSticky"] }, { kind: "component", type: CdkHeaderRow, selector: "cdk-header-row, tr[cdk-header-row]" }, { kind: "component", type: CdkRow, selector: "cdk-row, tr[cdk-row]" }, { kind: "directive", type: CdkRowDef, selector: "[cdkRowDef]", inputs: ["cdkRowDefColumns", "cdkRowDefWhen"] }, { kind: "component", type: TableViewPaginationComponent, selector: "table-view-pagination", inputs: ["pageSize", "pageSizeOptions", "entriesCount"], outputs: ["pageChange"] }, { kind: "component", type: LoadingViewComponent, selector: "app-loading-view", inputs: ["headerHeight", "rowHeight", "rowCount"] }, { kind: "component", type: TableViewActions, selector: "table-view-actions", inputs: ["actions"], outputs: ["actionClicked"] }, { kind: "directive", type: TableViewCellDirective, selector: "[tableViewCell]", inputs: ["type", "data"] }, { kind: "component", type: LeIconComponent, selector: "le-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1040
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: TableViewComponent, isStandalone: true, selector: "table-view", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"le-toolbar\">\n @if (node(); as node) {\n <h2>{{ node?.title }}</h2>\n\n\n <span class=\"spacer\"></span>\n\n @if (filters().length) {\n <button class=\"le-button\" (click)=\"onFiltersClick($event)\">Filters</button>\n }\n\n @if (node.actions?.tableActions) {\n <table-view-actions\n [actions]=\"node.actions!.tableActions\"\n (actionClicked)=\"onToolbarActionClick($event)\"\n ></table-view-actions>\n }\n }\n</div>\n\n@if (pageSize()) {\n <table-view-pagination\n [pageSize]=\"pageSize()\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n [entriesCount]=\"entriesCount()\"\n (pageChange)=\"onPageChange($event)\"\n ></table-view-pagination>\n}\n\n<div class=\"le-table-container\">\n @if (displayedColumns().length) {\n <table cdk-table [dataSource]=\"data()\" class=\"le-table\" [class.le-table--loading]=\"isLoading()\">\n @for (column of columns(); track column) {\n <ng-container [cdkColumnDef]=\"column.key\">\n <th\n class=\"le-table-header-cell\"\n cdk-header-cell\n *cdkHeaderCellDef\n [tabindex]=\"sortColumnKeys().has(column.key) ? 0 : -1\"\n [class.le-table-header-cell--sortable]=\"sortColumnKeys().has(column.key)\"\n (click)=\"sortColumnKeys().has(column.key) && onSortClick($event, column)\"\n >\n <div class=\"le-cell-content\">\n <ng-template\n tableViewCell\n [data]=\"column.label\"\n [type]=\"column.column_format?.headerTemplate\"\n ></ng-template>\n\n @if (sortColumnKeys().has(column.key)) {\n <div class=\"le-sort-container\">\n @if (sortMap().has(column.key)) {\n <div class=\"le-sort-icon\">\n <i\n class=\"le-sort-arrow\"\n [class.le-sort-arrow--asc]=\"sortMap().get(column.key) === 'asc'\"\n [class.le-sort-arrow--desc]=\"sortMap().get(column.key) === 'desc'\"\n ></i>\n </div>\n\n <div class=\"le-sort-order\">\n @if (sortOrder().has(column.key)) {\n <span>\n {{ sortOrder().get(column.key) }}\n </span>\n }\n </div>\n } @else {\n<!-- <div class=\"le-sort-icon le-sort-icon&#45;&#45;unfold\">-->\n<!-- <span>&#8645;</span>-->\n<!-- </div>-->\n\n <le-icon name=\"sort\" class=\"le-sort-icon le-sort-icon--unfold\"></le-icon>\n }\n </div>\n }\n </div>\n </th>\n\n <td class=\"le-table-cell\" cdk-cell *cdkCellDef=\"let row\">\n <ng-template\n tableViewCell\n [data]=\"row[column.key]\"\n [type]=\"column.column_format?.cellTemplate\"\n ></ng-template>\n </td>\n </ng-container>\n }\n\n <tr cdk-header-row class=\"le-header-row\" *cdkHeaderRowDef=\"displayedColumns()\"></tr>\n <tr\n cdk-row\n class=\"le-table-row\"\n [tabindex]=\"0\"\n [class.le-table-row--clickable]=\"hasRowClickAction()\"\n *cdkRowDef=\"let row; columns: displayedColumns()\"\n (click)=\"onRowClick(row)\"\n ></tr>\n </table>\n }\n</div>\n\n@if (data().count === 0) {\n @if (isLoading()) {\n <app-loading-view [headerHeight]=\"65\" [rowCount]=\"pageSize() || 10\"></app-loading-view>\n } @else {\n <div class=\"no-entities\">\n <span>No Entities</span>\n </div>\n }\n}\n", dependencies: [{ kind: "component", type: CdkTable, selector: "cdk-table, table[cdk-table]", inputs: ["trackBy", "dataSource", "multiTemplateDataRows", "fixedLayout"], outputs: ["contentChanged"], exportAs: ["cdkTable"] }, { kind: "directive", type: CdkColumnDef, selector: "[cdkColumnDef]", inputs: ["cdkColumnDef", "sticky", "stickyEnd"] }, { kind: "directive", type: CdkHeaderCell, selector: "cdk-header-cell, th[cdk-header-cell]" }, { kind: "directive", type: CdkHeaderCellDef, selector: "[cdkHeaderCellDef]" }, { kind: "directive", type: CdkCell, selector: "cdk-cell, td[cdk-cell]" }, { kind: "directive", type: CdkCellDef, selector: "[cdkCellDef]" }, { kind: "directive", type: CdkHeaderRowDef, selector: "[cdkHeaderRowDef]", inputs: ["cdkHeaderRowDef", "cdkHeaderRowDefSticky"] }, { kind: "component", type: CdkHeaderRow, selector: "cdk-header-row, tr[cdk-header-row]" }, { kind: "component", type: CdkRow, selector: "cdk-row, tr[cdk-row]" }, { kind: "directive", type: CdkRowDef, selector: "[cdkRowDef]", inputs: ["cdkRowDefColumns", "cdkRowDefWhen"] }, { kind: "component", type: TableViewPaginationComponent, selector: "table-view-pagination", inputs: ["pageSize", "pageSizeOptions", "entriesCount"], outputs: ["pageChange"] }, { kind: "component", type: LoadingViewComponent, selector: "app-loading-view", inputs: ["headerHeight", "rowHeight", "rowCount"] }, { kind: "component", type: TableViewActions, selector: "table-view-actions", inputs: ["actions"], outputs: ["actionClicked"] }, { kind: "directive", type: TableViewCellDirective, selector: "[tableViewCell]", inputs: ["type", "data"] }, { kind: "component", type: LeIconComponent, selector: "le-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
953
1041
  }
954
1042
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TableViewComponent, decorators: [{
955
1043
  type: Component,
@@ -969,7 +1057,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
969
1057
  TableViewActions,
970
1058
  TableViewCellDirective,
971
1059
  LeIconComponent,
972
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"le-toolbar\">\n @if (node(); as node) {\n <h2>{{ node?.title }}</h2>\n\n @if (node.actions?.tableActions) {\n <table-view-actions\n [actions]=\"node.actions!.tableActions\"\n (actionClicked)=\"onToolbarActionClick($event)\"\n ></table-view-actions>\n }\n }\n</div>\n\n@if (pageSize()) {\n <table-view-pagination\n [pageSize]=\"pageSize()\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n [entriesCount]=\"entriesCount()\"\n (pageChange)=\"onPageChange($event)\"\n ></table-view-pagination>\n}\n\n<div class=\"le-table-container\">\n @if (displayedColumns().length) {\n <table cdk-table [dataSource]=\"data()\" class=\"le-table\" [class.le-table--loading]=\"isLoading()\">\n @for (column of columns(); track column) {\n <ng-container [cdkColumnDef]=\"column.key\">\n <th\n class=\"le-table-header-cell\"\n cdk-header-cell\n *cdkHeaderCellDef\n [tabindex]=\"sortColumnKeys().has(column.key) ? 0 : -1\"\n [class.le-table-header-cell--sortable]=\"sortColumnKeys().has(column.key)\"\n (click)=\"sortColumnKeys().has(column.key) && onSortClick($event, column)\"\n >\n <div class=\"le-cell-content\">\n <ng-template\n tableViewCell\n [data]=\"column.label\"\n [type]=\"column.column_format?.headerTemplate\"\n ></ng-template>\n\n @if (sortColumnKeys().has(column.key)) {\n <div class=\"le-sort-container\">\n @if (sortMap().has(column.key)) {\n <div class=\"le-sort-icon\">\n <i\n class=\"le-sort-arrow\"\n [class.le-sort-arrow--asc]=\"sortMap().get(column.key) === 'asc'\"\n [class.le-sort-arrow--desc]=\"sortMap().get(column.key) === 'desc'\"\n ></i>\n </div>\n\n <div class=\"le-sort-order\">\n @if (sortOrder().has(column.key)) {\n <span>\n {{ sortOrder().get(column.key) }}\n </span>\n }\n </div>\n } @else {\n<!-- <div class=\"le-sort-icon le-sort-icon&#45;&#45;unfold\">-->\n<!-- <span>&#8645;</span>-->\n<!-- </div>-->\n\n <le-icon name=\"sort\" class=\"le-sort-icon le-sort-icon--unfold\"></le-icon>\n }\n </div>\n }\n </div>\n </th>\n\n <td class=\"le-table-cell\" cdk-cell *cdkCellDef=\"let row\">\n <ng-template\n tableViewCell\n [data]=\"row[column.key]\"\n [type]=\"column.column_format?.cellTemplate\"\n ></ng-template>\n </td>\n </ng-container>\n }\n\n <tr cdk-header-row class=\"le-header-row\" *cdkHeaderRowDef=\"displayedColumns()\"></tr>\n <tr\n cdk-row\n class=\"le-table-row\"\n [tabindex]=\"0\"\n [class.le-table-row--clickable]=\"hasRowClickAction()\"\n *cdkRowDef=\"let row; columns: displayedColumns()\"\n (click)=\"onRowClick(row)\"\n ></tr>\n </table>\n }\n</div>\n\n@if (data().count === 0) {\n @if (isLoading()) {\n <app-loading-view [headerHeight]=\"65\" [rowCount]=\"pageSize() || 10\"></app-loading-view>\n } @else {\n <div class=\"no-entities\">\n <span>No Entities</span>\n </div>\n }\n}\n" }]
1060
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"le-toolbar\">\n @if (node(); as node) {\n <h2>{{ node?.title }}</h2>\n\n\n <span class=\"spacer\"></span>\n\n @if (filters().length) {\n <button class=\"le-button\" (click)=\"onFiltersClick($event)\">Filters</button>\n }\n\n @if (node.actions?.tableActions) {\n <table-view-actions\n [actions]=\"node.actions!.tableActions\"\n (actionClicked)=\"onToolbarActionClick($event)\"\n ></table-view-actions>\n }\n }\n</div>\n\n@if (pageSize()) {\n <table-view-pagination\n [pageSize]=\"pageSize()\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n [entriesCount]=\"entriesCount()\"\n (pageChange)=\"onPageChange($event)\"\n ></table-view-pagination>\n}\n\n<div class=\"le-table-container\">\n @if (displayedColumns().length) {\n <table cdk-table [dataSource]=\"data()\" class=\"le-table\" [class.le-table--loading]=\"isLoading()\">\n @for (column of columns(); track column) {\n <ng-container [cdkColumnDef]=\"column.key\">\n <th\n class=\"le-table-header-cell\"\n cdk-header-cell\n *cdkHeaderCellDef\n [tabindex]=\"sortColumnKeys().has(column.key) ? 0 : -1\"\n [class.le-table-header-cell--sortable]=\"sortColumnKeys().has(column.key)\"\n (click)=\"sortColumnKeys().has(column.key) && onSortClick($event, column)\"\n >\n <div class=\"le-cell-content\">\n <ng-template\n tableViewCell\n [data]=\"column.label\"\n [type]=\"column.column_format?.headerTemplate\"\n ></ng-template>\n\n @if (sortColumnKeys().has(column.key)) {\n <div class=\"le-sort-container\">\n @if (sortMap().has(column.key)) {\n <div class=\"le-sort-icon\">\n <i\n class=\"le-sort-arrow\"\n [class.le-sort-arrow--asc]=\"sortMap().get(column.key) === 'asc'\"\n [class.le-sort-arrow--desc]=\"sortMap().get(column.key) === 'desc'\"\n ></i>\n </div>\n\n <div class=\"le-sort-order\">\n @if (sortOrder().has(column.key)) {\n <span>\n {{ sortOrder().get(column.key) }}\n </span>\n }\n </div>\n } @else {\n<!-- <div class=\"le-sort-icon le-sort-icon&#45;&#45;unfold\">-->\n<!-- <span>&#8645;</span>-->\n<!-- </div>-->\n\n <le-icon name=\"sort\" class=\"le-sort-icon le-sort-icon--unfold\"></le-icon>\n }\n </div>\n }\n </div>\n </th>\n\n <td class=\"le-table-cell\" cdk-cell *cdkCellDef=\"let row\">\n <ng-template\n tableViewCell\n [data]=\"row[column.key]\"\n [type]=\"column.column_format?.cellTemplate\"\n ></ng-template>\n </td>\n </ng-container>\n }\n\n <tr cdk-header-row class=\"le-header-row\" *cdkHeaderRowDef=\"displayedColumns()\"></tr>\n <tr\n cdk-row\n class=\"le-table-row\"\n [tabindex]=\"0\"\n [class.le-table-row--clickable]=\"hasRowClickAction()\"\n *cdkRowDef=\"let row; columns: displayedColumns()\"\n (click)=\"onRowClick(row)\"\n ></tr>\n </table>\n }\n</div>\n\n@if (data().count === 0) {\n @if (isLoading()) {\n <app-loading-view [headerHeight]=\"65\" [rowCount]=\"pageSize() || 10\"></app-loading-view>\n } @else {\n <div class=\"no-entities\">\n <span>No Entities</span>\n </div>\n }\n}\n" }]
973
1061
  }], ctorParameters: () => [] });
974
1062
 
975
1063
  const isSectionsSchema = (raw) => {
@@ -1064,6 +1152,9 @@ const mapResponseToRequestBody = (bodyModel = {}, values = {}) => {
1064
1152
  if (value !== null && value !== undefined && value !== '') {
1065
1153
  result[key] = value;
1066
1154
  }
1155
+ else {
1156
+ result[key] = null;
1157
+ }
1067
1158
  }
1068
1159
  else {
1069
1160
  result[key] = placeholder;
@@ -1556,6 +1647,192 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
1556
1647
  ], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (node(); as node) {\n @switch (node.type) {\n @case ('section') {\n <section-view [node]=\"node\"></section-view>\n }\n @case ('grid') {\n <grid-view [node]=\"node\"></grid-view>\n }\n @case ('grid_col') {\n <grid-col-view [node]=\"node\"></grid-col-view>\n }\n @case ('table') {\n <table-view [node]=\"node\"></table-view>\n }\n @case ('chart') {\n <chart-view [node]=\"node\"></chart-view>\n }\n @case ('form') {\n <form-view [node]=\"node\"></form-view>\n }\n }\n}\n" }]
1557
1648
  }] });
1558
1649
 
1650
+ class FiltersComponent {
1651
+ filtersService = inject(LEFiltersService);
1652
+ overlay = inject(Overlay);
1653
+ viewContainerRef = inject(ViewContainerRef);
1654
+ _filteredOptions = signal([]);
1655
+ _isDropdownOpened = signal(false);
1656
+ overlayRef = null;
1657
+ destroy$ = new Subject();
1658
+ isOpened = this.filtersService.shown;
1659
+ options = this.filtersService.options;
1660
+ filteredOptions = this._filteredOptions.asReadonly();
1661
+ isDropdownOpened = this._isDropdownOpened.asReadonly();
1662
+ inputEl = viewChild('inputEl');
1663
+ inputContainerEl = viewChild('inputContainerEl');
1664
+ dropdownTpl = viewChild('autocompleteDropdownTpl');
1665
+ contentTpl = viewChild('contentEl');
1666
+ search = new FormControl();
1667
+ selectedFilters = new SelectionModel(true);
1668
+ filtersForm = new FormGroup({});
1669
+ constructor() {
1670
+ this.initFilters();
1671
+ this.listenSearchChanges();
1672
+ this.listenSelectionChanges();
1673
+ this.listenDropdownState();
1674
+ }
1675
+ ngAfterViewInit() {
1676
+ fromEvent(this.contentTpl().nativeElement, 'click')
1677
+ .pipe(takeUntil(this.destroy$))
1678
+ .subscribe({
1679
+ next: () => this.filtersService.close()
1680
+ });
1681
+ }
1682
+ ngOnDestroy() {
1683
+ this.destroy$.next();
1684
+ this.destroy$.complete();
1685
+ }
1686
+ onApplyClick(event) {
1687
+ event.stopPropagation();
1688
+ this.filtersService.updateSelection(this.filtersForm.getRawValue());
1689
+ }
1690
+ onResetClick(event) {
1691
+ event.stopPropagation();
1692
+ this.clearSelection();
1693
+ }
1694
+ onCloseClick(event) {
1695
+ event.stopPropagation();
1696
+ this.closeDropdown();
1697
+ this.filtersService.close();
1698
+ }
1699
+ onInput(event) {
1700
+ event.stopPropagation();
1701
+ this.search.setValue(event.target.value);
1702
+ }
1703
+ onInputClearClick(event) {
1704
+ event.stopPropagation();
1705
+ this.search.setValue('');
1706
+ }
1707
+ onFocus(event) {
1708
+ event.stopPropagation();
1709
+ this.showDropdown();
1710
+ }
1711
+ onBlur(event) {
1712
+ event.stopPropagation();
1713
+ }
1714
+ onOptionClick(control) {
1715
+ this.selectedFilters.toggle(control);
1716
+ this.closeDropdown();
1717
+ this.search.setValue('');
1718
+ }
1719
+ onFilterRemoveClick(control) {
1720
+ this.selectedFilters.toggle(control);
1721
+ }
1722
+ closePanel() {
1723
+ this.overlayRef?.detach();
1724
+ this.overlayRef?.dispose();
1725
+ this.overlayRef = null;
1726
+ }
1727
+ openPanel() {
1728
+ if (this.overlayRef !== null)
1729
+ return;
1730
+ const positionStrategy = this.overlay
1731
+ .position()
1732
+ .flexibleConnectedTo(this.inputContainerEl())
1733
+ .withPositions([
1734
+ { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
1735
+ { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
1736
+ ])
1737
+ .withPush(false);
1738
+ this.overlayRef = this.overlay.create({
1739
+ positionStrategy,
1740
+ scrollStrategy: this.overlay.scrollStrategies.reposition(),
1741
+ width: this.inputContainerEl().nativeElement.offsetWidth,
1742
+ hasBackdrop: false,
1743
+ });
1744
+ this.overlayRef.attach(new TemplatePortal(this.dropdownTpl(), this.viewContainerRef));
1745
+ this.overlayRef
1746
+ .outsidePointerEvents()
1747
+ .pipe(takeUntil(this.destroy$))
1748
+ .subscribe((event) => {
1749
+ if (!this.inputContainerEl().nativeElement.contains(event.target)) {
1750
+ this.closeDropdown();
1751
+ }
1752
+ });
1753
+ }
1754
+ showDropdown() {
1755
+ this._isDropdownOpened.set(true);
1756
+ }
1757
+ closeDropdown() {
1758
+ this._isDropdownOpened.set(false);
1759
+ }
1760
+ clearSelection() {
1761
+ this.selectedFilters.clear();
1762
+ this.filtersService.updateSelection({});
1763
+ }
1764
+ initFilters() {
1765
+ effect(() => {
1766
+ const options = this.options();
1767
+ untracked(() => {
1768
+ this._filteredOptions.set(options);
1769
+ this.selectedFilters.clear();
1770
+ });
1771
+ });
1772
+ }
1773
+ listenSearchChanges() {
1774
+ this.search.valueChanges
1775
+ .pipe(startWith(''), map((value) => this.filter(value)), takeUntilDestroyed())
1776
+ .subscribe((filters) => {
1777
+ this._filteredOptions.set(filters);
1778
+ console.log(filters);
1779
+ });
1780
+ }
1781
+ listenSelectionChanges() {
1782
+ this.selectedFilters.changed.pipe(takeUntilDestroyed()).subscribe(({ added, removed }) => {
1783
+ added.forEach((option) => {
1784
+ this.filtersForm.addControl(option.key, new FormControl(''));
1785
+ });
1786
+ removed.forEach((option) => {
1787
+ this.filtersForm.removeControl(option.key);
1788
+ });
1789
+ });
1790
+ }
1791
+ listenDropdownState() {
1792
+ effect(() => {
1793
+ const isDropdownOpened = this.isDropdownOpened();
1794
+ untracked(() => {
1795
+ if (isDropdownOpened) {
1796
+ this.openPanel();
1797
+ }
1798
+ else {
1799
+ this.closePanel();
1800
+ }
1801
+ });
1802
+ });
1803
+ }
1804
+ filter(value) {
1805
+ const options = this.options();
1806
+ try {
1807
+ const filterValue = value.toLowerCase();
1808
+ return options.reduce((acc, option) => {
1809
+ const filters = option.filters.filter((filter) => {
1810
+ return filter.control.label.toLowerCase().includes(filterValue.toLowerCase());
1811
+ });
1812
+ if (filters.length) {
1813
+ acc.push({ ...option, filters });
1814
+ }
1815
+ return acc;
1816
+ }, []);
1817
+ }
1818
+ catch {
1819
+ return options;
1820
+ }
1821
+ }
1822
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FiltersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1823
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: FiltersComponent, isStandalone: true, selector: "le-filters", viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["inputEl"], descendants: true, isSignal: true }, { propertyName: "inputContainerEl", first: true, predicate: ["inputContainerEl"], descendants: true, isSignal: true }, { propertyName: "dropdownTpl", first: true, predicate: ["autocompleteDropdownTpl"], descendants: true, isSignal: true }, { propertyName: "contentTpl", first: true, predicate: ["contentEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div leDrawerContainer>\n <div leDrawer type=\"over\" [opened]=\"isOpened()\" [width]=\"320\" [hideOnClose]=\"true\" [style.z-index]=\"100\">\n <div class=\"le-filters-container\">\n <div class=\"le-filters-title\">Filters</div>\n\n <div class=\"le-divider le-divider-horizontal\"></div>\n\n <div class=\"le-filters-actions\">\n <button class=\"le-button le-button-flat le-button--success\" (click)=\"onApplyClick($event)\">Apply</button>\n\n <button class=\"le-button le-button-basic\" (click)=\"onResetClick($event)\">Reset</button>\n\n <button class=\"le-button le-button-basic\" (click)=\"onCloseClick($event)\">Close</button>\n </div>\n\n <div #inputContainerEl class=\"le-autocomplete-container\">\n <input\n #inputEl\n class=\"le-autocomplete-input\"\n type=\"text\"\n placeholder=\"Select filters\"\n [value]=\"search.value\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus($event)\"\n (blur)=\"onBlur($event)\"\n autocomplete=\"off\"\n role=\"combobox\"\n [attr.aria-expanded]=\"isDropdownOpened()\"\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n >\n\n <button type=\"button\" class=\"le-button-icon\" (click)=\"onInputClearClick($event)\">\n <le-icon size=\"16\" class=\"le-icon-clear\" name=\"close\"></le-icon>\n </button>\n </div>\n\n <div>\n <form [formGroup]=\"filtersForm\" class=\"le-filters-list\">\n @for (control of selectedFilters.selected; track control.key) {\n <div class=\"le-filters-list-item\">\n <label class=\"le-filters-list-label\" [for]=\"control.key\">{{control.label}}</label>\n\n <div class=\"le-filters-list-input\">\n @switch (control.type) {\n @case ('single_select') {\n <select [id]=\"control.key\" [formControlName]=\"control.key\">\n @for (option of control.options; track option) {\n <option [value]=\"option\">{{option}}</option>\n }\n </select>\n }\n @case ('multi_select') {\n <select [id]=\"control.key\" [formControlName]=\"control.key\" multiple>\n @for (option of control.options; track option) {\n <option [value]=\"option\">{{option}}</option>\n }\n </select>\n }\n @case ('dateTime') {\n <input type=\"datetime-local\" [id]=\"control.key\" [formControlName]=\"control.key\">\n }\n @case ('date') {\n <input type=\"date\" [id]=\"control.key\" [formControlName]=\"control.key\">\n }\n @default {\n <input\n type=\"text\"\n [id]=\"control.key\"\n [formControlName]=\"control.key\"\n (keydown.enter)=\"onApplyClick($event)\"\n >\n }\n }\n\n <button type=\"button\" class=\"le-button-icon\" (click)=\"onFilterRemoveClick(control)\">\n <le-icon size=\"16\" class=\"le-icon-clear\" name=\"close\"></le-icon>\n </button>\n </div>\n </div>\n }\n </form>\n </div>\n </div>\n </div>\n\n <div #contentEl leDrawerContent>\n <ng-content></ng-content>\n </div>\n</div>\n\n\n<ng-template #autocompleteDropdownTpl>\n <div class=\"le-autocomplete-panel\" role=\"listbox\">\n @for (option of filteredOptions(); track option) {\n <div class=\"le-autocomplete-label\">{{option.label}}</div>\n\n <div>\n @for (item of option.filters; track item) {\n <div\n role=\"option\"\n class=\"le-autocomplete-option\"\n [class.le-autocomplete-option--selected]=\"selectedFilters.isSelected(item.control)\"\n [attr.aria-selected]=\"selectedFilters.isSelected(item.control)\"\n (click)=\"onOptionClick(item.control)\"\n >{{item.control.label}}</div>\n }\n </div>\n }\n </div>\n</ng-template>\n", dependencies: [{ kind: "directive", type: DrawerContentDirective, selector: "[leDrawerContent]" }, { kind: "directive", type: DrawerContainerDirective, selector: "[leDrawerContainer]" }, { kind: "directive", type: LeDrawerDirective, selector: "[leDrawer]", inputs: ["opened", "width", "hideOnClose", "type"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.SelectMultipleControlValueAccessor, selector: "select[multiple][formControlName],select[multiple][formControl],select[multiple][ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: LeIconComponent, selector: "le-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1824
+ }
1825
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FiltersComponent, decorators: [{
1826
+ type: Component,
1827
+ args: [{ selector: 'le-filters', imports: [
1828
+ DrawerContentDirective,
1829
+ DrawerContainerDirective,
1830
+ LeDrawerDirective,
1831
+ ReactiveFormsModule,
1832
+ LeIconComponent,
1833
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div leDrawerContainer>\n <div leDrawer type=\"over\" [opened]=\"isOpened()\" [width]=\"320\" [hideOnClose]=\"true\" [style.z-index]=\"100\">\n <div class=\"le-filters-container\">\n <div class=\"le-filters-title\">Filters</div>\n\n <div class=\"le-divider le-divider-horizontal\"></div>\n\n <div class=\"le-filters-actions\">\n <button class=\"le-button le-button-flat le-button--success\" (click)=\"onApplyClick($event)\">Apply</button>\n\n <button class=\"le-button le-button-basic\" (click)=\"onResetClick($event)\">Reset</button>\n\n <button class=\"le-button le-button-basic\" (click)=\"onCloseClick($event)\">Close</button>\n </div>\n\n <div #inputContainerEl class=\"le-autocomplete-container\">\n <input\n #inputEl\n class=\"le-autocomplete-input\"\n type=\"text\"\n placeholder=\"Select filters\"\n [value]=\"search.value\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus($event)\"\n (blur)=\"onBlur($event)\"\n autocomplete=\"off\"\n role=\"combobox\"\n [attr.aria-expanded]=\"isDropdownOpened()\"\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n >\n\n <button type=\"button\" class=\"le-button-icon\" (click)=\"onInputClearClick($event)\">\n <le-icon size=\"16\" class=\"le-icon-clear\" name=\"close\"></le-icon>\n </button>\n </div>\n\n <div>\n <form [formGroup]=\"filtersForm\" class=\"le-filters-list\">\n @for (control of selectedFilters.selected; track control.key) {\n <div class=\"le-filters-list-item\">\n <label class=\"le-filters-list-label\" [for]=\"control.key\">{{control.label}}</label>\n\n <div class=\"le-filters-list-input\">\n @switch (control.type) {\n @case ('single_select') {\n <select [id]=\"control.key\" [formControlName]=\"control.key\">\n @for (option of control.options; track option) {\n <option [value]=\"option\">{{option}}</option>\n }\n </select>\n }\n @case ('multi_select') {\n <select [id]=\"control.key\" [formControlName]=\"control.key\" multiple>\n @for (option of control.options; track option) {\n <option [value]=\"option\">{{option}}</option>\n }\n </select>\n }\n @case ('dateTime') {\n <input type=\"datetime-local\" [id]=\"control.key\" [formControlName]=\"control.key\">\n }\n @case ('date') {\n <input type=\"date\" [id]=\"control.key\" [formControlName]=\"control.key\">\n }\n @default {\n <input\n type=\"text\"\n [id]=\"control.key\"\n [formControlName]=\"control.key\"\n (keydown.enter)=\"onApplyClick($event)\"\n >\n }\n }\n\n <button type=\"button\" class=\"le-button-icon\" (click)=\"onFilterRemoveClick(control)\">\n <le-icon size=\"16\" class=\"le-icon-clear\" name=\"close\"></le-icon>\n </button>\n </div>\n </div>\n }\n </form>\n </div>\n </div>\n </div>\n\n <div #contentEl leDrawerContent>\n <ng-content></ng-content>\n </div>\n</div>\n\n\n<ng-template #autocompleteDropdownTpl>\n <div class=\"le-autocomplete-panel\" role=\"listbox\">\n @for (option of filteredOptions(); track option) {\n <div class=\"le-autocomplete-label\">{{option.label}}</div>\n\n <div>\n @for (item of option.filters; track item) {\n <div\n role=\"option\"\n class=\"le-autocomplete-option\"\n [class.le-autocomplete-option--selected]=\"selectedFilters.isSelected(item.control)\"\n [attr.aria-selected]=\"selectedFilters.isSelected(item.control)\"\n (click)=\"onOptionClick(item.control)\"\n >{{item.control.label}}</div>\n }\n </div>\n }\n </div>\n</ng-template>\n" }]
1834
+ }], ctorParameters: () => [] });
1835
+
1559
1836
  class LeContainerComponent {
1560
1837
  auth = inject(LEAuthService);
1561
1838
  dataService = inject(LEDataService);
@@ -1571,12 +1848,13 @@ class LeContainerComponent {
1571
1848
  };
1572
1849
  });
1573
1850
  constructor() {
1574
- this.setEffects();
1851
+ this.listenAuthState();
1852
+ this.listenPageInit();
1575
1853
  }
1576
1854
  onSelectionChange(view) {
1577
1855
  this.dataService.setView(view);
1578
1856
  }
1579
- setEffects() {
1857
+ listenAuthState() {
1580
1858
  effect(() => {
1581
1859
  const token = this.auth.token();
1582
1860
  const isGuest = this.auth.isGuest();
@@ -1586,6 +1864,8 @@ class LeContainerComponent {
1586
1864
  this.dataService.requestConfig();
1587
1865
  });
1588
1866
  });
1867
+ }
1868
+ listenPageInit() {
1589
1869
  effect(() => {
1590
1870
  const parentMenu = this.dataService.parentMenu();
1591
1871
  const sidebar = this.sidebar();
@@ -1597,11 +1877,11 @@ class LeContainerComponent {
1597
1877
  });
1598
1878
  }
1599
1879
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1600
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: LeContainerComponent, isStandalone: true, selector: "le-container", providers: [LEDataService, LEApiService], viewQueries: [{ propertyName: "sidebar", first: true, predicate: SidebarComponent, descendants: true, isSignal: true }], ngImport: i0, template: "@if (data(); as data) {\n <le-sidebar\n [config]=\"data.config\"\n [view]=\"data.view\"\n (selectionChange)=\"onSelectionChange($event)\"\n >\n <le-node [node]=\"data.view\"></le-node>\n </le-sidebar>\n}\n", dependencies: [{ kind: "component", type: SidebarComponent, selector: "le-sidebar", inputs: ["config", "view"], outputs: ["selectionChange"] }, { kind: "component", type: NodeComponent, selector: "le-node", inputs: ["node"] }] });
1880
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: LeContainerComponent, isStandalone: true, selector: "le-container", providers: [LEDataService, LEApiService, LEFiltersService], viewQueries: [{ propertyName: "sidebar", first: true, predicate: SidebarComponent, descendants: true, isSignal: true }], ngImport: i0, template: "@if (data(); as data) {\n <le-sidebar\n [config]=\"data.config\"\n [view]=\"data.view\"\n (selectionChange)=\"onSelectionChange($event)\"\n >\n <le-filters>\n <le-node [node]=\"data.view\"></le-node>\n </le-filters>\n </le-sidebar>\n}\n", dependencies: [{ kind: "component", type: SidebarComponent, selector: "le-sidebar", inputs: ["config", "view"], outputs: ["selectionChange"] }, { kind: "component", type: NodeComponent, selector: "le-node", inputs: ["node"] }, { kind: "component", type: FiltersComponent, selector: "le-filters" }] });
1601
1881
  }
1602
1882
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LeContainerComponent, decorators: [{
1603
1883
  type: Component,
1604
- args: [{ selector: 'le-container', imports: [SidebarComponent, NodeComponent], providers: [LEDataService, LEApiService], template: "@if (data(); as data) {\n <le-sidebar\n [config]=\"data.config\"\n [view]=\"data.view\"\n (selectionChange)=\"onSelectionChange($event)\"\n >\n <le-node [node]=\"data.view\"></le-node>\n </le-sidebar>\n}\n" }]
1884
+ args: [{ selector: 'le-container', imports: [SidebarComponent, NodeComponent, FiltersComponent], providers: [LEDataService, LEApiService, LEFiltersService], template: "@if (data(); as data) {\n <le-sidebar\n [config]=\"data.config\"\n [view]=\"data.view\"\n (selectionChange)=\"onSelectionChange($event)\"\n >\n <le-filters>\n <le-node [node]=\"data.view\"></le-node>\n </le-filters>\n </le-sidebar>\n}\n" }]
1605
1885
  }], ctorParameters: () => [] });
1606
1886
 
1607
1887
  const provideConfig = (config) => {