diff --git a/package.json b/package.json index 078d2d09c..d0f187333 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "@slickgrid-universal/graphql": "~2.6.3", "@slickgrid-universal/odata": "~2.6.3", "@slickgrid-universal/text-export": "~2.6.3", - "@types/dompurify": "^2.4.0", + "@types/dompurify": "^3.0.0", "@types/flatpickr": "^3.1.2", "@types/fnando__sparkline": "^0.3.4", "@types/jest": "^29.5.0", diff --git a/src/app/modules/angular-slickgrid/components/__tests__/angular-slickgrid.component.spec.ts b/src/app/modules/angular-slickgrid/components/__tests__/angular-slickgrid.component.spec.ts index cb9eaa3cd..63b630b2b 100644 --- a/src/app/modules/angular-slickgrid/components/__tests__/angular-slickgrid.component.spec.ts +++ b/src/app/modules/angular-slickgrid/components/__tests__/angular-slickgrid.component.spec.ts @@ -1424,6 +1424,56 @@ describe('Angular-Slickgrid Custom Component instantiated via Constructor', () = expect(setColSpy).toHaveBeenCalledWith(mockCols); }); + it('should reflect columns with an extra row detail column in the grid when "enableRowDetailView" is set', () => { + const mockColsPresets = [{ columnId: 'firstName', width: 100 }]; + const mockCol = { id: 'firstName', field: 'firstName' }; + const mockCols = [{ id: '_detail_selector', field: '_detail_selector', editor: undefined, internalColumnEditor: {} }, mockCol]; + const getAssocColSpy = jest.spyOn(gridStateServiceStub, 'getAssociatedGridColumns').mockReturnValue([mockCol]); + const setColSpy = jest.spyOn(mockGrid, 'setColumns'); + + component.columnDefinitions = mockCols; + component.gridOptions = { ...gridOptions, enableRowDetailView: true, presets: { columns: mockColsPresets } } as unknown as GridOption; + component.initialization(slickEventHandler); + + expect(getAssocColSpy).toHaveBeenCalledWith(mockGrid, mockColsPresets); + expect(setColSpy).toHaveBeenCalledWith(mockCols); + }); + + it('should reflect columns with an extra row move column in the grid when "enableRowMoveManager" is set', () => { + const mockColsPresets = [{ columnId: 'firstName', width: 100 }]; + const mockCol = { id: 'firstName', field: 'firstName' }; + const mockCols = [{ id: '_move', field: '_move', editor: undefined, internalColumnEditor: {} }, mockCol]; + const getAssocColSpy = jest.spyOn(gridStateServiceStub, 'getAssociatedGridColumns').mockReturnValue([mockCol]); + const setColSpy = jest.spyOn(mockGrid, 'setColumns'); + + component.columnDefinitions = mockCols; + component.gridOptions = { ...gridOptions, enableRowMoveManager: true, presets: { columns: mockColsPresets } } as unknown as GridOption; + component.initialization(slickEventHandler); + + expect(getAssocColSpy).toHaveBeenCalledWith(mockGrid, mockColsPresets); + expect(setColSpy).toHaveBeenCalledWith(mockCols); + }); + + it('should reflect 3 dynamic columns (1-RowMove, 2-RowSelection, 3-RowDetail) when all associated extension flags are enabled', () => { + const mockColsPresets = [{ columnId: 'firstName', width: 100 }]; + const mockCol = { id: 'firstName', field: 'firstName' }; + const mockCols = [ + { id: '_move', field: '_move', editor: undefined, internalColumnEditor: {} }, + { id: '_checkbox_selector', field: '_checkbox_selector', editor: undefined, internalColumnEditor: {} }, + { id: '_detail_selector', field: '_detail_selector', editor: undefined, internalColumnEditor: {} }, + mockCol + ]; + const getAssocColSpy = jest.spyOn(gridStateServiceStub, 'getAssociatedGridColumns').mockReturnValue([mockCol]); + const setColSpy = jest.spyOn(mockGrid, 'setColumns'); + + component.columnDefinitions = mockCols; + component.gridOptions = { ...gridOptions, enableCheckboxSelector: true, enableRowDetailView: true, enableRowMoveManager: true, presets: { columns: mockColsPresets } } as unknown as GridOption; + component.initialization(slickEventHandler); + + expect(getAssocColSpy).toHaveBeenCalledWith(mockGrid, mockColsPresets); + expect(setColSpy).toHaveBeenCalledWith(mockCols); + }); + it('should execute backend service "init" method when set', () => { const mockPagination = { pageNumber: 1, pageSizes: [10, 25, 50], pageSize: 10, totalItems: 100 }; const mockGraphqlOptions = { datasetName: 'users', extraQueryArguments: [{ field: 'userId', value: 123 }] } as GraphqlServiceOption; diff --git a/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts b/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts index b5980c390..1eab1480e 100644 --- a/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts +++ b/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts @@ -1107,27 +1107,47 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { } } + protected insertDynamicPresetColumns(columnId: string, gridPresetColumns: Column[]) { + if (this._columnDefinitions) { + const columnPosition = this._columnDefinitions.findIndex(c => c.id === columnId); + if (columnPosition >= 0) { + const dynColumn = this._columnDefinitions[columnPosition]; + if (dynColumn?.id === columnId && !gridPresetColumns.some(c => c.id === columnId)) { + columnPosition > 0 + ? gridPresetColumns.splice(columnPosition, 0, dynColumn) + : gridPresetColumns.unshift(dynColumn); + } + } + } + } + /** Load any possible Columns Grid Presets */ private loadColumnPresetsWhenDatasetInitialized() { // if user entered some Columns "presets", we need to reflect them all in the grid if (this.gridOptions.presets && Array.isArray(this.gridOptions.presets.columns) && this.gridOptions.presets.columns.length > 0) { - const gridColumns: Column[] = this.gridStateService.getAssociatedGridColumns(this.slickGrid, this.gridOptions.presets.columns); - if (gridColumns && Array.isArray(gridColumns) && gridColumns.length > 0) { - // make sure that the checkbox selector is also visible if it is enabled + const gridPresetColumns: Column[] = this.gridStateService.getAssociatedGridColumns(this.slickGrid, this.gridOptions.presets.columns); + if (gridPresetColumns && Array.isArray(gridPresetColumns) && gridPresetColumns.length > 0 && Array.isArray(this._columnDefinitions)) { + // make sure that the dynamic columns are included in presets (1.Row Move, 2. Row Selection, 3. Row Detail) + if (this.gridOptions.enableRowMoveManager) { + const rmmColId = this.gridOptions?.rowMoveManager?.columnId ?? '_move'; + this.insertDynamicPresetColumns(rmmColId, gridPresetColumns); + } if (this.gridOptions.enableCheckboxSelector) { - const checkboxColumn = (Array.isArray(this._columnDefinitions) && this._columnDefinitions.length > 0) ? this._columnDefinitions[0] : null; - if (checkboxColumn && checkboxColumn.id === '_checkbox_selector' && gridColumns[0].id !== '_checkbox_selector') { - gridColumns.unshift(checkboxColumn); - } + const chkColId = this.gridOptions?.checkboxSelector?.columnId ?? '_checkbox_selector'; + this.insertDynamicPresetColumns(chkColId, gridPresetColumns); + } + if (this.gridOptions.enableRowDetailView) { + const rdvColId = this.gridOptions?.rowDetailView?.columnId ?? '_detail_selector'; + this.insertDynamicPresetColumns(rdvColId, gridPresetColumns); } // keep copy the original optional `width` properties optionally provided by the user. // We will use this when doing a resize by cell content, if user provided a `width` it won't override it. - gridColumns.forEach(col => col.originalWidth = col.width); + gridPresetColumns.forEach(col => col.originalWidth = col.width); // finally set the new presets columns (including checkbox selector if need be) - this.slickGrid.setColumns(gridColumns); - this.sharedService.visibleColumns = gridColumns; + this.slickGrid.setColumns(gridPresetColumns); + this.sharedService.visibleColumns = gridPresetColumns; } } } diff --git a/test/mockSlickEvent.ts b/test/mockSlickEvent.ts index a7d4ec27d..f97bab080 100644 --- a/test/mockSlickEvent.ts +++ b/test/mockSlickEvent.ts @@ -1,4 +1,4 @@ -import { SlickEvent, SlickEventHandler } from '@slickgrid-universal/common'; +import { SlickEvent, SlickEventData, SlickEventHandler } from '@slickgrid-universal/common'; // interface PubSubEvent { // name: string; @@ -6,7 +6,7 @@ import { SlickEvent, SlickEventHandler } from '@slickgrid-universal/common'; // } export class MockSlickEvent implements SlickEvent { - private _handlers = []; + private _handlers: any[] = []; notify(args: any, event?: any, scope?: any) { scope = scope || this; @@ -19,13 +19,13 @@ export class MockSlickEvent implements SlickEvent { return returnValue; } - subscribe(handler: (data: any, e?: any) => void): any { - this._handlers.push(handler); + subscribe(fn: (data: any, e?: any) => void): any { + this._handlers.push(fn); } - unsubscribe(handler: (data: any, e?: any) => void) { + unsubscribe(fn?: (e: SlickEventData | Event, data?: any) => void) { this._handlers.forEach((handlerFn, index) => { - if (handlerFn === handler) { + if (handlerFn === fn) { this._handlers.splice(index, 1); } }); @@ -33,7 +33,7 @@ export class MockSlickEvent implements SlickEvent { } export class MockSlickEventHandler implements SlickEventHandler { - private _handlers = []; + private _handlers: any[] = []; notify(eventName: string, data?: any) { const pubSub = this._handlers.find(subscription => subscription.name === eventName); diff --git a/test/translaterServiceStub.ts b/test/translaterServiceStub.ts index 979fbabe0..8b70447ae 100644 --- a/test/translaterServiceStub.ts +++ b/test/translaterServiceStub.ts @@ -1,12 +1,8 @@ import { TranslaterService, TranslateServiceEventName } from '@slickgrid-universal/common'; -import { I18N } from 'aurelia-i18n'; - export class TranslaterServiceStub implements TranslaterService { eventName = 'onLanguageChange' as TranslateServiceEventName; private _locale = 'en'; - constructor(private i18n?: I18N) { } - getCurrentLanguage(): string { return this._locale; } diff --git a/yarn.lock b/yarn.lock index b032b8e99..17ad32fd5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2407,10 +2407,10 @@ dependencies: "@types/node" "*" -"@types/dompurify@^2.4.0": - version "2.4.0" - resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-2.4.0.tgz#fd9706392a88e0e0e6d367f3588482d817df0ab9" - integrity sha512-IDBwO5IZhrKvHFUl+clZxgf3hn2b/lU6H1KaBShPkQyGJUQ0xwebezIPSuiyGwfz1UzJWQl4M7BDxtHtCCPlTg== +"@types/dompurify@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-3.0.0.tgz#28388a1aff0ced6e635b5b912c5f5935711d45b9" + integrity sha512-EcSqmgm/xJwH8CcJPy9AHNypp/j58CYga3nWdl93/wLxX6OH+rSD3aAj75NQazcZd1YKHJ/pjNZ9qmgVajggwQ== dependencies: "@types/trusted-types" "*"