@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.
- package/coverage/clover.xml +2 -2
- package/coverage/lcov-report/index.html +1 -1
- package/coverage/lcov-report/tests/__helpers__/component-event-helper.ts.html +100 -0
- package/coverage/lcov-report/tests/__helpers__/create-component.ts.html +109 -0
- package/coverage/lcov-report/tests/__helpers__/find-component.ts.html +139 -0
- package/coverage/lcov-report/tests/__helpers__/flush-promises-helper.ts.html +94 -0
- package/coverage/lcov-report/tests/__helpers__/get-child-helper.ts.html +166 -0
- package/coverage/lcov-report/tests/__helpers__/index.html +221 -0
- package/coverage/lcov-report/tests/__helpers__/index.ts.html +106 -0
- package/coverage/lcov-report/tests/__helpers__/mock-created-helper.ts.html +121 -0
- package/coverage/lcov-report/tests/__helpers__/spy-on-all-methods.ts.html +223 -0
- package/dist/teknisa-components-common.js +72 -66
- package/dist/teknisa-components-common.min.js +72 -66
- package/dist/types/components/index.d.ts +2 -0
- package/dist/types/components/tek-datasource/tek-memory-datasource.d.ts +16 -16
- package/dist/types/components/tek-datasource/tek-rest-datasource.d.ts +18 -20
- package/dist/types/components/tek-grid/grouped-data-navigator.d.ts +12 -0
- package/dist/types/components/tek-grid/index.d.ts +1 -1
- package/dist/types/components/tek-grid/tek-grid.d.ts +2 -1
- package/dist/types/components/tek-loading/interfaces.d.ts +6 -0
- package/dist/types/components/tek-loading/loading.d.ts +16 -0
- package/environments.json +12 -0
- package/jest.config.cjs +23 -0
- package/package.json +5 -3
- package/src/components/index.ts +2 -2
- package/src/components/tek-datasource/tek-memory-datasource.ts +2 -2
- package/src/components/tek-datasource/tek-rest-datasource.ts +2 -2
- package/src/components/tek-grid/grid-filter-button.ts +5 -3
- package/src/components/tek-grid/grouped-data-navigator.ts +66 -0
- package/src/components/tek-grid/index.ts +1 -1
- package/src/components/tek-grid/tek-grid.ts +19 -15
- package/src/components/tek-loading/interfaces.ts +7 -0
- package/src/components/tek-loading/loading.ts +27 -0
- package/tests/__helpers__/create-component.ts +8 -0
- package/tests/__helpers__/find-component.ts +18 -0
- package/tests/__helpers__/index.ts +4 -0
- package/tests/__helpers__/spy-on-all-methods.ts +46 -0
- package/tests/unit/components/tek-breadcrumb-header/tek-breadcrumb-header.spec.ts +2 -1
- package/tests/unit/components/tek-datasource/memory-datasource.spec.ts +4 -1
- package/tests/unit/components/tek-datasource/rest-datasource.spec.ts +1 -1
- package/tests/unit/components/tek-grid/filter-helper.spec.ts +8 -4
- package/tests/unit/components/tek-grid/grid-filter-button.spec.ts +1 -1
- package/tests/unit/components/tek-grid/grouped-data-manager.spec.ts +1 -1
- package/tests/unit/components/tek-grid/grouped-data-navigator.spec.ts +143 -0
- package/tests/unit/components/tek-grid/layout-options.spec.ts +1 -1
- package/tests/unit/components/tek-grid/tek-grid-column.spec.ts +23 -17
- package/tests/unit/components/tek-grid/tek-grid-columns-button.spec.ts +2 -1
- package/tests/unit/components/tek-grid/tek-grid.spec.ts +14 -12
- package/tests/unit/components/tek-grid/tek-memory-datasource.spec.ts +1 -1
- package/tests/unit/components/tek-grid/tek-rest-datasource.spec.ts +1 -1
- package/tests/unit/components/tek-loading/loading.spec.ts +29 -0
- package/tests/unit/components/tek-user-info/tek-user-info-list.spec.ts +12 -2
- package/tests/unit/components/tek-user-info/tek-user-info.spec.ts +18 -6
- package/tests/unit/utils/mock-console.ts +18 -0
- package/tests/unit/utils/setup.ts +5 -0
- package/dist/types/error/delete-rows-error.d.ts +0 -6
- package/jest.config.js +0 -1
- package/src/components/tek-grid/grouped-view-navigator.ts +0 -84
- package/tests/unit/components/crud/crud-add-button.spec.ts +0 -56
- package/tests/unit/components/crud/crud-button.spec.ts +0 -94
- package/tests/unit/components/crud/crud-cancel-button.spec.ts +0 -91
- package/tests/unit/components/crud/crud-delete-button.spec.ts +0 -122
- package/tests/unit/components/crud/crud-form.spec.ts +0 -165
- package/tests/unit/components/crud/crud-save-button.spec.ts +0 -118
- package/tests/unit/components/tek-card-title/CardTitle.spec.ts +0 -34
- package/tests/unit/components/tek-drag-grid/tek-drag-grid.spec.ts +0 -112
- package/tests/unit/components/tek-grid/grouped-view-navigator.spec.ts +0 -244
- package/tests/unit/components/tek-grid/multi-option.spec.ts +0 -139
- package/tests/unit/components/tek-image/Image.spec.ts +0 -67
- package/tests/unit/components/tek-iterable-carousel/iterable-carousel.spec.ts +0 -37
- package/tests/unit/components/tek-iterable-component-render/iterable-component-render.spec.ts +0 -200
- package/tests/unit/components/tek-loading/Loading.spec.ts +0 -30
- package/tests/unit/components/tek-notifications/notifications.spec.ts +0 -201
- package/tests/unit/components/tek-product-card/product-card.spec.ts +0 -61
- package/tests/unit/components/tree-grid/tree-grid.spec.ts +0 -776
- package/tests/unit/utils/grid-base/export-options/button-option.spec.ts +0 -44
- package/tests/unit/utils/grid-base/export-options/multi-option.spec.ts +0 -135
- package/tests/unit/utils/grid-base/grid-controller.spec.ts +0 -174
- 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
|
-
|
|
326
|
-
|
|
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
|
-
...
|
|
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-
|
|
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 {
|
|
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
|
|
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
|
|
449
|
-
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.
|
|
537
|
+
this.viewNavigator.navigateLeft(param);
|
|
540
538
|
}
|
|
541
539
|
|
|
542
540
|
directionalRight(param: IEventParam<any>): void {
|
|
543
541
|
this.groupedDataManager.directionalRight(param);
|
|
544
|
-
this.
|
|
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.
|
|
653
|
+
this.viewNavigator.setViewNavigate(viewNavigate);
|
|
654
654
|
}
|
|
655
655
|
|
|
656
656
|
navigateLeft(params: IEventParam<any>): void {
|
|
657
657
|
if (!this.cellSelection) return;
|
|
658
|
-
this.
|
|
658
|
+
this.viewNavigator.navigateLeft(params);
|
|
659
659
|
}
|
|
660
660
|
|
|
661
661
|
navigateRight(params: IEventParam<any>): void {
|
|
662
662
|
if (!this.cellSelection) return;
|
|
663
|
-
this.
|
|
663
|
+
this.viewNavigator.navigateRight(params);
|
|
664
664
|
}
|
|
665
665
|
|
|
666
666
|
navigateUp(): void {
|
|
667
|
-
this.
|
|
667
|
+
this.viewNavigator.navigateUp();
|
|
668
668
|
}
|
|
669
669
|
|
|
670
670
|
navigateDown(): void {
|
|
671
|
-
this.
|
|
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,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 };
|
|
@@ -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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 '
|
|
15
|
+
import { flushPromises, getChild, setClick } from '../../../__helpers__';
|
|
16
16
|
|
|
17
17
|
jest.mock('lodash.debounce', () => jest.fn((fn) => fn));
|
|
18
18
|
|
|
@@ -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 '
|
|
10
|
+
import { flushPromises } from '../../../__helpers__';
|
|
11
11
|
|
|
12
12
|
let savedLayouts: string = '';
|
|
13
13
|
const testLayouts: ITekGridLayoutInfo = {
|