@zeedhi/teknisa-components-common 1.125.0 → 1.126.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.
@@ -1335,6 +1335,9 @@ Messages.add({
1335
1335
  TEKGRID_WITH_GROUPS: '(Com grupos)',
1336
1336
  TEKGRID_GRID_MIRROR: '(Espelho do grid)',
1337
1337
  TEKGRID_NO_DATA: 'Não há dados para exportar',
1338
+ TEKGRID_LAYOUT_FILTER_CONFIRMATION: 'O layout possui informações de filtro. '
1339
+ + 'Deseja salvar o filtro com o layout?',
1340
+ TEKGRID_LAYOUT_HAS_FILTER: 'possui filtro',
1338
1341
  },
1339
1342
  },
1340
1343
  'en-US': {
@@ -1409,6 +1412,9 @@ Messages.add({
1409
1412
  TEKGRID_WITH_GROUPS: '(With groups)',
1410
1413
  TEKGRID_GRID_MIRROR: '(Grid mirror)',
1411
1414
  TEKGRID_NO_DATA: 'There is no data to export',
1415
+ TEKGRID_LAYOUT_FILTER_CONFIRMATION: 'The layout contains filter information. '
1416
+ + 'Do you want to save the filter with the layout?',
1417
+ TEKGRID_LAYOUT_HAS_FILTER: 'has filter',
1412
1418
  },
1413
1419
  },
1414
1420
  'es-CL': {
@@ -1483,6 +1489,9 @@ Messages.add({
1483
1489
  TEKGRID_WITH_GROUPS: '(Con grupos)',
1484
1490
  TEKGRID_GRID_MIRROR: '(Espejo de grid)',
1485
1491
  TEKGRID_NO_DATA: 'No hay datos para exportar',
1492
+ TEKGRID_LAYOUT_FILTER_CONFIRMATION: 'La disposición contiene información de filtro. '
1493
+ + '¿Desea guardar el filtro junto con la disposición?',
1494
+ TEKGRID_LAYOUT_HAS_FILTER: 'contiene filtro',
1486
1495
  },
1487
1496
  },
1488
1497
  });
@@ -3834,6 +3843,9 @@ class TekGridLayoutOptions extends ComponentRender {
3834
3843
  }
3835
3844
  });
3836
3845
  }
3846
+ checkLayoutsData(data) {
3847
+ return Object.assign(Object.assign({}, data), { layouts: Array.isArray(data === null || data === void 0 ? void 0 : data.layouts) ? {} : ((data === null || data === void 0 ? void 0 : data.layouts) || {}) });
3848
+ }
3837
3849
  loadLayoutsInfo() {
3838
3850
  return __awaiter(this, void 0, void 0, function* () {
3839
3851
  const eventFunction = this.events.loadLayouts || this.grid.events.loadLayouts;
@@ -3844,9 +3856,9 @@ class TekGridLayoutOptions extends ComponentRender {
3844
3856
  const route = Config.loadGridLayoutsEndPoint;
3845
3857
  const response = yield Http.get(`${route}?id=${this.grid.name}`);
3846
3858
  const responseData = response.data.data;
3847
- return responseData.length && responseData[0]
3859
+ return this.checkLayoutsData(responseData.length && responseData[0]
3848
3860
  ? responseData[0].layouts
3849
- : responseData.layouts || {};
3861
+ : responseData.layouts);
3850
3862
  }
3851
3863
  return JSON.parse(localStorage.getItem(this.grid.name) || '{}');
3852
3864
  });
@@ -3859,8 +3871,91 @@ class TekGridLayoutOptions extends ComponentRender {
3859
3871
  }
3860
3872
  return '';
3861
3873
  }
3874
+ layoutHasFilter(layout) {
3875
+ const layoutValue = typeof layout === 'string' ? this.layouts[layout] : layout;
3876
+ return Object.keys(layoutValue.filter || {}).length
3877
+ || Object.keys(layoutValue.dynamicFilter || {}).length;
3878
+ }
3862
3879
  newLayout(layout) {
3863
- this.fixColumns(layout);
3880
+ this.newLayoutValue = layout;
3881
+ if (this.layoutHasFilter(layout)) {
3882
+ if (!this.confirmFilterModal) {
3883
+ this.confirmFilterModal = ModalService.create({
3884
+ name: 'tekgrid_layout_filter_modal',
3885
+ persistent: true,
3886
+ children: [
3887
+ {
3888
+ name: 'tekgrid_layout_filter_header',
3889
+ component: 'ZdHeader',
3890
+ height: 32,
3891
+ cssClass: 'zd-mb-4',
3892
+ color: 'transparent',
3893
+ padless: true,
3894
+ elevation: 0,
3895
+ leftSlot: [
3896
+ {
3897
+ name: 'tekgrid_layout_filter_title',
3898
+ component: 'ZdText',
3899
+ text: I18n.translate('TEKGRID_LAYOUT_FILTER_CONFIRMATION'),
3900
+ cssClass: 'zd-theme-font-title',
3901
+ },
3902
+ ],
3903
+ rightSlot: [
3904
+ {
3905
+ name: 'closeModalButton',
3906
+ component: 'ZdModalCloseButton',
3907
+ small: true,
3908
+ modalName: 'tekgrid_layout_filter_modal',
3909
+ },
3910
+ ],
3911
+ },
3912
+ {
3913
+ name: 'tekgrid_layout_filter_footer',
3914
+ component: 'ZdFooter',
3915
+ color: 'transparent',
3916
+ padless: true,
3917
+ rightSlot: [
3918
+ {
3919
+ name: 'tekgrid_layout_filter_no',
3920
+ component: 'ZdButton',
3921
+ label: I18n.translate('NO'),
3922
+ outline: true,
3923
+ cssClass: 'zd-mr-2',
3924
+ events: {
3925
+ click: () => {
3926
+ this.doNewLayout(this.newLayoutValue, false);
3927
+ this.confirmFilterModal.hide();
3928
+ },
3929
+ },
3930
+ },
3931
+ {
3932
+ name: 'tekgrid_layout_filter_yes',
3933
+ component: 'ZdButton',
3934
+ label: I18n.translate('YES'),
3935
+ cssClass: 'zd-mr-2',
3936
+ events: {
3937
+ click: () => {
3938
+ this.doNewLayout(this.newLayoutValue, true);
3939
+ this.confirmFilterModal.hide();
3940
+ },
3941
+ },
3942
+ },
3943
+ ],
3944
+ },
3945
+ ],
3946
+ });
3947
+ }
3948
+ this.confirmFilterModal.show();
3949
+ }
3950
+ else {
3951
+ this.doNewLayout(layout);
3952
+ }
3953
+ }
3954
+ doNewLayout(layout, saveFilter = true) {
3955
+ if (!saveFilter) {
3956
+ layout.filter = undefined;
3957
+ layout.dynamicFilter = undefined;
3958
+ }
3864
3959
  this.currentLayoutName = layout.name;
3865
3960
  this.addLayout(layout);
3866
3961
  this.layoutEdited = false;
@@ -3878,6 +3973,14 @@ class TekGridLayoutOptions extends ComponentRender {
3878
3973
  this.layoutEdited = false;
3879
3974
  }
3880
3975
  applyLayout(name, save = true) {
3976
+ if (this.grid.events.beforeApplyLayout) {
3977
+ const canApply = this.grid.callEvent('beforeApplyLayout', {
3978
+ component: this.grid,
3979
+ layout: this.layouts[name],
3980
+ });
3981
+ if (canApply === false)
3982
+ return;
3983
+ }
3881
3984
  this.currentLayoutName = name;
3882
3985
  const layoutSelected = this.layouts[name];
3883
3986
  if (this.viewApplyLayout) {
@@ -1339,6 +1339,9 @@
1339
1339
  TEKGRID_WITH_GROUPS: '(Com grupos)',
1340
1340
  TEKGRID_GRID_MIRROR: '(Espelho do grid)',
1341
1341
  TEKGRID_NO_DATA: 'Não há dados para exportar',
1342
+ TEKGRID_LAYOUT_FILTER_CONFIRMATION: 'O layout possui informações de filtro. '
1343
+ + 'Deseja salvar o filtro com o layout?',
1344
+ TEKGRID_LAYOUT_HAS_FILTER: 'possui filtro',
1342
1345
  },
1343
1346
  },
1344
1347
  'en-US': {
@@ -1413,6 +1416,9 @@
1413
1416
  TEKGRID_WITH_GROUPS: '(With groups)',
1414
1417
  TEKGRID_GRID_MIRROR: '(Grid mirror)',
1415
1418
  TEKGRID_NO_DATA: 'There is no data to export',
1419
+ TEKGRID_LAYOUT_FILTER_CONFIRMATION: 'The layout contains filter information. '
1420
+ + 'Do you want to save the filter with the layout?',
1421
+ TEKGRID_LAYOUT_HAS_FILTER: 'has filter',
1416
1422
  },
1417
1423
  },
1418
1424
  'es-CL': {
@@ -1487,6 +1493,9 @@
1487
1493
  TEKGRID_WITH_GROUPS: '(Con grupos)',
1488
1494
  TEKGRID_GRID_MIRROR: '(Espejo de grid)',
1489
1495
  TEKGRID_NO_DATA: 'No hay datos para exportar',
1496
+ TEKGRID_LAYOUT_FILTER_CONFIRMATION: 'La disposición contiene información de filtro. '
1497
+ + '¿Desea guardar el filtro junto con la disposición?',
1498
+ TEKGRID_LAYOUT_HAS_FILTER: 'contiene filtro',
1490
1499
  },
1491
1500
  },
1492
1501
  });
@@ -3838,6 +3847,9 @@
3838
3847
  }
3839
3848
  });
3840
3849
  }
3850
+ checkLayoutsData(data) {
3851
+ return Object.assign(Object.assign({}, data), { layouts: Array.isArray(data === null || data === void 0 ? void 0 : data.layouts) ? {} : ((data === null || data === void 0 ? void 0 : data.layouts) || {}) });
3852
+ }
3841
3853
  loadLayoutsInfo() {
3842
3854
  return __awaiter(this, void 0, void 0, function* () {
3843
3855
  const eventFunction = this.events.loadLayouts || this.grid.events.loadLayouts;
@@ -3848,9 +3860,9 @@
3848
3860
  const route = core.Config.loadGridLayoutsEndPoint;
3849
3861
  const response = yield core.Http.get(`${route}?id=${this.grid.name}`);
3850
3862
  const responseData = response.data.data;
3851
- return responseData.length && responseData[0]
3863
+ return this.checkLayoutsData(responseData.length && responseData[0]
3852
3864
  ? responseData[0].layouts
3853
- : responseData.layouts || {};
3865
+ : responseData.layouts);
3854
3866
  }
3855
3867
  return JSON.parse(localStorage.getItem(this.grid.name) || '{}');
3856
3868
  });
@@ -3863,8 +3875,91 @@
3863
3875
  }
3864
3876
  return '';
3865
3877
  }
3878
+ layoutHasFilter(layout) {
3879
+ const layoutValue = typeof layout === 'string' ? this.layouts[layout] : layout;
3880
+ return Object.keys(layoutValue.filter || {}).length
3881
+ || Object.keys(layoutValue.dynamicFilter || {}).length;
3882
+ }
3866
3883
  newLayout(layout) {
3867
- this.fixColumns(layout);
3884
+ this.newLayoutValue = layout;
3885
+ if (this.layoutHasFilter(layout)) {
3886
+ if (!this.confirmFilterModal) {
3887
+ this.confirmFilterModal = common.ModalService.create({
3888
+ name: 'tekgrid_layout_filter_modal',
3889
+ persistent: true,
3890
+ children: [
3891
+ {
3892
+ name: 'tekgrid_layout_filter_header',
3893
+ component: 'ZdHeader',
3894
+ height: 32,
3895
+ cssClass: 'zd-mb-4',
3896
+ color: 'transparent',
3897
+ padless: true,
3898
+ elevation: 0,
3899
+ leftSlot: [
3900
+ {
3901
+ name: 'tekgrid_layout_filter_title',
3902
+ component: 'ZdText',
3903
+ text: core.I18n.translate('TEKGRID_LAYOUT_FILTER_CONFIRMATION'),
3904
+ cssClass: 'zd-theme-font-title',
3905
+ },
3906
+ ],
3907
+ rightSlot: [
3908
+ {
3909
+ name: 'closeModalButton',
3910
+ component: 'ZdModalCloseButton',
3911
+ small: true,
3912
+ modalName: 'tekgrid_layout_filter_modal',
3913
+ },
3914
+ ],
3915
+ },
3916
+ {
3917
+ name: 'tekgrid_layout_filter_footer',
3918
+ component: 'ZdFooter',
3919
+ color: 'transparent',
3920
+ padless: true,
3921
+ rightSlot: [
3922
+ {
3923
+ name: 'tekgrid_layout_filter_no',
3924
+ component: 'ZdButton',
3925
+ label: core.I18n.translate('NO'),
3926
+ outline: true,
3927
+ cssClass: 'zd-mr-2',
3928
+ events: {
3929
+ click: () => {
3930
+ this.doNewLayout(this.newLayoutValue, false);
3931
+ this.confirmFilterModal.hide();
3932
+ },
3933
+ },
3934
+ },
3935
+ {
3936
+ name: 'tekgrid_layout_filter_yes',
3937
+ component: 'ZdButton',
3938
+ label: core.I18n.translate('YES'),
3939
+ cssClass: 'zd-mr-2',
3940
+ events: {
3941
+ click: () => {
3942
+ this.doNewLayout(this.newLayoutValue, true);
3943
+ this.confirmFilterModal.hide();
3944
+ },
3945
+ },
3946
+ },
3947
+ ],
3948
+ },
3949
+ ],
3950
+ });
3951
+ }
3952
+ this.confirmFilterModal.show();
3953
+ }
3954
+ else {
3955
+ this.doNewLayout(layout);
3956
+ }
3957
+ }
3958
+ doNewLayout(layout, saveFilter = true) {
3959
+ if (!saveFilter) {
3960
+ layout.filter = undefined;
3961
+ layout.dynamicFilter = undefined;
3962
+ }
3868
3963
  this.currentLayoutName = layout.name;
3869
3964
  this.addLayout(layout);
3870
3965
  this.layoutEdited = false;
@@ -3882,6 +3977,14 @@
3882
3977
  this.layoutEdited = false;
3883
3978
  }
3884
3979
  applyLayout(name, save = true) {
3980
+ if (this.grid.events.beforeApplyLayout) {
3981
+ const canApply = this.grid.callEvent('beforeApplyLayout', {
3982
+ component: this.grid,
3983
+ layout: this.layouts[name],
3984
+ });
3985
+ if (canApply === false)
3986
+ return;
3987
+ }
3885
3988
  this.currentLayoutName = name;
3886
3989
  const layoutSelected = this.layouts[name];
3887
3990
  if (this.viewApplyLayout) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeedhi/teknisa-components-common",
3
- "version": "1.125.0",
3
+ "version": "1.126.0",
4
4
  "description": "Teknisa Components Common",
5
5
  "author": "Zeedhi <zeedhi@teknisa.com>",
6
6
  "license": "ISC",
@@ -32,5 +32,5 @@
32
32
  "peerDependencies": {
33
33
  "@zeedhi/core": "^1.97.0"
34
34
  },
35
- "gitHead": "8419653d2cc2243ea75d74b0640589e6ecefe6d2"
35
+ "gitHead": "8783f8a1fc5b3ee71dc7bc21662065f9e5e7c653"
36
36
  }
@@ -1,11 +1,15 @@
1
- import { Grid, Tag } from '@zeedhi/common';
1
+ import {
2
+ Grid, Tag, Button, ModalService, IModal, Modal,
3
+ } from '@zeedhi/common';
2
4
  import { Config, Http } from '@zeedhi/core';
3
5
  import {
4
6
  ITekConfig,
7
+ ITekGridApplyLayoutEventParams,
5
8
  ITekGridLayoutInfo,
6
9
  TekGrid,
7
10
  TekGridLayoutOptions,
8
11
  } from '../../../../src';
12
+ import { setClick } from '../../../__helpers__';
9
13
 
10
14
  let savedLayouts: string = '';
11
15
  const testLayouts: ITekGridLayoutInfo = {
@@ -379,6 +383,65 @@ describe('LayoutOptions', () => {
379
383
  layouts: { 'Name first': newLayout },
380
384
  }));
381
385
  });
386
+
387
+ it('should add new layout with filter', () => {
388
+ const newLayout1 = {
389
+ name: 'teste1',
390
+ filter: { name: '1' },
391
+ };
392
+ const newLayout2 = {
393
+ name: 'teste2',
394
+ filter: { name: '1' },
395
+ };
396
+ const tag = new Tag({
397
+ name: 'toolbar',
398
+ component: 'ZdTag',
399
+ tag: 'span',
400
+ });
401
+ const grid = new TekGrid({
402
+ name: 'grid',
403
+ component: 'TekGrid',
404
+ columns: [
405
+ { name: 'id' },
406
+ { name: 'name' },
407
+ { name: 'salary' },
408
+ ],
409
+ });
410
+ const instance = new TekGridLayoutOptions({ name: 'layout', component: 'TekGridLayoutOptions' });
411
+ instance.parent = tag;
412
+ tag.parent = grid;
413
+
414
+ instance.onMounted({} as HTMLElement);
415
+
416
+ let yesButton!: Button;
417
+ let noButton!: Button;
418
+
419
+ const modalServiceCreateSpy = jest.spyOn(ModalService, 'create').mockImplementation((modal: IModal) => {
420
+ const newModal = new Modal(modal);
421
+ noButton = new Button(newModal.children[1].rightSlot[0]);
422
+ yesButton = new Button(newModal.children[1].rightSlot[1]);
423
+ return newModal;
424
+ });
425
+
426
+ instance.newLayout(newLayout1);
427
+ setClick(yesButton!);
428
+
429
+ expect(instance.currentLayoutName).toBe('teste1');
430
+ expect(instance.layoutNames).toEqual(['teste1']);
431
+ expect(instance.layouts.teste1).toEqual(newLayout1);
432
+ expect(instance.layoutHasFilter('teste1')).toBeTruthy();
433
+
434
+ instance.newLayout(newLayout2);
435
+ setClick(noButton!);
436
+
437
+ expect(instance.currentLayoutName).toBe('teste2');
438
+ expect(instance.layoutNames).toEqual(['teste1', 'teste2']);
439
+ expect(instance.layouts.teste2.filter).toBeUndefined();
440
+ expect(instance.layouts.teste2.dynamicFilter).toBeUndefined();
441
+ expect(instance.layoutHasFilter('teste2')).toBeFalsy();
442
+
443
+ modalServiceCreateSpy.mockReset();
444
+ });
382
445
  });
383
446
 
384
447
  describe('addLayout()', () => {
@@ -499,6 +562,45 @@ describe('LayoutOptions', () => {
499
562
  expect(instance.currentLayoutName).toBe('Name first');
500
563
  expect(eventSavedLayouts.currentLayoutName).toBe('Name first');
501
564
  });
565
+
566
+ it('should call beforeApplyLayout', async () => {
567
+ const tag = new Tag({
568
+ name: 'toolbar',
569
+ component: 'ZdTag',
570
+ tag: 'span',
571
+ });
572
+ const grid = new TekGrid({
573
+ name: 'grid',
574
+ component: 'TekGrid',
575
+ columns: [
576
+ { name: 'id' },
577
+ { name: 'name' },
578
+ { name: 'salary' },
579
+ ],
580
+ events: {
581
+ beforeApplyLayout: ({ layout }: ITekGridApplyLayoutEventParams) => {
582
+ if (layout) layout.gridWidth = '740px';
583
+ return layout?.name === 'Name first';
584
+ },
585
+ },
586
+ });
587
+ const instance = new TekGridLayoutOptions({ name: 'layout', component: 'TekGridLayoutOptions' });
588
+ instance.parent = tag;
589
+ tag.parent = grid;
590
+
591
+ await instance.onMounted({} as HTMLElement);
592
+ instance.addLayout({
593
+ name: 'Name last',
594
+ });
595
+
596
+ expect(instance.currentLayoutName).toBe('');
597
+ instance.applyLayout('Name first');
598
+ expect(instance.currentLayoutName).toBe('Name first');
599
+ expect(instance.layouts['Name first'].gridWidth).toBe('740px');
600
+ instance.applyLayout('Name last');
601
+ expect(instance.currentLayoutName).toBe('Name first');
602
+ expect(instance.layouts['Name last'].gridWidth).toBe('740px');
603
+ });
502
604
  });
503
605
 
504
606
  describe('deleteLayout()', () => {
@@ -826,7 +928,7 @@ describe('LayoutOptions', () => {
826
928
  },
827
929
  };
828
930
 
829
- const spy = jest.spyOn(Http, 'get').mockImplementation(() => Promise.resolve({ data: { data: { layouts } } }));
931
+ let spy = jest.spyOn(Http, 'get').mockImplementation(() => Promise.resolve({ data: { data: { layouts } } }));
830
932
 
831
933
  await instance.onMounted({} as HTMLElement);
832
934
  await grid.onMounted({} as HTMLElement);
@@ -846,6 +948,20 @@ describe('LayoutOptions', () => {
846
948
  },
847
949
  });
848
950
  spy.mockReset();
951
+
952
+ // tratamento do erro no backend que esta retornando layouts como array vazio
953
+ instance.layouts = {};
954
+ spy = jest.spyOn(Http, 'get').mockImplementation(() => Promise.resolve({
955
+ data: { data: { layouts: { currentLayoutName: '', layouts: [] } } },
956
+ }));
957
+ await instance.onMounted({} as HTMLElement);
958
+ await grid.onMounted({} as HTMLElement);
959
+
960
+ await flushPromises();
961
+ expect(spy).toBeCalled();
962
+ expect(instance.layouts).toEqual({});
963
+ spy.mockReset();
964
+
849
965
  (Config as ITekConfig).loadGridLayoutsEndPoint = '';
850
966
  });
851
967
 
@@ -4,18 +4,22 @@ import { IDynamicFilterItem, TekGrid, TekGridLayoutOptions, TekTreeGrid } from '
4
4
  export interface ITekGridLayoutEventParams extends IEventParam<ITekGrid> {
5
5
  layouts: ITekGridLayoutInfo;
6
6
  }
7
+ export interface ITekGridApplyLayoutEventParams extends IEventParam<ITekGrid> {
8
+ layout?: ITekGridLayout;
9
+ }
7
10
  export interface ITekGridCalcSummaryEventParams extends IEventParam<ITekGrid> {
8
11
  summary: ITekGridSummary;
9
12
  columnName: string;
10
13
  rowValue: IDictionary<any>;
11
14
  }
12
15
  export declare type ITekGridEvent<T> = (event: T) => Promise<any>;
13
- export interface ITekGridEvents<T = IEventParam<any> | ITekGridLayoutEventParams | ITekGridCalcSummaryEventParams> extends IComponentEvents<T> {
16
+ export interface ITekGridEvents<T = IEventParam<any> | ITekGridLayoutEventParams | ITekGridApplyLayoutEventParams | ITekGridCalcSummaryEventParams> extends IComponentEvents<T> {
14
17
  addClick?: EventDef<T>;
15
18
  afterCancel?: EventDef<T>;
16
19
  afterDelete?: EventDef<T>;
17
20
  afterSave?: EventDef<T>;
18
21
  beforeApplyFilter?: EventDef<T>;
22
+ beforeApplyLayout?: EventDef<T>;
19
23
  beforeCancel?: EventDef<T>;
20
24
  beforeDelete?: EventDef<T>;
21
25
  beforeSave?: EventDef<T>;
@@ -17,9 +17,14 @@ export declare class TekGridLayoutOptions extends ComponentRender implements ITe
17
17
  grid: Grid;
18
18
  private getParentGrid;
19
19
  onMounted(element: HTMLElement): Promise<void>;
20
+ private checkLayoutsData;
20
21
  protected loadLayoutsInfo(): Promise<any>;
21
22
  getHelperValue(column: any): string | (string | undefined)[] | undefined;
23
+ layoutHasFilter(layout: string | ITekGridLayout): number;
24
+ private confirmFilterModal?;
25
+ private newLayoutValue?;
22
26
  newLayout(layout: ITekGridLayout): void;
27
+ private doNewLayout;
23
28
  addLayout(layout: ITekGridLayout): void;
24
29
  discardChanges(): void;
25
30
  applyLayout(name: string, save?: boolean): void;