From 2724c9741cbac30164976632b422de68bf21dcdf Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Fri, 1 Dec 2023 20:35:11 -0500 Subject: [PATCH 1/3] fix: registered external resouces should keep singleton ref - external resources can be provided through the grid options, but these options are sometime deep copied and that might have the side effect of losing the singleton ref of the instantiate services/resources, instead we can simply keep these singleton refs before any grid options merge can happen and that is in the constructor before the grid initializes and before the grid options are merged and sometime deep copied with global options --- src/app/examples/grid-clientside.component.ts | 2 +- src/app/examples/grid-colspan.component.ts | 4 +- .../grid-composite-editor.component.ts | 2 +- .../examples/grid-contextmenu.component.ts | 2 +- .../examples/grid-custom-tooltip.component.ts | 2 +- .../examples/grid-draggrouping.component.ts | 2 +- src/app/examples/grid-graphql.component.ts | 2 +- src/app/examples/grid-grouping.component.ts | 2 +- .../examples/grid-localization.component.ts | 2 +- src/app/examples/grid-range.component.ts | 2 +- .../grid-resize-by-content.component.ts | 2 +- .../grid-tree-data-hierarchical.component.ts | 2 +- .../grid-tree-data-parent-child.component.ts | 2 +- .../angular-slickgrid.component.spec.ts | 10 +- .../components/angular-slickgrid.component.ts | 156 +++++++++++------- 15 files changed, 113 insertions(+), 81 deletions(-) diff --git a/src/app/examples/grid-clientside.component.ts b/src/app/examples/grid-clientside.component.ts index 315cf9df9..74a4026e9 100644 --- a/src/app/examples/grid-clientside.component.ts +++ b/src/app/examples/grid-clientside.component.ts @@ -196,7 +196,7 @@ export class GridClientSideComponent implements OnInit { { columnId: 'complete', direction: 'ASC' } ], }, - registerExternalResources: [new ExcelExportService()], + externalResources: [new ExcelExportService()], }; // mock a dataset diff --git a/src/app/examples/grid-colspan.component.ts b/src/app/examples/grid-colspan.component.ts index d1ce7e4d3..8fb8e443d 100644 --- a/src/app/examples/grid-colspan.component.ts +++ b/src/app/examples/grid-colspan.component.ts @@ -68,7 +68,7 @@ export class GridColspanComponent implements OnInit { excelExportOptions: { exportWithFormatter: false }, - registerExternalResources: [new ExcelExportService()], + externalResources: [new ExcelExportService()], }; this.dataset1 = this.getData(500); @@ -100,7 +100,7 @@ export class GridColspanComponent implements OnInit { excelExportOptions: { exportWithFormatter: false }, - registerExternalResources: [new ExcelExportService()], + externalResources: [new ExcelExportService()], }; this.dataset2 = this.getData(500); diff --git a/src/app/examples/grid-composite-editor.component.ts b/src/app/examples/grid-composite-editor.component.ts index 1a3101e8a..297d54bb7 100644 --- a/src/app/examples/grid-composite-editor.component.ts +++ b/src/app/examples/grid-composite-editor.component.ts @@ -394,7 +394,7 @@ export class GridCompositeEditorComponent implements OnInit { excelExportOptions: { exportWithFormatter: false }, - registerExternalResources: [new ExcelExportService(), this.compositeEditorInstance], + externalResources: [new ExcelExportService(), this.compositeEditorInstance], enableFiltering: true, rowSelectionOptions: { // True (Single Selection), False (Multiple Selections) diff --git a/src/app/examples/grid-contextmenu.component.ts b/src/app/examples/grid-contextmenu.component.ts index 9f7b5aca4..d6ec3e6e5 100644 --- a/src/app/examples/grid-contextmenu.component.ts +++ b/src/app/examples/grid-contextmenu.component.ts @@ -297,7 +297,7 @@ export class GridContextMenuComponent implements OnInit, OnDestroy { columnHeaderStyle: { font: { bold: true, italic: true } } }, i18n: this.translate, - registerExternalResources: [new ExcelExportService()], + externalResources: [new ExcelExportService()], enableContextMenu: true, enableCellMenu: true, diff --git a/src/app/examples/grid-custom-tooltip.component.ts b/src/app/examples/grid-custom-tooltip.component.ts index 41fe400bd..95304d756 100644 --- a/src/app/examples/grid-custom-tooltip.component.ts +++ b/src/app/examples/grid-custom-tooltip.component.ts @@ -323,7 +323,7 @@ export class GridCustomTooltipComponent implements OnInit { exportWithFormatter: true }, // Custom Tooltip options can be defined in a Column or Grid Options or a mixed of both (first options found wins) - registerExternalResources: [new SlickCustomTooltip(), new ExcelExportService()], + externalResources: [new SlickCustomTooltip(), new ExcelExportService()], customTooltip: { formatter: this.tooltipFormatter.bind(this) as Formatter, headerFormatter: this.headerFormatter, diff --git a/src/app/examples/grid-draggrouping.component.ts b/src/app/examples/grid-draggrouping.component.ts index 37c1d374f..72149273a 100644 --- a/src/app/examples/grid-draggrouping.component.ts +++ b/src/app/examples/grid-draggrouping.component.ts @@ -244,7 +244,7 @@ export class GridDraggableGroupingComponent implements OnInit { enableTextExport: true, enableExcelExport: true, excelExportOptions: { sanitizeDataExport: true }, - registerExternalResources: [this.excelExportService, this.textExportService], + externalResources: [this.excelExportService, this.textExportService], }; this.loadData(500); diff --git a/src/app/examples/grid-graphql.component.ts b/src/app/examples/grid-graphql.component.ts index 2dc0ea6ea..9cc7200cb 100644 --- a/src/app/examples/grid-graphql.component.ts +++ b/src/app/examples/grid-graphql.component.ts @@ -276,7 +276,7 @@ export class GridGraphqlComponent implements OnInit, OnDestroy { setTimeout(() => { this.graphqlQuery = this.angularGrid.backendService!.buildQuery(); if (this.isWithCursor) { - // When using cursor pagination, the pagination service needs to updated with the PageInfo data from the latest request + // When using cursor pagination, the pagination service needs to be updated with the PageInfo data from the latest request // This might be done automatically if using a framework specific slickgrid library // Note because of this timeout, this may cause race conditions with rapid clicks! this.angularGrid?.paginationService?.setCursorPageInfo((mockedResult.data[GRAPHQL_QUERY_DATASET_NAME].pageInfo)); diff --git a/src/app/examples/grid-grouping.component.ts b/src/app/examples/grid-grouping.component.ts index 6bbdb5119..ed3bade9b 100644 --- a/src/app/examples/grid-grouping.component.ts +++ b/src/app/examples/grid-grouping.component.ts @@ -165,7 +165,7 @@ export class GridGroupingComponent implements OnInit { }, excelExportOptions: { sanitizeDataExport: true }, textExportOptions: { sanitizeDataExport: true }, - registerExternalResources: [this.excelExportService, this.textExportService], + externalResources: [this.excelExportService, this.textExportService], }; this.loadData(500); diff --git a/src/app/examples/grid-localization.component.ts b/src/app/examples/grid-localization.component.ts index 37e833daa..d7ce4bfbb 100644 --- a/src/app/examples/grid-localization.component.ts +++ b/src/app/examples/grid-localization.component.ts @@ -202,7 +202,7 @@ export class GridLocalizationComponent implements OnInit, OnDestroy { exportWithFormatter: true, sanitizeDataExport: true }, - registerExternalResources: [this.excelExportService, this.textExportService], + externalResources: [this.excelExportService, this.textExportService], }; this.loadData(NB_ITEMS); diff --git a/src/app/examples/grid-range.component.ts b/src/app/examples/grid-range.component.ts index f37ae6f5d..2a292ee10 100644 --- a/src/app/examples/grid-range.component.ts +++ b/src/app/examples/grid-range.component.ts @@ -184,7 +184,7 @@ export class GridRangeComponent implements OnInit, OnDestroy { { columnId: 'duration', direction: 'ASC' }, ], }, - registerExternalResources: [new SlickCustomTooltip(), new ExcelExportService()], + externalResources: [new SlickCustomTooltip(), new ExcelExportService()], }; // mock a dataset diff --git a/src/app/examples/grid-resize-by-content.component.ts b/src/app/examples/grid-resize-by-content.component.ts index 5a44e3460..9f6884440 100644 --- a/src/app/examples/grid-resize-by-content.component.ts +++ b/src/app/examples/grid-resize-by-content.component.ts @@ -327,7 +327,7 @@ export class GridResizeByContentComponent implements OnInit { excelExportOptions: { exportWithFormatter: false }, - registerExternalResources: [new ExcelExportService()], + externalResources: [new ExcelExportService()], enableFiltering: true, enableRowSelection: true, enableCheckboxSelector: true, diff --git a/src/app/examples/grid-tree-data-hierarchical.component.ts b/src/app/examples/grid-tree-data-hierarchical.component.ts index 801628665..b1f52aba7 100644 --- a/src/app/examples/grid-tree-data-hierarchical.component.ts +++ b/src/app/examples/grid-tree-data-hierarchical.component.ts @@ -128,7 +128,7 @@ export class GridTreeDataHierarchicalComponent implements OnInit { exportWithFormatter: true, sanitizeDataExport: true }, - registerExternalResources: [new ExcelExportService()], + externalResources: [new ExcelExportService()], enableFiltering: true, enableTreeData: true, // you must enable this flag for the filtering & sorting to work as expected multiColumnSort: false, // multi-column sorting is not supported with Tree Data, so you need to disable it diff --git a/src/app/examples/grid-tree-data-parent-child.component.ts b/src/app/examples/grid-tree-data-parent-child.component.ts index 231a08b8d..6dee20574 100644 --- a/src/app/examples/grid-tree-data-parent-child.component.ts +++ b/src/app/examples/grid-tree-data-parent-child.component.ts @@ -108,7 +108,7 @@ export class GridTreeDataParentChildComponent implements OnInit { enableAutoResize: true, enableExcelExport: true, excelExportOptions: { exportWithFormatter: true, sanitizeDataExport: true }, - registerExternalResources: [new ExcelExportService()], + externalResources: [new ExcelExportService()], enableFiltering: true, showCustomFooter: true, // display some metrics in the bottom custom footer enableTreeData: true, // you must enable this flag for the filtering & sorting to work as expected 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 0c0c58224..de523073f 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 @@ -973,7 +973,8 @@ describe('Angular-Slickgrid Custom Component instantiated via Constructor', () = const sortServiceSpy = jest.spyOn(sortServiceStub, 'addRxJsResource'); const paginationServiceSpy = jest.spyOn(paginationServiceStub, 'addRxJsResource'); - component.gridOptions = { registerExternalResources: [rxjsMock] } as unknown as GridOption; + component.gridOptions = { externalResources: [rxjsMock] } as unknown as GridOption; + component.registerExternalResources([rxjsMock], true); component.initialization(slickEventHandler); expect(backendUtilitySpy).toHaveBeenCalled(); @@ -1253,7 +1254,8 @@ describe('Angular-Slickgrid Custom Component instantiated via Constructor', () = jest.spyOn((component.gridOptions as any).backendServiceApi.service, 'buildQuery').mockReturnValue(query); const backendExecuteSpy = jest.spyOn(backendUtilityServiceStub, 'executeBackendProcessesCallback'); - component.gridOptions.registerExternalResources = [rxjsMock]; + component.gridOptions.externalResources = [rxjsMock]; + component.registerExternalResources([rxjsMock], true); component.gridOptions.backendServiceApi!.service.options = { executeProcessCommandOnInit: true }; component.initialization(slickEventHandler); @@ -1328,7 +1330,9 @@ describe('Angular-Slickgrid Custom Component instantiated via Constructor', () = jest.spyOn(component.gridOptions.backendServiceApi!.service, 'buildQuery').mockReturnValue(query); const backendErrorSpy = jest.spyOn(backendUtilityServiceStub, 'onBackendError'); - component.gridOptions.registerExternalResources = [rxjsMock]; + component.gridOptions.externalResources = [rxjsMock]; + component.resetExternalResources(); + component.registerExternalResources([rxjsMock], true); component.gridOptions.backendServiceApi!.service.options = { executeProcessCommandOnInit: true }; component.initialization(slickEventHandler); 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 15622d127..27be02459 100644 --- a/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts +++ b/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts @@ -90,20 +90,20 @@ declare const Slick: SlickNamespace; ] }) export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { - private _dataset?: any[] | null; - private _columnDefinitions!: Column[]; - private _currentDatasetLength = 0; - private _eventHandler: SlickEventHandler = new Slick.EventHandler(); - private _eventPubSubService!: EventPubSubService; - private _angularGridInstances: AngularGridInstance | undefined; - private _hideHeaderRowAfterPageLoad = false; - private _isGridInitialized = false; - private _isDatasetInitialized = false; - private _isDatasetHierarchicalInitialized = false; - private _isPaginationInitialized = false; - private _isLocalGrid = true; - private _paginationOptions: Pagination | undefined; - private _registeredResources: ExternalResource[] = []; + protected _dataset?: any[] | null; + protected _columnDefinitions!: Column[]; + protected _currentDatasetLength = 0; + protected _eventHandler: SlickEventHandler = new Slick.EventHandler(); + protected _eventPubSubService!: EventPubSubService; + protected _angularGridInstances: AngularGridInstance | undefined; + protected _hideHeaderRowAfterPageLoad = false; + protected _isGridInitialized = false; + protected _isDatasetInitialized = false; + protected _isDatasetHierarchicalInitialized = false; + protected _isPaginationInitialized = false; + protected _isLocalGrid = true; + protected _paginationOptions: Pagination | undefined; + protected _registeredResources: ExternalResource[] = []; dataView!: SlickDataView; slickGrid!: SlickGrid; groupingDefinition: any = {}; @@ -263,14 +263,14 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { } constructor( - private readonly angularUtilService: AngularUtilService, - private readonly appRef: ApplicationRef, - private readonly cd: ChangeDetectorRef, - private readonly containerService: ContainerService, - private readonly elm: ElementRef, - @Optional() private readonly translate: TranslateService, - @Optional() private readonly translaterService: TranslaterService, - @Inject('config') private forRootConfig: GridOption, + protected readonly angularUtilService: AngularUtilService, + protected readonly appRef: ApplicationRef, + protected readonly cd: ChangeDetectorRef, + protected readonly containerService: ContainerService, + protected readonly elm: ElementRef, + @Optional() protected readonly translate: TranslateService, + @Optional() protected readonly translaterService: TranslaterService, + @Inject('config') protected forRootConfig: GridOption, @Inject('externalService') externalServices: ExternalTestingDependencies ) { const slickgridConfig = new SlickgridConfig(); @@ -342,6 +342,15 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { if (!this.gridOptions || !this.columnDefinitions) { throw new Error('Using `` requires [gridOptions] and [columnDefinitions], it seems that you might have forgot to provide them since at least of them is undefined.'); } + + // save resource refs to register before the grid options are merged and possibly deep copied + // since a deep copy of grid options would lose original resource refs but we want to keep them as singleton + this._registeredResources = this.gridOptions?.externalResources || this.gridOptions?.registerExternalResources || []; + /* istanbul ignore if */ + if (this.gridOptions?.registerExternalResources) { + console.warn('[Angular-Slickgrid] Please note that the grid option `registerExternalResources` was deprecated and will be removed in next major, please use `externalResources` instead.'); + } + this.initialization(this._eventHandler); this._isGridInitialized = true; @@ -368,15 +377,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { this.serviceList = []; // dispose all registered external resources - if (Array.isArray(this._registeredResources)) { - while (this._registeredResources.length > 0) { - const resource = this._registeredResources.pop(); - if (resource?.dispose) { - resource.dispose(); - } - } - this._registeredResources = []; - } + this.disposeExternalResources(); // dispose the Components this.slickEmptyWarning?.dispose(); @@ -423,6 +424,18 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { this.slickGrid = undefined as any; } + disposeExternalResources() { + if (Array.isArray(this._registeredResources)) { + while (this._registeredResources.length > 0) { + const res = this._registeredResources.pop(); + if (res?.dispose) { + res.dispose(); + } + } + } + this._registeredResources = []; + } + emptyGridContainerElm() { const gridContainerId = this.gridOptions?.gridContainerId ?? 'grid1'; const gridContainerElm = document.querySelector(`#${gridContainerId}`); @@ -786,22 +799,22 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { } // - // private functions + // protected functions // ------------------ /** * Loop through all column definitions and 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. */ - private copyColumnWidthsReference(columnDefinitions: Column[]) { + protected copyColumnWidthsReference(columnDefinitions: Column[]) { columnDefinitions.forEach(col => col.originalWidth = col.width); } - private displayEmptyDataWarning(showWarning = true) { + protected displayEmptyDataWarning(showWarning = true) { this.slickEmptyWarning?.showEmptyDataMessage(showWarning); } - private bindDifferentHooks(grid: SlickGrid, gridOptions: GridOption, dataView: SlickDataView) { + protected bindDifferentHooks(grid: SlickGrid, gridOptions: GridOption, dataView: SlickDataView) { // on locale change, we have to manually translate the Headers, GridMenu if (this.translate?.onLangChange) { // translate some of them on first load, then on each language change @@ -937,7 +950,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { } } - private bindBackendCallbackFunctions(gridOptions: GridOption) { + protected bindBackendCallbackFunctions(gridOptions: GridOption) { const backendApi = gridOptions.backendServiceApi; const backendApiService = backendApi && backendApi.service; const serviceOptions: BackendServiceOption = backendApiService?.options ?? {}; @@ -1005,7 +1018,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { } } - private bindResizeHook(grid: SlickGrid, options: GridOption) { + protected bindResizeHook(grid: SlickGrid, options: GridOption) { if ((options.autoFitColumnsOnFirstLoad && options.autosizeColumnsByCellContentOnFirstLoad) || (options.enableAutoSizeColumns && options.enableAutoResizeColumnsByCellContent)) { throw new Error(`[Angular-Slickgrid] You cannot enable both autosize/fit viewport & resize by content, you must choose which resize technique to use. You can enable these 2 options ("autoFitColumnsOnFirstLoad" and "enableAutoSizeColumns") OR these other 2 options ("autosizeColumnsByCellContentOnFirstLoad" and "enableAutoResizeColumnsByCellContent").`); } @@ -1028,7 +1041,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { } } - private executeAfterDataviewCreated(_grid: SlickGrid, gridOptions: GridOption) { + protected executeAfterDataviewCreated(_grid: SlickGrid, gridOptions: GridOption) { // if user entered some Sort "presets", we need to reflect them all in the DOM if (gridOptions.enableSorting) { if (gridOptions.presets && Array.isArray(gridOptions.presets.sorters)) { @@ -1040,7 +1053,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { } /** When data changes in the DataView, we'll refresh the metrics and/or display a warning if the dataset is empty */ - private handleOnItemCountChanged(currentPageRowItemCount: number, totalItemCount: number) { + protected handleOnItemCountChanged(currentPageRowItemCount: number, totalItemCount: number) { this._currentDatasetLength = totalItemCount; this.metrics = { startTime: new Date(), @@ -1059,7 +1072,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { } } - private initializePaginationService(paginationOptions: Pagination) { + protected initializePaginationService(paginationOptions: Pagination) { if (this.gridOptions) { this.paginationData = { gridOptions: this.gridOptions, @@ -1087,7 +1100,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { } /** Load the Editor Collection asynchronously and replace the "collection" property when Observable resolves */ - private loadEditorCollectionAsync(column: Column) { + protected loadEditorCollectionAsync(column: Column) { const collectionAsync = column && column.editor && (column.editor as ColumnEditor).collectionAsync; if (collectionAsync instanceof Observable) { this.subscriptions.push( @@ -1119,7 +1132,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { } /** Load any possible Columns Grid Presets */ - private loadColumnPresetsWhenDatasetInitialized() { + protected 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 gridPresetColumns: Column[] = this.gridStateService.getAssociatedGridColumns(this.slickGrid, this.gridOptions.presets.columns); @@ -1150,7 +1163,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { } /** Load any possible Filters Grid Presets */ - private loadFilterPresetsWhenDatasetInitialized() { + protected loadFilterPresetsWhenDatasetInitialized() { if (this.gridOptions && !this.customDataView) { // if user entered some Filter "presets", we need to reflect them all in the DOM // also note that a presets of Tree Data Toggling will also call this method because Tree Data toggling does work with data filtering @@ -1166,7 +1179,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { * if so then also check if there's any presets and finally initialize the PaginationService * a local grid with Pagination presets will potentially have a different total of items, we'll need to get it from the DataView and update our total */ - private loadLocalGridPagination(dataset?: any[]) { + protected loadLocalGridPagination(dataset?: any[]) { if (this.gridOptions && this._paginationOptions) { this.totalItems = Array.isArray(dataset) ? dataset.length : 0; if (this._paginationOptions && this.dataView?.getPagingInfo) { @@ -1182,7 +1195,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { } /** Load any Row Selections into the DataView that were presets by the user */ - private loadRowSelectionPresetWhenExists() { + protected loadRowSelectionPresetWhenExists() { // if user entered some Row Selections "presets" const presets = this.gridOptions?.presets; const enableRowSelection = this.gridOptions && (this.gridOptions.enableCheckboxSelector || this.gridOptions.enableRowSelection); @@ -1209,7 +1222,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { } } - private mergeGridOptions(gridOptions: GridOption): GridOption { + protected mergeGridOptions(gridOptions: GridOption): GridOption { gridOptions.gridId = this.gridId; gridOptions.gridContainerId = `slickGridContainer-${this.gridId}`; @@ -1247,10 +1260,21 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { return options; } - /** Pre-Register any Resource that don't require SlickGrid to be instantiated (for example RxJS Resource & RowDetail) */ - private preRegisterResources() { - this._registeredResources = this.gridOptions.registerExternalResources || []; + /** Add a register a new external resource, user could also optional dispose all previous resources before pushing any new resources to the resources array list. */ + registerExternalResources(resources: ExternalResource[], disposePreviousResources = false) { + if (disposePreviousResources) { + this.disposeExternalResources(); + } + resources.forEach(res => this._registeredResources.push(res)); + this.initializeExternalResources(resources); + } + + resetExternalResources() { + this._registeredResources = []; + } + /** Pre-Register any Resource that don't require SlickGrid to be instantiated (for example RxJS Resource & RowDetail) */ + protected preRegisterResources() { // Angular-Slickgrid requires RxJS, so we'll register it as the first resource this.registerRxJsResource(new RxJsResource() as RxJsFacade); @@ -1262,7 +1286,17 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { } } - private registerResources() { + protected initializeExternalResources(resources: ExternalResource[]) { + if (Array.isArray(resources)) { + for (const resource of resources) { + if (this.slickGrid && typeof resource.init === 'function') { + resource.init(this.slickGrid, this.containerService); + } + } + } + } + + protected registerResources() { // at this point, we consider all the registered services as external services, anything else registered afterward aren't external if (Array.isArray(this._registeredResources)) { this.sharedService.externalRegisteredResources = this._registeredResources; @@ -1292,17 +1326,11 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { // bind & initialize all Components/Services that were tagged as enabled // register all services by executing their init method and providing them with the Grid object - if (Array.isArray(this._registeredResources)) { - for (const resource of this._registeredResources) { - if (this.slickGrid && typeof resource.init === 'function') { - resource.init(this.slickGrid, this.containerService); - } - } - } + this.initializeExternalResources(this._registeredResources); } /** Register the RxJS Resource in all necessary services which uses */ - private registerRxJsResource(resource: RxJsFacade) { + protected registerRxJsResource(resource: RxJsFacade) { this.rxjs = resource; this.backendUtilityService.addRxJsResource(this.rxjs); this.filterFactory.addRxJsResource(this.rxjs); @@ -1318,7 +1346,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { * @param {Boolean} showPagination - show (new render) or not (dispose) the Pagination * @param {Boolean} shouldDisposePaginationService - when disposing the Pagination, do we also want to dispose of the Pagination Service? (defaults to True) */ - private renderPagination(showPagination = true) { + protected renderPagination(showPagination = true) { if (this.gridOptions?.enablePagination && !this._isPaginationInitialized && showPagination) { this.slickPagination = new SlickPaginationComponent(this.paginationService, this._eventPubSubService, this.sharedService, this.translaterService); this.slickPagination.renderPagination(this.gridContainerElement as HTMLElement); @@ -1337,7 +1365,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { * @param {Boolean} forceGridRefresh - optionally force a full grid refresh * @returns {Array} sort flat parent/child dataset */ - private sortTreeDataset(flatDatasetInput: T[], forceGridRefresh = false): T[] { + protected sortTreeDataset(flatDatasetInput: T[], forceGridRefresh = false): T[] { const prevDatasetLn = this._currentDatasetLength; let sortedDatasetResult; let flatDatasetOutput: any[] = []; @@ -1374,7 +1402,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { * so in our lib we will swap "editor" and copy it into a new property called "internalColumnEditor" * then take back "editor.model" and make it the new "editor" so that SlickGrid Editor Factory still works */ - private swapInternalEditorToSlickGridFactoryEditor(columnDefinitions: Column[]) { + protected swapInternalEditorToSlickGridFactoryEditor(columnDefinitions: Column[]) { if (columnDefinitions.some(col => `${col.id}`.includes('.'))) { console.error('[Angular-Slickgrid] Make sure that none of your Column Definition "id" property includes a dot in its name because that will cause some problems with the Editors. For example if your column definition "field" property is "user.firstName" then use "firstName" as the column "id".'); } @@ -1388,12 +1416,12 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { }); } - private translateColumnHeaderTitleKeys() { + protected translateColumnHeaderTitleKeys() { // translate all columns (including hidden columns) this.extensionUtility.translateItems(this.sharedService.allColumns, 'nameKey', 'name'); } - private translateColumnGroupKeys() { + protected translateColumnGroupKeys() { // translate all column groups (including hidden columns) this.extensionUtility.translateItems(this.sharedService.allColumns, 'columnGroupKey', 'columnGroup'); } @@ -1403,7 +1431,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy { * Since this is called after the async call resolves, the pointer will not be the same as the "column" argument passed. * Once we found the new pointer, we will reassign the "editor" and "collection" to the "internalColumnEditor" so it has newest collection */ - private updateEditorCollection(column: Column, newCollection: T[]) { + protected updateEditorCollection(column: Column, newCollection: T[]) { (column.editor as ColumnEditor).collection = newCollection; (column.editor as ColumnEditor).disabled = false; From 6d6bfb3da0e90684731ea7a9edb2b076a3bd153a Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Wed, 6 Dec 2023 23:14:49 -0500 Subject: [PATCH 2/3] docs: add Stack Overflow & Discussions templates --- .github/ISSUE_TEMPLATE/config.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 6c50401cd..6c7d5f57c 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,8 @@ blank_issues_enabled: false contact_links: - - name: Questions & Discussions + - name: Questions + url: https://stackoverflow.com/search?q=slickgrid + about: Use Stack Overflow to find or ask for any related SlickGrid questions + - name: Discussions url: https://github.com/ghiscoding/Angular-Slickgrid/discussions about: Use GitHub discussions for message-board style questions and discussions. \ No newline at end of file From e82c9f465cc3119fc42bafd68b27cfa474cacb39 Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Thu, 7 Dec 2023 22:34:22 -0500 Subject: [PATCH 3/3] chore: update all non-major deps --- package.json | 40 +++---- yarn.lock | 331 ++++++++++++++++++++++++++------------------------- 2 files changed, 188 insertions(+), 183 deletions(-) diff --git a/package.json b/package.json index 038182a4e..ab8693e6f 100644 --- a/package.json +++ b/package.json @@ -50,17 +50,17 @@ }, "dependencies": { "@ngx-translate/core": "^15.0.0", - "@slickgrid-universal/common": "~3.6.0", - "@slickgrid-universal/custom-footer-component": "~3.6.0", - "@slickgrid-universal/empty-warning-component": "~3.6.0", - "@slickgrid-universal/event-pub-sub": "~3.6.0", - "@slickgrid-universal/pagination-component": "~3.6.0", - "@slickgrid-universal/row-detail-view-plugin": "~3.6.0", - "@slickgrid-universal/rxjs-observable": "~3.6.0", + "@slickgrid-universal/common": "~3.7.0", + "@slickgrid-universal/custom-footer-component": "~3.7.0", + "@slickgrid-universal/empty-warning-component": "~3.7.0", + "@slickgrid-universal/event-pub-sub": "~3.7.0", + "@slickgrid-universal/pagination-component": "~3.7.0", + "@slickgrid-universal/row-detail-view-plugin": "~3.7.0", + "@slickgrid-universal/rxjs-observable": "~3.7.0", "dequal": "^2.0.3", "dompurify": "^3.0.6", "rxjs": "^7.8.1", - "sortablejs": "^1.15.0" + "sortablejs": "^1.15.1" }, "devDependencies": { "@4tw/cypress-drag-drop": "^2.2.5", @@ -87,25 +87,25 @@ "@ngx-translate/http-loader": "^8.0.0", "@popperjs/core": "^2.11.8", "@release-it/conventional-changelog": "^8.0.1", - "@slickgrid-universal/composite-editor-component": "~3.6.0", - "@slickgrid-universal/custom-tooltip-plugin": "~3.6.0", - "@slickgrid-universal/excel-export": "~3.6.0", - "@slickgrid-universal/graphql": "~3.6.0", - "@slickgrid-universal/odata": "~3.6.0", - "@slickgrid-universal/text-export": "~3.6.0", + "@slickgrid-universal/composite-editor-component": "~3.7.0", + "@slickgrid-universal/custom-tooltip-plugin": "~3.7.0", + "@slickgrid-universal/excel-export": "~3.7.0", + "@slickgrid-universal/graphql": "~3.7.0", + "@slickgrid-universal/odata": "~3.7.0", + "@slickgrid-universal/text-export": "~3.7.0", "@types/dompurify": "^3.0.5", "@types/flatpickr": "^3.1.2", "@types/fnando__sparkline": "^0.3.7", - "@types/jest": "^29.5.10", - "@types/node": "^20.10.0", + "@types/jest": "^29.5.11", + "@types/node": "^20.10.4", "@types/sortablejs": "^1.15.7", - "@typescript-eslint/eslint-plugin": "^6.12.0", - "@typescript-eslint/parser": "^6.12.0", + "@typescript-eslint/eslint-plugin": "^6.13.2", + "@typescript-eslint/parser": "^6.13.2", "bootstrap": "^5.3.2", "copyfiles": "^2.4.1", "custom-event-polyfill": "^1.0.7", - "cypress": "^13.6.0", - "eslint": "^8.54.0", + "cypress": "^13.6.1", + "eslint": "^8.55.0", "fetch-jsonp": "^1.3.0", "font-awesome": "^4.7.0", "jest": "^29.7.0", diff --git a/yarn.lock b/yarn.lock index 90cd7f99a..f9bc76d66 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2223,10 +2223,10 @@ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.6.2.tgz#1816b5f6948029c5eaacb0703b850ee0cb37d8f8" integrity sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw== -"@eslint/eslintrc@^2.1.3": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.3.tgz#797470a75fe0fbd5a53350ee715e85e87baff22d" - integrity sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA== +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -2238,10 +2238,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.54.0": - version "8.54.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.54.0.tgz#4fab9a2ff7860082c304f750e94acd644cf984cf" - integrity sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ== +"@eslint/js@8.55.0": + version "8.55.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.55.0.tgz#b721d52060f369aa259cf97392403cb9ce892ec6" + integrity sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA== "@faker-js/faker@^8.3.1": version "8.3.1" @@ -3034,129 +3034,129 @@ dependencies: "@sinonjs/commons" "^3.0.0" -"@slickgrid-universal/binding@~3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/binding/-/binding-3.6.0.tgz#05e512440e48b8dd86877ef765d69a06b360174a" - integrity sha512-QDwN5kCvazo5IQgaNT6V2l952Ys3iCh2+RazLA/MpECRnHz66dmeDzGpjbhpGnAiOuFJXKSnXoa0VXG02RUtrg== +"@slickgrid-universal/binding@~3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/binding/-/binding-3.7.0.tgz#5cc5b21ae90d2f533ae72dbaebcf3f297624e74d" + integrity sha512-qKCYejhhgY14E+yMdvkrcPppdjL1CEp9pff6tONhUzrm+of40fljtESF6gf4t20GgePiPDXwxdmxdrUcZYYPdg== -"@slickgrid-universal/common@~3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/common/-/common-3.6.0.tgz#39117ceb3d862dc80f118982f0b7f82463b56012" - integrity sha512-fKM35Kof7KEUFn9+XPvQXg1Fy/8smH5D6W7dl/+T3zoPxYDJlk4NG9wPrqBnDwNpY1hBUX0VN4VImc6lOiSkLA== +"@slickgrid-universal/common@~3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/common/-/common-3.7.0.tgz#122dd1f08ecbdaacec03761b45a697249a8b15a9" + integrity sha512-5hh0wWfaK7ttU4EVzAYo+7rFWBfBb1jnjjO4rZjrJXCGx0WIp1qb/qPNSpPldOoLzXZRcickforchsrFQfJBew== dependencies: - "@slickgrid-universal/event-pub-sub" "~3.6.0" - "@slickgrid-universal/utils" "~3.6.0" + "@slickgrid-universal/event-pub-sub" "~3.7.0" + "@slickgrid-universal/utils" "~3.7.0" autocompleter "^9.1.2" dequal "^2.0.3" dompurify "^3.0.6" flatpickr "^4.6.13" moment-mini "^2.29.4" multiple-select-vanilla "^0.6.3" - slickgrid "^4.1.5" - sortablejs "^1.15.0" + slickgrid "^4.1.7" + sortablejs "^1.15.1" un-flatten-tree "^2.0.12" -"@slickgrid-universal/composite-editor-component@~3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/composite-editor-component/-/composite-editor-component-3.6.0.tgz#85dddf6f6207cc4101ef65e9ef02ce3ecdfeafd1" - integrity sha512-OGoNFTGmD+IahoZjmvmvUTTtvyyb54SjjTkwXEyfR6HWDCiLxDaTFq1PM95PNwce0hi39EuoJwdq0w/rGDvi1w== +"@slickgrid-universal/composite-editor-component@~3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/composite-editor-component/-/composite-editor-component-3.7.0.tgz#ab2934c07529e35a9f30ecdc3ab771425d868671" + integrity sha512-FZAmRy3IZqHuU8MC0n+OF5CtHrHGpgDjcy6LWyB1UvN6P1kHLm/ztgboUe2Q+GiYq2LoxyykFNbqPMeG485ciA== dependencies: - "@slickgrid-universal/common" "~3.6.0" - "@slickgrid-universal/utils" "~3.6.0" + "@slickgrid-universal/common" "~3.7.0" + "@slickgrid-universal/utils" "~3.7.0" -"@slickgrid-universal/custom-footer-component@~3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/custom-footer-component/-/custom-footer-component-3.6.0.tgz#b1f9078d2eb4083bef72b7306fa96119979fba25" - integrity sha512-R9tsDKxy+8zvqYBcURfh3ERXQAQYnreoGCZ7qRJQgXFSgl5fD3P6lrbQ6t3g+i/FXRklzDH11HSm6EslSonxjQ== +"@slickgrid-universal/custom-footer-component@~3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/custom-footer-component/-/custom-footer-component-3.7.0.tgz#39b4d3ab1dd8b37dcdc28a9e153ac1a4a5fc587d" + integrity sha512-d12ptYPeLc49KOxjmx4JUrZ0KQ59ZVpATAEXfI52Lt29lTABK3vBL5dx2iUFIRZemNhWIIIs5h4cxCXjvwkggw== dependencies: - "@slickgrid-universal/binding" "~3.6.0" - "@slickgrid-universal/common" "~3.6.0" + "@slickgrid-universal/binding" "~3.7.0" + "@slickgrid-universal/common" "~3.7.0" moment-mini "^2.29.4" -"@slickgrid-universal/custom-tooltip-plugin@~3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/custom-tooltip-plugin/-/custom-tooltip-plugin-3.6.0.tgz#f2010a769a8c3c2bcd2abb576f7db3083c64f8ed" - integrity sha512-pJF/+MwFhR8B0rO6aAGmxEEhKXriFddBLCLvNE/WCkQ1ujP8rxqD4j6/0HB2/uPwfrZO0tVLxk1u4FZw1vp/eA== +"@slickgrid-universal/custom-tooltip-plugin@~3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/custom-tooltip-plugin/-/custom-tooltip-plugin-3.7.0.tgz#b9d53624c24aca42231d337ea66052a7bb2334c0" + integrity sha512-1CgtWRzTD3QiJv31/snLCtnWhllMIzOOi8cDl4Xk4O0qb+Qr/8SHIHVOCVddPtu4CImH1OSLx35r5UVlEVur+g== dependencies: - "@slickgrid-universal/common" "~3.6.0" + "@slickgrid-universal/common" "~3.7.0" dompurify "^3.0.6" -"@slickgrid-universal/empty-warning-component@~3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/empty-warning-component/-/empty-warning-component-3.6.0.tgz#76e94056f23ed019a31f8e437919a26e28570480" - integrity sha512-JXS4bdYPMBWfONWCLCr9D7iALLV1i3jhNh33aGt9FL7eqzaov5hVsACnj9OCaYqvxcKC6aqH0TbNWaXb9OpO2w== +"@slickgrid-universal/empty-warning-component@~3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/empty-warning-component/-/empty-warning-component-3.7.0.tgz#baac3b04fc9b9c39759cb19962f4432be990001b" + integrity sha512-3Nto7+MdRrxHoqI9wfAq2XKMYIj69oyVsVdMEiXEuGh/CSjKwlAMXKyg9/stM090ps+97xQ/01g20m5v1aS3xw== dependencies: - "@slickgrid-universal/common" "~3.6.0" + "@slickgrid-universal/common" "~3.7.0" -"@slickgrid-universal/event-pub-sub@~3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/event-pub-sub/-/event-pub-sub-3.6.0.tgz#98f99120d07ac9f1586190b71789c21d4056c46e" - integrity sha512-d0w+yh96nKT6mCQClGXlWA8rnQhfyNyALg6c8wKgMyO4qtKs9nwuNu23MeBzFhjVHwJjFg/ALc1gAlw6sH8L1w== +"@slickgrid-universal/event-pub-sub@~3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/event-pub-sub/-/event-pub-sub-3.7.0.tgz#3bbae10ecf8a58c0b2e61cc219ca775179a8f6f8" + integrity sha512-Ojm7A2PpshrCw2hZx1FLHFuFSr33H/z8yiR4pl8Z1YpsgGlf9xYXkn6Z3P1g8/tHi7vk0P4qd8x62Wa2tkOyAg== dependencies: - "@slickgrid-universal/utils" "~3.6.0" + "@slickgrid-universal/utils" "~3.7.0" -"@slickgrid-universal/excel-export@~3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/excel-export/-/excel-export-3.6.0.tgz#75ddc791e408243caafd763f1ae47fea11f0f12f" - integrity sha512-dXpNCUrIfqD1Jmt1d28R+ggRd05FPLJr81INSbLlYkZyaA9QIOYiD2Hpe6dmczimxUd2mFjz3dQOXdZ3ab8hVQ== +"@slickgrid-universal/excel-export@~3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/excel-export/-/excel-export-3.7.0.tgz#f846d1db4a15f00f83f329765fbb496e1e0cc447" + integrity sha512-qpFDfzKuabSB/HoGYIkmf8u5FUfg1Xnq6K4Pz+tobGZ+P4WWtdopdGlCI5bkMrrTIkrO6iLJuVxqLA3Mh/z8OA== dependencies: - "@slickgrid-universal/common" "~3.6.0" - "@slickgrid-universal/utils" "~3.6.0" + "@slickgrid-universal/common" "~3.7.0" + "@slickgrid-universal/utils" "~3.7.0" excel-builder-webpacker "^2.1.8" moment-mini "^2.29.4" -"@slickgrid-universal/graphql@~3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/graphql/-/graphql-3.6.0.tgz#13674b0918c1714a85e24c7477509fcb448010a6" - integrity sha512-NJoV5YM5eGFg1t2IohN8ZWc0yZUyYGVGTSVU7Eyaj57G7eY/xwwUHfpynZkmpk4MNDWv61bs5Rn0oegOpNAxsw== +"@slickgrid-universal/graphql@~3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/graphql/-/graphql-3.7.0.tgz#cb112c4984c5c2656665d86eb98e40c4e60e81df" + integrity sha512-UszIoxOBjD3w7EkdK13Gn1etoXq6V9gUEb2JNHiqMTVoDe77US4qQAKLdCPshJjNCfASqcGxcxqTrCq27ScWdQ== dependencies: - "@slickgrid-universal/common" "~3.6.0" + "@slickgrid-universal/common" "~3.7.0" -"@slickgrid-universal/odata@~3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/odata/-/odata-3.6.0.tgz#95cbc3a598c3ab716012a701278a6873ba4965f1" - integrity sha512-mHhe8EifBsrofJ70InefLToWNKHDnx4xjTJFem/jUk+/ZGuJXzRktyOyeoZfWBnFHVknKPOl4fn2q/r0ALuGWw== +"@slickgrid-universal/odata@~3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/odata/-/odata-3.7.0.tgz#9ec7028ff94e0ec5cc7d9f95d4174bf3f034aeda" + integrity sha512-anOpW1qKW9J7peBAEgS6tSpB/UIkv9w+tJAn+tWCQGVEFyxt/VS8n/LuOkwmYxAWJcZAtyS5WJ1ff5QzWRHVJA== dependencies: - "@slickgrid-universal/common" "~3.6.0" - "@slickgrid-universal/utils" "~3.6.0" + "@slickgrid-universal/common" "~3.7.0" + "@slickgrid-universal/utils" "~3.7.0" -"@slickgrid-universal/pagination-component@~3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/pagination-component/-/pagination-component-3.6.0.tgz#05ab3d70e6522273cbc02f523f648662e2fec35c" - integrity sha512-jTQTf7rWw++JopPJIISuBD048pEe5DIgLoDGqCbZ681WreAjOW1lBU3oCXX3UWpLoJGiy0L0123nOcZ2lgAkaQ== +"@slickgrid-universal/pagination-component@~3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/pagination-component/-/pagination-component-3.7.0.tgz#2f43e9d7f55b4164360b57ae6d909975d9c1a6db" + integrity sha512-IjmUkvVTh6LLOeJZ9p3tnbhXbELQgasnloOnsda7uRL9KWHn4c21Ij0o9pSFlbZnqdoWtq7tfKJFIhOVEM+RsQ== dependencies: - "@slickgrid-universal/binding" "~3.6.0" - "@slickgrid-universal/common" "~3.6.0" + "@slickgrid-universal/binding" "~3.7.0" + "@slickgrid-universal/common" "~3.7.0" -"@slickgrid-universal/row-detail-view-plugin@~3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/row-detail-view-plugin/-/row-detail-view-plugin-3.6.0.tgz#d7ea372c471c9e455f35f75ca3a3f08e4f805ea6" - integrity sha512-pgZLidsd6pvbUoMz1bzx+upAYn82Au0EnKCWqRlWTuSt0fxYrP1d3qxc2Xs9jYX/ix7p4yJpNC+O9D+8Jn5s2A== +"@slickgrid-universal/row-detail-view-plugin@~3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/row-detail-view-plugin/-/row-detail-view-plugin-3.7.0.tgz#372e5ea5e53b027b81ca3281b0292dc1ec2c322f" + integrity sha512-XE5WKUy0qZiE717v/NzK0cfb/AFL2SIHULcUyLMmHytKiU+L6eSFd5wuU6UkNFMtHUqSyYK3gGvPm8ovoW6sKA== dependencies: - "@slickgrid-universal/common" "~3.6.0" - "@slickgrid-universal/utils" "~3.6.0" + "@slickgrid-universal/common" "~3.7.0" + "@slickgrid-universal/utils" "~3.7.0" -"@slickgrid-universal/rxjs-observable@~3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/rxjs-observable/-/rxjs-observable-3.6.0.tgz#53eca5be430a4e5c63099b60fc1963a07b2ea736" - integrity sha512-2TeySsVnCo1v7efcanncuVnnMfYFaBJPpy+ltsQItquidURBTcs/ggrdqH2tKg8rFL04oHC4BgXIPQ7Sglal3A== +"@slickgrid-universal/rxjs-observable@~3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/rxjs-observable/-/rxjs-observable-3.7.0.tgz#22db7f729e061d66a090879ed002ef6a70fa97df" + integrity sha512-mt0Z+PfIeW3ncbNA2Kn4x92VJLluHrqQYUTRz8XyM+qkRCRiEygMu+ZxVHMboaQxCOIStoQZi4b5/pXkSOVsxg== dependencies: - "@slickgrid-universal/common" "~3.6.0" + "@slickgrid-universal/common" "~3.7.0" rxjs "^7.8.1" -"@slickgrid-universal/text-export@~3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/text-export/-/text-export-3.6.0.tgz#218aed5439e0e1a58fb0987768868c22754527b5" - integrity sha512-UPVuJL7fymIrt3eUK9p/AKemQbz3GYoS5cpq8oQsSTMTY1ueycb2VhQ44pgFvCz+nsvbiqf/GAGq/+gQBp3LpA== +"@slickgrid-universal/text-export@~3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/text-export/-/text-export-3.7.0.tgz#d2930df0fbd16865a0619c070042015855d00c92" + integrity sha512-X7Oy5V7mFym6/Fs7vY/kssMRPU0JxkGmWbZhZ4XoqTrz9ZynioUIN/iICypIBwTjlk5Psvq5Yt5dBu5eO2rB0Q== dependencies: - "@slickgrid-universal/common" "~3.6.0" - "@slickgrid-universal/utils" "~3.6.0" + "@slickgrid-universal/common" "~3.7.0" + "@slickgrid-universal/utils" "~3.7.0" text-encoding-utf-8 "^1.0.2" -"@slickgrid-universal/utils@~3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/utils/-/utils-3.6.0.tgz#c586a5c150d687a749f419cb58f62fab5263495b" - integrity sha512-QGc6d+YpKv3tyig+asCObQteUBwBXUPiTp3p7J/cHBfgapzV78WL2olJPK1vJjoXYBvzdY9HERR6wh0jsXaX5w== +"@slickgrid-universal/utils@~3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/utils/-/utils-3.7.0.tgz#0aad56219c4118eae3990a26c4d9fb2a93bcd5ee" + integrity sha512-Hy04lEr4p1HU3ew0OLgJElrCX5gC9nGbnglrXDsQUtJuB7l3pUZ52OEK7pVX8i9UZn5brVWcjw5kRRq8qeWaUw== "@szmarczak/http-timer@^5.0.1": version "5.0.1" @@ -3374,10 +3374,10 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^29.5.10": - version "29.5.10" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.10.tgz#a10fc5bab9e426081c12b2ef73d24d4f0c9b7f50" - integrity sha512-tE4yxKEphEyxj9s4inideLHktW/x6DwesIwWZ9NN1FKf9zbJYsnhBoA9vrHA/IuIOKwPa5PcFBNV4lpMIOEzyQ== +"@types/jest@^29.5.11": + version "29.5.11" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.11.tgz#0c13aa0da7d0929f078ab080ae5d4ced80fa2f2c" + integrity sha512-S2mHmYIVe13vrm6q4kN6fLYYAka15ALQki/vgDC3mIukEOx8WJlv0kQPM+d4w8Gp6u0uSdKND04IlTXBv0rwnQ== dependencies: expect "^29.0.0" pretty-format "^29.0.0" @@ -3423,10 +3423,10 @@ dependencies: undici-types "~5.26.4" -"@types/node@^20.10.0": - version "20.10.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.0.tgz#16ddf9c0a72b832ec4fcce35b8249cf149214617" - integrity sha512-D0WfRmU9TQ8I9PFx9Yc+EBHw+vSpIub4IDvQivcp26PtPrdMGAq5SDcpXEo/epqa/DXotVpekHiLNTg3iaKXBQ== +"@types/node@^20.10.4": + version "20.10.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.4.tgz#b246fd84d55d5b1b71bf51f964bd514409347198" + integrity sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg== dependencies: undici-types "~5.26.4" @@ -3551,16 +3551,16 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@^6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.12.0.tgz#2a647d278bb48bf397fef07ba0507612ff9dd812" - integrity sha512-XOpZ3IyJUIV1b15M7HVOpgQxPPF7lGXgsfcEIu3yDxFPaf/xZKt7s9QO/pbk7vpWQyVulpJbu4E5LwpZiQo4kA== +"@typescript-eslint/eslint-plugin@^6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.2.tgz#2e03506c5362a65e43cb132c37c9ce2d3cb51470" + integrity sha512-3+9OGAWHhk4O1LlcwLBONbdXsAhLjyCFogJY/cWy2lxdVJ2JrcTF2pTGMaLl2AE7U1l31n8Py4a8bx5DLf/0dQ== dependencies: "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.12.0" - "@typescript-eslint/type-utils" "6.12.0" - "@typescript-eslint/utils" "6.12.0" - "@typescript-eslint/visitor-keys" "6.12.0" + "@typescript-eslint/scope-manager" "6.13.2" + "@typescript-eslint/type-utils" "6.13.2" + "@typescript-eslint/utils" "6.13.2" + "@typescript-eslint/visitor-keys" "6.13.2" debug "^4.3.4" graphemer "^1.4.0" ignore "^5.2.4" @@ -3568,15 +3568,15 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/parser@^6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.12.0.tgz#9fb21ed7d88065a4a2ee21eb80b8578debb8217c" - integrity sha512-s8/jNFPKPNRmXEnNXfuo1gemBdVmpQsK1pcu+QIvuNJuhFzGrpD7WjOcvDc/+uEdfzSYpNu7U/+MmbScjoQ6vg== +"@typescript-eslint/parser@^6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.13.2.tgz#390b79cc9a57a5f904d197a201cc4b6bc4f9afb9" + integrity sha512-MUkcC+7Wt/QOGeVlM8aGGJZy1XV5YKjTpq9jK6r6/iLsGXhBVaGP5N0UYvFsu9BFlSpwY9kMretzdBH01rkRXg== dependencies: - "@typescript-eslint/scope-manager" "6.12.0" - "@typescript-eslint/types" "6.12.0" - "@typescript-eslint/typescript-estree" "6.12.0" - "@typescript-eslint/visitor-keys" "6.12.0" + "@typescript-eslint/scope-manager" "6.13.2" + "@typescript-eslint/types" "6.13.2" + "@typescript-eslint/typescript-estree" "6.13.2" + "@typescript-eslint/visitor-keys" "6.13.2" debug "^4.3.4" "@typescript-eslint/scope-manager@5.62.0": @@ -3587,13 +3587,13 @@ "@typescript-eslint/types" "5.62.0" "@typescript-eslint/visitor-keys" "5.62.0" -"@typescript-eslint/scope-manager@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.12.0.tgz#5833a16dbe19cfbad639d4d33bcca5e755c7044b" - integrity sha512-5gUvjg+XdSj8pcetdL9eXJzQNTl3RD7LgUiYTl8Aabdi8hFkaGSYnaS6BLc0BGNaDH+tVzVwmKtWvu0jLgWVbw== +"@typescript-eslint/scope-manager@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.13.2.tgz#5fa4e4adace028dafac212c770640b94e7b61052" + integrity sha512-CXQA0xo7z6x13FeDYCgBkjWzNqzBn8RXaE3QVQVIUm74fWJLkJkaHmHdKStrxQllGh6Q4eUGyNpMe0b1hMkXFA== dependencies: - "@typescript-eslint/types" "6.12.0" - "@typescript-eslint/visitor-keys" "6.12.0" + "@typescript-eslint/types" "6.13.2" + "@typescript-eslint/visitor-keys" "6.13.2" "@typescript-eslint/type-utils@5.62.0": version "5.62.0" @@ -3605,13 +3605,13 @@ debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/type-utils@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.12.0.tgz#968f7c95162808d69950ab5dff710ad730e58287" - integrity sha512-WWmRXxhm1X8Wlquj+MhsAG4dU/Blvf1xDgGaYCzfvStP2NwPQh6KBvCDbiOEvaE0filhranjIlK/2fSTVwtBng== +"@typescript-eslint/type-utils@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.13.2.tgz#ebec2da14a6bb7122e0fd31eea72a382c39c6102" + integrity sha512-Qr6ssS1GFongzH2qfnWKkAQmMUyZSyOr0W54nZNU1MDfo+U4Mv3XveeLZzadc/yq8iYhQZHYT+eoXJqnACM1tw== dependencies: - "@typescript-eslint/typescript-estree" "6.12.0" - "@typescript-eslint/utils" "6.12.0" + "@typescript-eslint/typescript-estree" "6.13.2" + "@typescript-eslint/utils" "6.13.2" debug "^4.3.4" ts-api-utils "^1.0.1" @@ -3620,10 +3620,10 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== -"@typescript-eslint/types@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.12.0.tgz#ffc5297bcfe77003c8b7b545b51c2505748314ac" - integrity sha512-MA16p/+WxM5JG/F3RTpRIcuOghWO30//VEOvzubM8zuOOBYXsP+IfjoCXXiIfy2Ta8FRh9+IO9QLlaFQUU+10Q== +"@typescript-eslint/types@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.13.2.tgz#c044aac24c2f6cefb8e921e397acad5417dd0ae6" + integrity sha512-7sxbQ+EMRubQc3wTfTsycgYpSujyVbI1xw+3UMRUcrhSy+pN09y/lWzeKDbvhoqcRbHdc+APLs/PWYi/cisLPg== "@typescript-eslint/typescript-estree@5.62.0": version "5.62.0" @@ -3638,13 +3638,13 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.12.0.tgz#764ccc32598549e5b48ec99e3b85f89b1385310c" - integrity sha512-vw9E2P9+3UUWzhgjyyVczLWxZ3GuQNT7QpnIY3o5OMeLO/c8oHljGc8ZpryBMIyympiAAaKgw9e5Hl9dCWFOYw== +"@typescript-eslint/typescript-estree@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.2.tgz#ae556ee154c1acf025b48d37c3ef95a1d55da258" + integrity sha512-SuD8YLQv6WHnOEtKv8D6HZUzOub855cfPnPMKvdM/Bh1plv1f7Q/0iFUDLKKlxHcEstQnaUU4QZskgQq74t+3w== dependencies: - "@typescript-eslint/types" "6.12.0" - "@typescript-eslint/visitor-keys" "6.12.0" + "@typescript-eslint/types" "6.13.2" + "@typescript-eslint/visitor-keys" "6.13.2" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" @@ -3665,17 +3665,17 @@ eslint-scope "^5.1.1" semver "^7.3.7" -"@typescript-eslint/utils@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.12.0.tgz#c6ce8c06fe9b0212620e5674a2036f6f8f611754" - integrity sha512-LywPm8h3tGEbgfyjYnu3dauZ0U7R60m+miXgKcZS8c7QALO9uWJdvNoP+duKTk2XMWc7/Q3d/QiCuLN9X6SWyQ== +"@typescript-eslint/utils@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.13.2.tgz#8eb89e53adc6d703a879b131e528807245486f89" + integrity sha512-b9Ptq4eAZUym4idijCRzl61oPCwwREcfDI8xGk751Vhzig5fFZR9CyzDz4Sp/nxSLBYxUPyh4QdIDqWykFhNmQ== dependencies: "@eslint-community/eslint-utils" "^4.4.0" "@types/json-schema" "^7.0.12" "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.12.0" - "@typescript-eslint/types" "6.12.0" - "@typescript-eslint/typescript-estree" "6.12.0" + "@typescript-eslint/scope-manager" "6.13.2" + "@typescript-eslint/types" "6.13.2" + "@typescript-eslint/typescript-estree" "6.13.2" semver "^7.5.4" "@typescript-eslint/visitor-keys@5.62.0": @@ -3686,12 +3686,12 @@ "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" -"@typescript-eslint/visitor-keys@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.12.0.tgz#5877950de42a0f3344261b7a1eee15417306d7e9" - integrity sha512-rg3BizTZHF1k3ipn8gfrzDXXSFKyOEB5zxYXInQ6z0hUvmQlhaZQzK+YmHmNViMA9HzW5Q9+bPPt90bU6GQwyw== +"@typescript-eslint/visitor-keys@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.2.tgz#e0a4a80cf842bb08e6127b903284166ac4a5594c" + integrity sha512-OGznFs0eAQXJsp+xSd6k/O1UbFi/K/L7WjqeRoFE7vadjAF9y0uppXhYNQNEqygjou782maGClOoZwPqF0Drlw== dependencies: - "@typescript-eslint/types" "6.12.0" + "@typescript-eslint/types" "6.13.2" eslint-visitor-keys "^3.4.1" "@ungap/structured-clone@^1.2.0": @@ -5418,10 +5418,10 @@ custom-event-polyfill@^1.0.7: resolved "https://registry.yarnpkg.com/custom-event-polyfill/-/custom-event-polyfill-1.0.7.tgz#9bc993ddda937c1a30ccd335614c6c58c4f87aee" integrity sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w== -cypress@^13.6.0: - version "13.6.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.6.0.tgz#b98b7b837679012ed09c7ecee5565bf7b31d4982" - integrity sha512-quIsnFmtj4dBUEJYU4OH0H12bABJpSujvWexC24Ju1gTlKMJbeT6tTO0vh7WNfiBPPjoIXLN+OUqVtiKFs6SGw== +cypress@^13.6.1: + version "13.6.1" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.6.1.tgz#c5f714f08551666ed3ac1fa95718eabb23a416df" + integrity sha512-k1Wl5PQcA/4UoTffYKKaxA0FJKwg8yenYNYRzLt11CUR0Kln+h7Udne6mdU1cUIdXBDTVZWtmiUjzqGs7/pEpw== dependencies: "@cypress/request" "^3.0.0" "@cypress/xvfb" "^1.2.4" @@ -6280,15 +6280,15 @@ eslint-visitor-keys@^3.4.3: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@^8.54.0: - version "8.54.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.54.0.tgz#588e0dd4388af91a2e8fa37ea64924074c783537" - integrity sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA== +eslint@^8.55.0: + version "8.55.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.55.0.tgz#078cb7b847d66f2c254ea1794fa395bf8e7e03f8" + integrity sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.3" - "@eslint/js" "8.54.0" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.55.0" "@humanwhocodes/config-array" "^0.11.13" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" @@ -11409,10 +11409,10 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -slickgrid@^4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/slickgrid/-/slickgrid-4.1.5.tgz#224cbe6bcc93c78d8b55fe09cab6432d5e72016e" - integrity sha512-riHpgidZ2qOinsthGCewFhAYbo7LX/rpXd9B6rGWaVqap1sbL8viGbe8ZCXu2SZvwaGC+LqkGisW77UzMOLoVg== +slickgrid@^4.1.7: + version "4.1.7" + resolved "https://registry.yarnpkg.com/slickgrid/-/slickgrid-4.1.7.tgz#743149e1cefcdb0cd6fba61e3fc7e31b3193dba8" + integrity sha512-dWaJjOlOdBXjQN/ivwzTGlF+Xx3ktKNK+CxejnsMXUybgUj32vqAjwezeTYkiDZDr5K0MMPMXvNysfIhjn79KA== dependencies: sortablejs "^1.15.0" @@ -11461,6 +11461,11 @@ sortablejs@^1.15.0: resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.15.0.tgz#53230b8aa3502bb77a29e2005808ffdb4a5f7e2a" integrity sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w== +sortablejs@^1.15.1: + version "1.15.1" + resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.15.1.tgz#9a35f52cdff449fb42ea8ecf222f3468d76e0a47" + integrity sha512-P5Cjvb0UG1ZVNiDPj/n4V+DinttXG6K8n7vM/HQf0C25K3YKQTQY6fsr/sEGsJGpQ9exmPxluHxKBc0mLKU1lQ== + "source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"