@zeedhi/teknisa-components-common 3.0.4 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/coverage/clover.xml +2 -2
  2. package/coverage/lcov-report/index.html +1 -1
  3. package/coverage/lcov-report/tests/__helpers__/component-event-helper.ts.html +100 -0
  4. package/coverage/lcov-report/tests/__helpers__/create-component.ts.html +109 -0
  5. package/coverage/lcov-report/tests/__helpers__/find-component.ts.html +139 -0
  6. package/coverage/lcov-report/tests/__helpers__/flush-promises-helper.ts.html +94 -0
  7. package/coverage/lcov-report/tests/__helpers__/get-child-helper.ts.html +166 -0
  8. package/coverage/lcov-report/tests/__helpers__/index.html +221 -0
  9. package/coverage/lcov-report/tests/__helpers__/index.ts.html +106 -0
  10. package/coverage/lcov-report/tests/__helpers__/mock-created-helper.ts.html +121 -0
  11. package/coverage/lcov-report/tests/__helpers__/spy-on-all-methods.ts.html +223 -0
  12. package/dist/teknisa-components-common.js +72 -66
  13. package/dist/teknisa-components-common.min.js +72 -66
  14. package/dist/types/components/index.d.ts +2 -0
  15. package/dist/types/components/tek-datasource/tek-memory-datasource.d.ts +16 -16
  16. package/dist/types/components/tek-datasource/tek-rest-datasource.d.ts +18 -20
  17. package/dist/types/components/tek-grid/grouped-data-navigator.d.ts +12 -0
  18. package/dist/types/components/tek-grid/index.d.ts +1 -1
  19. package/dist/types/components/tek-grid/tek-grid.d.ts +2 -1
  20. package/dist/types/components/tek-loading/interfaces.d.ts +6 -0
  21. package/dist/types/components/tek-loading/loading.d.ts +16 -0
  22. package/environments.json +12 -0
  23. package/jest.config.cjs +23 -0
  24. package/package.json +5 -3
  25. package/src/components/index.ts +2 -2
  26. package/src/components/tek-datasource/tek-memory-datasource.ts +2 -2
  27. package/src/components/tek-datasource/tek-rest-datasource.ts +2 -2
  28. package/src/components/tek-grid/grid-filter-button.ts +5 -3
  29. package/src/components/tek-grid/grouped-data-navigator.ts +66 -0
  30. package/src/components/tek-grid/index.ts +1 -1
  31. package/src/components/tek-grid/tek-grid.ts +19 -15
  32. package/src/components/tek-loading/interfaces.ts +7 -0
  33. package/src/components/tek-loading/loading.ts +27 -0
  34. package/tests/__helpers__/create-component.ts +8 -0
  35. package/tests/__helpers__/find-component.ts +18 -0
  36. package/tests/__helpers__/index.ts +4 -0
  37. package/tests/__helpers__/spy-on-all-methods.ts +46 -0
  38. package/tests/unit/components/tek-breadcrumb-header/tek-breadcrumb-header.spec.ts +2 -1
  39. package/tests/unit/components/tek-datasource/memory-datasource.spec.ts +4 -1
  40. package/tests/unit/components/tek-datasource/rest-datasource.spec.ts +1 -1
  41. package/tests/unit/components/tek-grid/filter-helper.spec.ts +8 -4
  42. package/tests/unit/components/tek-grid/grid-filter-button.spec.ts +1 -1
  43. package/tests/unit/components/tek-grid/grouped-data-manager.spec.ts +1 -1
  44. package/tests/unit/components/tek-grid/grouped-data-navigator.spec.ts +143 -0
  45. package/tests/unit/components/tek-grid/layout-options.spec.ts +1 -1
  46. package/tests/unit/components/tek-grid/tek-grid-column.spec.ts +23 -17
  47. package/tests/unit/components/tek-grid/tek-grid-columns-button.spec.ts +2 -1
  48. package/tests/unit/components/tek-grid/tek-grid.spec.ts +14 -12
  49. package/tests/unit/components/tek-grid/tek-memory-datasource.spec.ts +1 -1
  50. package/tests/unit/components/tek-grid/tek-rest-datasource.spec.ts +1 -1
  51. package/tests/unit/components/tek-loading/loading.spec.ts +29 -0
  52. package/tests/unit/components/tek-user-info/tek-user-info-list.spec.ts +12 -2
  53. package/tests/unit/components/tek-user-info/tek-user-info.spec.ts +18 -6
  54. package/tests/unit/utils/mock-console.ts +18 -0
  55. package/tests/unit/utils/setup.ts +5 -0
  56. package/dist/types/error/delete-rows-error.d.ts +0 -6
  57. package/jest.config.js +0 -1
  58. package/src/components/tek-grid/grouped-view-navigator.ts +0 -84
  59. package/tests/unit/components/crud/crud-add-button.spec.ts +0 -56
  60. package/tests/unit/components/crud/crud-button.spec.ts +0 -94
  61. package/tests/unit/components/crud/crud-cancel-button.spec.ts +0 -91
  62. package/tests/unit/components/crud/crud-delete-button.spec.ts +0 -122
  63. package/tests/unit/components/crud/crud-form.spec.ts +0 -165
  64. package/tests/unit/components/crud/crud-save-button.spec.ts +0 -118
  65. package/tests/unit/components/tek-card-title/CardTitle.spec.ts +0 -34
  66. package/tests/unit/components/tek-drag-grid/tek-drag-grid.spec.ts +0 -112
  67. package/tests/unit/components/tek-grid/grouped-view-navigator.spec.ts +0 -244
  68. package/tests/unit/components/tek-grid/multi-option.spec.ts +0 -139
  69. package/tests/unit/components/tek-image/Image.spec.ts +0 -67
  70. package/tests/unit/components/tek-iterable-carousel/iterable-carousel.spec.ts +0 -37
  71. package/tests/unit/components/tek-iterable-component-render/iterable-component-render.spec.ts +0 -200
  72. package/tests/unit/components/tek-loading/Loading.spec.ts +0 -30
  73. package/tests/unit/components/tek-notifications/notifications.spec.ts +0 -201
  74. package/tests/unit/components/tek-product-card/product-card.spec.ts +0 -61
  75. package/tests/unit/components/tree-grid/tree-grid.spec.ts +0 -776
  76. package/tests/unit/utils/grid-base/export-options/button-option.spec.ts +0 -44
  77. package/tests/unit/utils/grid-base/export-options/multi-option.spec.ts +0 -135
  78. package/tests/unit/utils/grid-base/grid-controller.spec.ts +0 -174
  79. package/tests/unit/utils/report-filter/report-filter.spec.ts +0 -66
@@ -322,8 +322,9 @@ export class TekGridFilterButton extends Button implements ITekGridFilterButton
322
322
  let columnName = item.split(`${this.grid!.name}-filter-AND-CONTAINS-`)[1];
323
323
  columnName = columnName.split('-').slice(0, -1).join('-'); // remove index
324
324
 
325
- if (formValue[item]) {
326
- filter[columnName] = formValue[item];
325
+ const itemValue = formValue[item];
326
+ if (itemValue && !(Array.isArray(itemValue) && !itemValue.length)) {
327
+ filter[columnName] = itemValue;
327
328
  }
328
329
  });
329
330
 
@@ -377,9 +378,10 @@ export class TekGridFilterButton extends Button implements ITekGridFilterButton
377
378
 
378
379
  this.filterFormInputs[column.name].push(columnComponentName);
379
380
 
381
+ const { dataValueOut, ...componentProps } = column.componentProps || {};
380
382
  const newColumnComponent = {
381
383
  label: column.label,
382
- ...column.componentProps,
384
+ ...componentProps,
383
385
  ...filterItem,
384
386
  name: columnComponentName,
385
387
  };
@@ -0,0 +1,66 @@
1
+ import { IDictionary } from '@zeedhi/core';
2
+ import { DataNavigator, IDataNavigator, VerticalDirection } from '@zeedhi/common';
3
+ import { ITekGrid } from './interfaces';
4
+
5
+ export class GroupedDataNavigator implements IDataNavigator {
6
+ private dataNavigator: DataNavigator;
7
+
8
+ protected grid: ITekGrid;
9
+
10
+ constructor(grid: ITekGrid) {
11
+ this.dataNavigator = new DataNavigator(grid);
12
+ this.grid = grid;
13
+ }
14
+
15
+ public navigatePageUp(): void {
16
+ this.dataNavigator.navigatePageUp();
17
+ }
18
+
19
+ public navigatePageDown(): void {
20
+ this.dataNavigator.navigatePageDown();
21
+ }
22
+
23
+ public navigateDatasource(direction: VerticalDirection): void {
24
+ if (!this.grid.isGrouped()) {
25
+ this.dataNavigator.navigateDatasource(direction);
26
+ return;
27
+ }
28
+
29
+ this.navigateGroupedDatasource(direction);
30
+ }
31
+
32
+ private getRowIndex(groupedData: IDictionary[], index?: number) {
33
+ if (index !== undefined) return index;
34
+
35
+ const { currentRow } = this.grid.datasource;
36
+ return groupedData.findIndex((row) => {
37
+ if (currentRow.group) {
38
+ return row.group && row.groupValue === currentRow.groupValue;
39
+ }
40
+ const rowKey = this.grid.getRowKey(row);
41
+ const currentRowKey = this.grid.getRowKey(currentRow);
42
+ return rowKey && rowKey === currentRowKey;
43
+ });
44
+ }
45
+
46
+ private navigateGroupedDatasource(direction: VerticalDirection, index?: number): void {
47
+ const groupedData = this.grid.getGroupedData();
48
+ const up = direction === 'up';
49
+
50
+ if (!groupedData.length || (up && index === -1) || (!up && index === groupedData.length)) return;
51
+
52
+ let rowIndex = this.getRowIndex(groupedData, index);
53
+
54
+ if (up && rowIndex === -1) rowIndex = groupedData.length;
55
+
56
+ const nextIndex = rowIndex + (up ? -1 : 1);
57
+ const newRow = groupedData[nextIndex];
58
+
59
+ if (!newRow || !this.grid.isItemVisible(newRow) || newRow.groupFooter) {
60
+ this.navigateGroupedDatasource(direction, nextIndex);
61
+ return;
62
+ }
63
+
64
+ this.grid.setCurrentRow(newRow);
65
+ }
66
+ }
@@ -5,7 +5,7 @@ export * from './dynamic-filter-datasource-factory';
5
5
  export * from './filter-helper';
6
6
  export * from './grid-filter-button';
7
7
  export * from './grouped-data-manager';
8
- export * from './grouped-view-navigator';
8
+ export * from './grouped-data-navigator';
9
9
  export * from './interfaces';
10
10
  export * from './keymap-grouped';
11
11
  export * from './layout-options';
@@ -11,7 +11,6 @@ import {
11
11
  } from '@zeedhi/core';
12
12
  import clonedeep from 'lodash.clonedeep';
13
13
  import {
14
- DataNavigator,
15
14
  Direction,
16
15
  IDataNavigator,
17
16
  IDataSelector,
@@ -19,13 +18,12 @@ import {
19
18
  IIterableTable,
20
19
  IKeyMapMerger,
21
20
  ITableActionBuilder,
22
- IViewNavigator,
23
21
  IterableTable,
24
22
  KeyMapMerger,
25
23
  KeyMapNavigation,
26
24
  TableActionBuilder,
27
- VerticalDirection, IComponent, IComponentRender, DataEditorWithAdd, IDataEditorWithAdd, IGridColumnEditable, IGridEditable,
28
- KeyMapEditing, Iterable, IIterableProps,
25
+ VerticalDirection, IComponent, IComponentRender, DataEditorWithAdd, IDataEditorWithAdd, IGridColumnEditable, IGridEditable,
26
+ KeyMapEditing, Iterable, IIterableProps, ViewNavigator,
29
27
  } from '@zeedhi/common';
30
28
  import {
31
29
  IColumnsSearcher,
@@ -50,7 +48,7 @@ import { ColumnsSearcher } from './columns-searcher';
50
48
  import { DynamicFilterDatasourceFactory } from './dynamic-filter-datasource-factory';
51
49
  import { GroupedDataManager } from './grouped-data-manager';
52
50
  import { GroupedDataSelector } from './grouped-data-selector';
53
- import { GroupedViewNavigator } from './grouped-view-navigator';
51
+ import { GroupedDataNavigator } from './grouped-data-navigator';
54
52
  import { ITekConfig } from '../../utils';
55
53
  import { TekGridToolbarProvider } from './tek-grid-toolbar-provider/tek-grid-toolbar-provider';
56
54
 
@@ -66,7 +64,7 @@ export class TekGrid extends Iterable<TekGridColumn> implements ITekGrid {
66
64
 
67
65
  private dataNavigator: IDataNavigator;
68
66
 
69
- private groupedViewNavigator: IViewNavigator;
67
+ private viewNavigator: ViewNavigator;
70
68
 
71
69
  private keyMapMerger!: IKeyMapMerger;
72
70
 
@@ -445,8 +443,8 @@ export class TekGrid extends Iterable<TekGridColumn> implements ITekGrid {
445
443
  this.iterableTable = new IterableTable(this);
446
444
  this.dataSelector = new GroupedDataSelector(this);
447
445
  this.tekGridEvents = new TekGridEvents(this);
448
- this.dataNavigator = new DataNavigator(this);
449
- this.groupedViewNavigator = new GroupedViewNavigator(this);
446
+ this.dataNavigator = new GroupedDataNavigator(this);
447
+ this.viewNavigator = new ViewNavigator();
450
448
  this.dataEditor = new DataEditorWithAdd(this);
451
449
  this.columnsSearcher = new ColumnsSearcher();
452
450
  this.groupedDataManager = new GroupedDataManager(this);
@@ -536,12 +534,12 @@ export class TekGrid extends Iterable<TekGridColumn> implements ITekGrid {
536
534
 
537
535
  directionalLeft(param: IEventParam<any>): void {
538
536
  this.groupedDataManager.directionalLeft(param);
539
- this.groupedViewNavigator.navigateLeft(param);
537
+ this.viewNavigator.navigateLeft(param);
540
538
  }
541
539
 
542
540
  directionalRight(param: IEventParam<any>): void {
543
541
  this.groupedDataManager.directionalRight(param);
544
- this.groupedViewNavigator.navigateRight(param);
542
+ this.viewNavigator.navigateRight(param);
545
543
  }
546
544
 
547
545
  getReport(): Promise<Window | null> {
@@ -557,6 +555,8 @@ export class TekGrid extends Iterable<TekGridColumn> implements ITekGrid {
557
555
  }
558
556
 
559
557
  public onCreated(): void {
558
+ this.createGridController();
559
+ this.addCancelColumn();
560
560
  super.onCreated();
561
561
 
562
562
  Loader.addController(`GridController_${this.name}`, TekGridController, [this]);
@@ -650,25 +650,25 @@ export class TekGrid extends Iterable<TekGridColumn> implements ITekGrid {
650
650
  }
651
651
 
652
652
  setViewNavigate(viewNavigate: (direction: Direction, event?: Event) => void): void {
653
- this.groupedViewNavigator.setViewNavigate(viewNavigate);
653
+ this.viewNavigator.setViewNavigate(viewNavigate);
654
654
  }
655
655
 
656
656
  navigateLeft(params: IEventParam<any>): void {
657
657
  if (!this.cellSelection) return;
658
- this.groupedViewNavigator.navigateLeft(params);
658
+ this.viewNavigator.navigateLeft(params);
659
659
  }
660
660
 
661
661
  navigateRight(params: IEventParam<any>): void {
662
662
  if (!this.cellSelection) return;
663
- this.groupedViewNavigator.navigateRight(params);
663
+ this.viewNavigator.navigateRight(params);
664
664
  }
665
665
 
666
666
  navigateUp(): void {
667
- this.groupedViewNavigator.navigateUp();
667
+ this.viewNavigator.navigateUp();
668
668
  }
669
669
 
670
670
  navigateDown(): void {
671
- this.groupedViewNavigator.navigateDown();
671
+ this.viewNavigator.navigateDown();
672
672
  }
673
673
 
674
674
  navigateDatasource(direction: VerticalDirection): void {
@@ -684,6 +684,10 @@ export class TekGrid extends Iterable<TekGridColumn> implements ITekGrid {
684
684
  return this.tableActionBuilder.getActionComponent(actionComponent, column, row, parentPath);
685
685
  }
686
686
 
687
+ createGridController(): void {
688
+ this.dataEditor.createGridController();
689
+ }
690
+
687
691
  addCancelColumn(): void {
688
692
  this.dataEditor.addCancelColumn();
689
693
  }
@@ -0,0 +1,7 @@
1
+ import type { ILoading as IZdLoading } from '@zeedhi/common';
2
+
3
+ export interface ILoading extends IZdLoading {
4
+ text?: string;
5
+ zIndex?: number | string;
6
+ image?: string;
7
+ }
@@ -0,0 +1,27 @@
1
+ import { Loading as ZdLoading } from '@zeedhi/common';
2
+ import type { ILoading } from './interfaces';
3
+
4
+ // biome-ignore format: Preserve the legacy embedded GIF without rewriting a very large literal.
5
+ const loading = 'data:image/gif;base64,R0lGODlhlgCWAPf/AC1oxPa+ADarUdmsFEB/m0yTcjiMhEafWjFova2SNDZotX10VsOfJDlosFZnge25BnJtXTukVWVmaFh1eIuOZ1x0ZEFopHpyWGFpcS5ow+q2CVNnhmVnZvW9AW5qYUyKXUJnofW+AKWNOV9mcS9owZuGQTporlCGXbWXLmNrazxnqeKyDoGDZVFniFZ6ZNSpGJ+IPoR4Ud+wEURnnmtpYklnlll5YbGUMcagIk5njmhnZWpoZGF0aWBmbkdnmbyaKUtnlEaBfWdmZTNou0WUW5WDRFtmeGZmZ82kHqecTXqIdzRouGJmbPC6BIB2VDxnrGNmakyHYPO8AkxnkUh0qmRpZl9wZVxndmRmaVhnffS9AqmPN09ni96vEUmQWzBowC1ow2FtZVR3gl5ndFGCYEVnnF1mdGR9i1dnf7qZK4l7TnRvXOK1FD6eV8ijIG6Cgl58lF1rfEBnpFVsi1pmeo5+Sk56dz9np5OCRjaqUi5pxNarFndwWmNqZm9sYFx7a098itGnG4d6T7ikPKKLO1Rmg+e1Cr2bKVhme0GbVkpmk5mWW5GBSM+nHLiYLPG7BIp8TUKZWUFsqWJnbltmd0hnmNqtFExtm1tsgaiOOIx9TNuuE6CKPWJmbcqjH1OJb8CdJjFovlpwb+u5CzioU1aFbjdos0qYXJOPXWFwczepUnBsX8qrKuW0DD5nqdmsFUl+kTtnrDdntNKuI+OzDVRnhYuEV52HPzNqvjltuVBqkJeERNirFnVvXKSMOjVsvDmLhEJxsTloss+sJTeqUdyzGkaeWreYLmBqdjmMhDyhVvC8B49/STinVVV+YVp/bEuScq6fRj5tr8CnNUV/lUNnoGZnZkCFgTaqUVeCYTuLgz2Ig02RcUySck+QcTxpr5qQUFCPXjZsullviFh4ZNaxH0KAmEGYXFJ4oFCNcEdsoUicWpmFQkRooEFvsHt5YDepUXBvYzyKhESXWkeeWjxutcWlK250bYp+UFCQcGZoaLyeLtitFaGSR0OYV2ZmZiH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDcuMS1jMDAwIDc5LmRhYmFjYmIsIDIwMjEvMDQvMTQtMDA6Mzk6NDQgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCAyMy4wIChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpEMEVGRUY5RjYzRjYxMUVDQkRFNUM0MjQ5M0FFRTY2RSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpEMEVGRUZBMDYzRjYxMUVDQkRFNUM0MjQ5M0FFRTY2RSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkQwRUZFRjlENjNGNjExRUNCREU1QzQyNDkzQUVFNjZFIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkQwRUZFRjlFNjNGNjExRUNCREU1QzQyNDkzQUVFNjZFIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Af/+/fz7+vn49/b19PPy8fDv7u3s6+rp6Ofm5eTj4uHg397d3Nva2djX1tXU09LR0M/OzczLysnIx8bFxMPCwcC/vr28u7q5uLe2tbSzsrGwr66trKuqqainpqWko6KhoJ+enZybmpmYl5aVlJOSkZCPjo2Mi4qJiIeGhYSDgoGAf359fHt6eXh3dnV0c3JxcG9ubWxramloZ2ZlZGNiYWBfXl1cW1pZWFdWVVRTUlFQT05NTEtKSUhHRkVEQ0JBQD8+PTw7Ojk4NzY1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3cr155ExDjZsyDKiK8weU4R9AcAWTCgTLcyulFBrCdu7eAHITSmhEpi8gPeirJEBcGDBJR0UNpwXMUksChgfdhxyg+TJlD/eudw480cmdjnf9fxxDAnRo0l3vII6teqNZhajfs1xBILWemlrlNAAt+6NNXz/zjji9OzhGSu1Rp6RSW/RzDOaicw5esZJrqpbx4iFiynZd0mYgtiuEQuaSndMmJAzhY4E8vDjy59Pv779+/jz69/Pv7///wAGKOCABBZo4IEIJqjgggw26OCDEEYo4YQUVmjhhRhmqOGGHHbo4YcghijiiCSWaOKJKKao4oostujiizDGKOOMNNZo44045qjjjjz26OOPQAYp5JBEFmnkkUgmqSRVAQEAIfkEBQQA/wAsAAAAAJYAlgAACPEA/wkcSLCgwYMIEypcyLChw4cQI0qcSLGixYsYM2rcyLGjx48gQ4ocSbKkyZMoU6pcybKly5cwY8qcSbOmzZs4c+rcybOnz59AgwodSrSo0aNIkypdyrSp06dQo0qdSrWq1atYs2rdyrWr169gw4odS7as2bNo06pdy7at27dw48qdS7eu3bt48+rdy7ev37+AAwseTLiw4cOIEytezLix48eQI0ueTLmy5cuYM2vezLmz58+gQ4seTbq06dOoU6tezbq169ewY8ueTbu27du4c+vezbu379/AgwsfTry48ePIkytfzry58+fQo0ufbjggACH5BAUEAP8ALAAAAAABAAEAAAgEAP8FBAA7';
6
+
7
+ /**
8
+ * Teknisa component
9
+ */
10
+
11
+ export class Loading extends ZdLoading implements ILoading {
12
+ /**
13
+ * Text shown in the loading overlay.
14
+ */
15
+ public text = '';
16
+
17
+ /**
18
+ * Loading image.
19
+ */
20
+ public image = loading;
21
+
22
+ public constructor(props: ILoading) {
23
+ super(props);
24
+ this.text = this.getInitValue('text', props.text, this.text);
25
+ this.image = this.getInitValue('image', props.image, this.image);
26
+ }
27
+ }
@@ -0,0 +1,8 @@
1
+ import { Newable } from '@zeedhi/core';
2
+ import { ComponentRender, IComponentRender } from '@zeedhi/common';
3
+
4
+ export function createComponent<T extends ComponentRender>(componentClass: Newable<T>, props: IComponentRender): T {
5
+ const instance = new componentClass(props);
6
+ instance.onCreated();
7
+ return instance;
8
+ }
@@ -0,0 +1,18 @@
1
+ export function findComponent(name: string, children: any[]) {
2
+ let found: any;
3
+
4
+ children.forEach((child) => {
5
+ if (child.name === name) {
6
+ found = child;
7
+ return;
8
+ }
9
+
10
+ if (child.children && child.children.length > 0) {
11
+ const result = findComponent(name, child.children);
12
+
13
+ if (result) found = result;
14
+ }
15
+ });
16
+
17
+ return found;
18
+ }
@@ -1,3 +1,7 @@
1
1
  export * from './component-event-helper';
2
2
  export * from './get-child-helper';
3
3
  export * from './mock-created-helper';
4
+ export * from './spy-on-all-methods';
5
+ export * from './flush-promises-helper';
6
+ export * from './create-component';
7
+ export * from './find-component';
@@ -0,0 +1,46 @@
1
+ import { IDictionary } from "@zeedhi/core";
2
+
3
+ // add a spy on all methods from a class prototype
4
+ const spyOnAllMethods = (
5
+ prototype: any,
6
+ mockImplementations: IDictionary = {},
7
+ alreadySpiedMethods: Set<string> = new Set(),
8
+ depth: number = 0,
9
+ maxDepth: number = 10 // Safety limit
10
+ ) => {
11
+ // Safety check against infinite recursion
12
+ if (depth > maxDepth || prototype === null || prototype === Object.prototype) {
13
+ return {};
14
+ }
15
+
16
+ const methods = Object.getOwnPropertyNames(prototype).filter(
17
+ (prop) => typeof prototype[prop] === 'function' && prop !== 'constructor'
18
+ );
19
+
20
+ const spyObj: IDictionary<jest.SpyInstance> = {};
21
+
22
+ methods.forEach((method) => {
23
+ if (!alreadySpiedMethods.has(method)) {
24
+ const mockImplementation = mockImplementations[method] || jest.fn();
25
+ spyObj[method] = jest.spyOn(prototype, method).mockImplementation(mockImplementation);
26
+ alreadySpiedMethods.add(method);
27
+ }
28
+ });
29
+
30
+ // Get the parent prototype carefully
31
+ const parentPrototype = Object.getPrototypeOf(prototype);
32
+ if (parentPrototype && parentPrototype !== prototype) { // Additional check to prevent cycles
33
+ const parentSpyObj = spyOnAllMethods(
34
+ parentPrototype,
35
+ mockImplementations,
36
+ alreadySpiedMethods,
37
+ depth + 1,
38
+ maxDepth
39
+ );
40
+ Object.assign(spyObj, parentSpyObj);
41
+ }
42
+
43
+ return spyObj;
44
+ };
45
+
46
+ export { spyOnAllMethods };
@@ -1,4 +1,5 @@
1
- import { BreadcrumbHeader, Image } from '../../../../src';
1
+ import { BreadcrumbHeader } from '../../../../src';
2
+ import { Image } from '@zeedhi/common';
2
3
 
3
4
  describe('BreadcrumbHeader', () => {
4
5
  describe('constructor()', () => {
@@ -6,6 +6,7 @@ import {
6
6
  import {
7
7
  TekMemoryDatasource, type ITekMemoryDatasource,
8
8
  } from '../../../../src';
9
+ import { flushPromises } from '../../../__helpers__';
9
10
 
10
11
  describe('TekMemoryDatasource', () => {
11
12
  init({
@@ -120,6 +121,7 @@ describe('TekMemoryDatasource', () => {
120
121
  const flushPromises = () => new Promise(setImmediate);
121
122
  datasource.watchUrl = false;
122
123
  const instance = new TekMemoryDatasource(datasource);
124
+ instance.initialize();
123
125
 
124
126
  await flushPromises();
125
127
  expect(instance.data.length).toBe(6);
@@ -333,8 +335,8 @@ describe('TekMemoryDatasource', () => {
333
335
 
334
336
  describe('searchJoin', () => {
335
337
  it('should retrieve data using search join', async () => {
336
- const flushPromises = () => new Promise(setImmediate);
337
338
  const instance = new TekMemoryDatasource(datasource);
339
+ instance.initialize();
338
340
 
339
341
  await flushPromises();
340
342
  expect(instance.data.length).toBe(6);
@@ -434,6 +436,7 @@ describe('TekMemoryDatasource', () => {
434
436
  dynamicFilter,
435
437
  searchJoin,
436
438
  });
439
+ instance.initialize();
437
440
 
438
441
  const props = instance.clone();
439
442
 
@@ -118,6 +118,7 @@ describe('TekRestDatasource', () => {
118
118
  name: { operation: 'EQUALS', relation: 'AND', value: '1' },
119
119
  },
120
120
  });
121
+ instance.initialize();
121
122
  await flushPromises();
122
123
 
123
124
  expect(instance.data.length).toBe(6);
@@ -314,7 +315,6 @@ describe('TekRestDatasource', () => {
314
315
  search_in: [],
315
316
  page: 1,
316
317
  limit: 10,
317
- search_in_params: '{}',
318
318
  },
319
319
  }));
320
320
  });
@@ -12,14 +12,16 @@ describe('TekFilterHelper', () => {
12
12
  describe('getLabel', () => {
13
13
  it('should call DateHelper.getLabel with the provided name', () => {
14
14
  const testName = 'testFilter';
15
+ const getLabelspy = jest.spyOn(DateHelper, 'getLabel');
15
16
  TekFilterHelper.getLabel(testName);
16
- expect(DateHelper.getLabel).toHaveBeenCalledWith(testName);
17
+ expect(getLabelspy).toHaveBeenCalledWith(testName);
17
18
  });
18
19
  });
19
20
 
20
21
  describe('getValue', () => {
21
22
  it('should call DateHelper.getValue with name and column dateFormat', () => {
22
23
  const testName = 'testValue';
24
+ const getValuespy = jest.spyOn(DateHelper, 'getValue');
23
25
  const mockColumn = {
24
26
  componentProps: {
25
27
  dateFormat: 'YYYY-MM-DD'
@@ -27,7 +29,7 @@ describe('TekFilterHelper', () => {
27
29
  } as TekGridColumn;
28
30
 
29
31
  TekFilterHelper.getValue(testName, mockColumn);
30
- expect(DateHelper.getValue).toHaveBeenCalledWith(testName, mockColumn.componentProps.dateFormat);
32
+ expect(getValuespy).toHaveBeenCalledWith(testName, mockColumn.componentProps.dateFormat);
31
33
  });
32
34
  });
33
35
 
@@ -35,18 +37,20 @@ describe('TekFilterHelper', () => {
35
37
  it('should call DateHelper.register with provided parameters', () => {
36
38
  const testName = 'testRegister';
37
39
  const testLabel = 'Test Register';
40
+ const registerspy = jest.spyOn(DateHelper, 'register');
38
41
  const testFn = () => new Date();
39
42
 
40
43
  TekFilterHelper.register(testName, testLabel, testFn);
41
- expect(DateHelper.register).toHaveBeenCalledWith(testName, testLabel, testFn);
44
+ expect(registerspy).toHaveBeenCalledWith(testName, testLabel, testFn);
42
45
  });
43
46
  });
44
47
 
45
48
  describe('unregister', () => {
46
49
  it('should call DateHelper.unregister with the provided name', () => {
47
50
  const testName = 'testUnregister';
51
+ const unregisterspy = jest.spyOn(DateHelper, 'unregister');
48
52
  TekFilterHelper.unregister(testName);
49
- expect(DateHelper.unregister).toHaveBeenCalledWith(testName);
53
+ expect(unregisterspy).toHaveBeenCalledWith(testName);
50
54
  });
51
55
  });
52
56
  });
@@ -12,7 +12,7 @@ import {
12
12
  ITekGridFilterButton,
13
13
  TekGrid, TekGridFilterButton, TekRestDatasource,
14
14
  } from '../../../../src';
15
- import { flushPromises, getChild, setClick } from '../../__helpers__';
15
+ import { flushPromises, getChild, setClick } from '../../../__helpers__';
16
16
 
17
17
  jest.mock('lodash.debounce', () => jest.fn((fn) => fn));
18
18
 
@@ -1,4 +1,4 @@
1
- import { IDictionary } from 'packages/core/dist/types';
1
+ import { IDictionary } from '@zeedhi/core';
2
2
  import { GroupedDataManager, TekGridColumn } from '../../../../src';
3
3
 
4
4
  jest.mock('lodash.debounce', () => jest.fn((fn) => fn));
@@ -0,0 +1,143 @@
1
+ import { DataNavigator } from '@zeedhi/common';
2
+ import { GroupedDataNavigator } from '../../../../src';
3
+ import { spyOnAllMethods } from '../../../__helpers__';
4
+
5
+ describe('GroupedDataNavigator', () => {
6
+ let navigator: GroupedDataNavigator;
7
+ let mockGrid: any;
8
+
9
+ beforeEach(() => {
10
+ mockGrid = {
11
+ isGrouped: jest.fn(),
12
+ getGroupedData: jest.fn(),
13
+ datasource: { currentRow: {} },
14
+ getRowKey: jest.fn(),
15
+ isItemVisible: jest.fn().mockReturnValue(true),
16
+ setCurrentRow: jest.fn(),
17
+ getData: jest.fn().mockReturnValue([]),
18
+ getPage: jest.fn(),
19
+ getLastPage: jest.fn(),
20
+ setPage: jest.fn(),
21
+ selectCell: jest.fn(),
22
+ columns: [],
23
+ };
24
+
25
+ navigator = new GroupedDataNavigator(mockGrid);
26
+ });
27
+
28
+ afterEach(() => {
29
+ jest.restoreAllMocks();
30
+ });
31
+
32
+ it('should initialize with the provided grid', () => {
33
+ expect(navigator).toBeInstanceOf(GroupedDataNavigator);
34
+ // @ts-ignore - access protected property for testing
35
+ expect(navigator.grid).toBe(mockGrid);
36
+ });
37
+
38
+ it('should delegate page navigation to DataNavigator', () => {
39
+ const spyObj = spyOnAllMethods(DataNavigator.prototype);
40
+
41
+ navigator.navigatePageUp();
42
+ navigator.navigatePageDown();
43
+
44
+ expect(spyObj.navigatePageUp).toHaveBeenCalled();
45
+ expect(spyObj.navigatePageDown).toHaveBeenCalled();
46
+ });
47
+
48
+ it('should delegate ungrouped datasource navigation to DataNavigator', () => {
49
+ const spyObj = spyOnAllMethods(DataNavigator.prototype);
50
+ mockGrid.isGrouped.mockReturnValue(false);
51
+
52
+ navigator.navigateDatasource('up');
53
+
54
+ expect(spyObj.navigateDatasource).toHaveBeenCalledWith('up');
55
+ expect(mockGrid.getGroupedData).not.toHaveBeenCalled();
56
+ });
57
+
58
+ describe('grouped datasource navigation', () => {
59
+ const groupedData = [
60
+ { group: true, groupValue: 'Group1' },
61
+ { id: 1, name: 'Item1' },
62
+ { id: 2, name: 'Item2' },
63
+ { group: true, groupValue: 'Group2' },
64
+ { id: 3, name: 'Item3' },
65
+ { groupFooter: true, groupValue: 'Group2' },
66
+ ];
67
+
68
+ beforeEach(() => {
69
+ mockGrid.isGrouped.mockReturnValue(true);
70
+ mockGrid.getGroupedData.mockReturnValue(groupedData);
71
+ mockGrid.getRowKey.mockImplementation((row: any) => row.id);
72
+ });
73
+
74
+ it('should navigate to the previous visible row', () => {
75
+ mockGrid.datasource.currentRow = groupedData[2];
76
+
77
+ navigator.navigateDatasource('up');
78
+
79
+ expect(mockGrid.setCurrentRow).toHaveBeenCalledWith(groupedData[1]);
80
+ });
81
+
82
+ it('should navigate to the next visible row', () => {
83
+ mockGrid.datasource.currentRow = groupedData[1];
84
+
85
+ navigator.navigateDatasource('down');
86
+
87
+ expect(mockGrid.setCurrentRow).toHaveBeenCalledWith(groupedData[2]);
88
+ });
89
+
90
+ it('should find the current group by group value', () => {
91
+ mockGrid.datasource.currentRow = groupedData[3];
92
+
93
+ navigator.navigateDatasource('down');
94
+
95
+ expect(mockGrid.setCurrentRow).toHaveBeenCalledWith(groupedData[4]);
96
+ });
97
+
98
+ it('should skip group footers and invisible rows', () => {
99
+ mockGrid.datasource.currentRow = groupedData[4];
100
+ mockGrid.isItemVisible.mockImplementation((row: any) => row !== groupedData[3]);
101
+
102
+ navigator.navigateDatasource('up');
103
+
104
+ expect(mockGrid.setCurrentRow).toHaveBeenCalledWith(groupedData[2]);
105
+ });
106
+
107
+ it('should navigate to the last valid row when currentRow is not defined', () => {
108
+ mockGrid.datasource.currentRow = {};
109
+
110
+ navigator.navigateDatasource('up');
111
+
112
+ expect(mockGrid.setCurrentRow).toHaveBeenCalledWith(groupedData[4]);
113
+ });
114
+
115
+ it('should navigate to the first valid row when currentRow is not defined', () => {
116
+ mockGrid.datasource.currentRow = {};
117
+
118
+ navigator.navigateDatasource('down');
119
+
120
+ expect(mockGrid.setCurrentRow).toHaveBeenCalledWith(groupedData[0]);
121
+ });
122
+
123
+ it('should stop at the beginning and end of grouped data', () => {
124
+ mockGrid.datasource.currentRow = groupedData[0];
125
+ mockGrid.getRowKey.mockImplementation((row: any) => row.groupValue || row.id);
126
+
127
+ navigator.navigateDatasource('up');
128
+ expect(mockGrid.setCurrentRow).not.toHaveBeenCalled();
129
+
130
+ mockGrid.datasource.currentRow = groupedData[4];
131
+ navigator.navigateDatasource('down');
132
+ expect(mockGrid.setCurrentRow).not.toHaveBeenCalled();
133
+ });
134
+
135
+ it('should do nothing when grouped data is empty', () => {
136
+ mockGrid.getGroupedData.mockReturnValue([]);
137
+
138
+ navigator.navigateDatasource('down');
139
+
140
+ expect(mockGrid.setCurrentRow).not.toHaveBeenCalled();
141
+ });
142
+ });
143
+ });
@@ -7,7 +7,7 @@ import {
7
7
  TekGridLayoutOptions,
8
8
  ITekGridProps,
9
9
  } from '../../../../src';
10
- import { flushPromises } from '../../__helpers__';
10
+ import { flushPromises } from '../../../__helpers__';
11
11
 
12
12
  let savedLayouts: string = '';
13
13
  const testLayouts: ITekGridLayoutInfo = {