diff --git a/demo-shell/src/app/components/datatable/datatable.component.ts b/demo-shell/src/app/components/datatable/datatable.component.ts index f92350a493..b57448cb98 100644 --- a/demo-shell/src/app/components/datatable/datatable.component.ts +++ b/demo-shell/src/app/components/datatable/datatable.component.ts @@ -227,13 +227,13 @@ export class DataTableComponent { ], [ { type: 'image', key: 'icon', title: '', srTitle: 'Thumbnail' }, - { type: 'text', key: 'id', title: 'Id', sortable: true , cssClass: '' }, - { type: 'date', key: 'createdOn', title: 'Created On', sortable: true, cssClass: 'adf-ellipsis-cell adf-expand-cell-2' }, - { type: 'text', key: 'name', title: 'Name', cssClass: 'adf-ellipsis-cell', sortable: true }, - { type: 'text', key: 'createdBy.name', title: 'Created By', sortable: true, cssClass: ''}, - { type: 'json', key: 'json', title: 'Json', cssClass: 'adf-expand-cell-2'}, - { type: 'text', key: 'users', title: 'Users', cssClass: 'adf-expand-cell-2'}, - { type: 'json', key: 'status', title: 'Status', cssClass: 'adf-expand-cell-2'} + { type: 'text', key: 'id', title: 'Id', sortable: true , cssClass: '', draggable: true}, + { type: 'date', key: 'createdOn', title: 'Created On', sortable: true, cssClass: 'adf-ellipsis-cell adf-expand-cell-2', draggable: true }, + { type: 'text', key: 'name', title: 'Name', cssClass: 'adf-ellipsis-cell', sortable: true, draggable: true }, + { type: 'text', key: 'createdBy.name', title: 'Created By', sortable: true, cssClass: '', draggable: true}, + { type: 'json', key: 'json', title: 'Json', cssClass: 'adf-expand-cell-2', draggable: true}, + { type: 'text', key: 'users', title: 'Users', cssClass: 'adf-expand-cell-2', draggable: true}, + { type: 'json', key: 'status', title: 'Status', cssClass: 'adf-expand-cell-2', draggable: true} ] ); diff --git a/docs/core/components/data-column.component.md b/docs/core/components/data-column.component.md index 785ecb7c61..b0259688b0 100644 --- a/docs/core/components/data-column.component.md +++ b/docs/core/components/data-column.component.md @@ -43,6 +43,7 @@ Defines column properties for DataTable, Tasklist, Document List and other compo | Name | Type | Default value | Description | | ---- | ---- | ------------- | ----------- | +| id | `string` | '' | Column identifier. | | copyContent | `boolean` | | Enables/disables a [Clipboard directive](../../core/directives/clipboard.directive.md) to allow copying of cell contents. | | cssClass | `string` | | Additional CSS class to be applied to column (header and cells). | | editable | `boolean` | false | Toggles the editing support of the column data. | @@ -51,6 +52,7 @@ Defines column properties for DataTable, Tasklist, Document List and other compo | formatTooltip | `Function` | | Custom tooltip formatter function. | | key | `string` | | Data source key. Can be either a column/property key like `title` or a property path like `createdBy.name`. | | sortable | `boolean` | true | Toggles ability to sort by this column, for example by clicking the column header. | +| draggable | `boolean` | false | Toggles drag and drop for header column. | | sortingKey | `string` | | When using server side sorting the column used by the api call where the sorting will be performed | | srTitle | `string` | | Title to be used for screen readers. | | title | `string` | "" | Display title of the column, typically used for column headers. You can use the i18n resource key to get it translated automatically. | diff --git a/e2e/core/pages/content-services.page.ts b/e2e/core/pages/content-services.page.ts index dd6eb68047..c9fd712605 100644 --- a/e2e/core/pages/content-services.page.ts +++ b/e2e/core/pages/content-services.page.ts @@ -63,10 +63,10 @@ export class ContentServicesPage { errorSnackBar = $('simple-snack-bar[class*="mat-simple-snackbar"]'); emptyPagination = $('adf-pagination[class*="adf-pagination__empty"]'); dragAndDrop = $$('adf-upload-drag-area div').first(); - nameHeader = $$('div[data-automation-id="auto_id_name"] > span').first(); - sizeHeader = $$('div[data-automation-id="auto_id_content.sizeInBytes"] > span').first(); - createdByHeader = $$('div[data-automation-id="auto_id_createdByUser.displayName"] > span').first(); - createdHeader = $$('div[data-automation-id="auto_id_createdAt"] > span').first(); + nameHeader = $$('div[data-automation-id="auto_header_content_id_name"] > span').first(); + sizeHeader = $$('div[data-automation-id="auto_header_content_id_content.sizeInBytes"] > span').first(); + createdByHeader = $$('div[data-automation-id="auto_header_content_id_createdByUser.displayName"] > span').first(); + createdHeader = $$('div[data-automation-id="auto_header_content_id_createdAt"] > span').first(); recentFiles = $('.app-container-recent'); recentFilesExpanded = $('.app-container-recent mat-expansion-panel-header.mat-expanded'); recentFilesClosed = $('.app-container-recent mat-expansion-panel-header'); diff --git a/lib/content-services/src/lib/document-list/components/document-list.component.spec.ts b/lib/content-services/src/lib/document-list/components/document-list.component.spec.ts index dfc25ddbf9..a7fb1b0982 100644 --- a/lib/content-services/src/lib/document-list/components/document-list.component.spec.ts +++ b/lib/content-services/src/lib/document-list/components/document-list.component.spec.ts @@ -59,6 +59,8 @@ import { DocumentListModule } from '../document-list.module'; import { TranslateModule } from '@ngx-translate/core'; import { ShareDataRow } from '../data/share-data-row.model'; import { DocumentLoaderNode } from '../models/document-folder.model'; +import { matIconRegistryMock } from '../../testing/mat-icon-registry-mock'; +import { domSanitizerMock } from '../../testing/dom-sanitizer-mock'; describe('DocumentList', () => { @@ -1139,7 +1141,7 @@ describe('DocumentList', () => { it('should display [empty folder] template ', () => { fixture.detectChanges(); - documentList.dataTable = new DataTableComponent(null, null); + documentList.dataTable = new DataTableComponent(null, null, matIconRegistryMock, domSanitizerMock); expect(documentList.dataTable).toBeDefined(); expect(fixture.debugElement.query(By.css('adf-empty-list'))).not.toBeNull(); }); @@ -1157,7 +1159,7 @@ describe('DocumentList', () => { }); it('should empty folder NOT show the pagination', () => { - documentList.dataTable = new DataTableComponent(null, null); + documentList.dataTable = new DataTableComponent(null, null, matIconRegistryMock, domSanitizerMock); expect(documentList.isEmpty()).toBeTruthy(); expect(element.querySelector('alfresco-pagination')).toBe(null); diff --git a/lib/content-services/src/lib/testing/dom-sanitizer-mock.ts b/lib/content-services/src/lib/testing/dom-sanitizer-mock.ts new file mode 100644 index 0000000000..382b5322f0 --- /dev/null +++ b/lib/content-services/src/lib/testing/dom-sanitizer-mock.ts @@ -0,0 +1,5 @@ +import { DomSanitizer } from '@angular/platform-browser'; + +export const domSanitizerMock = { + bypassSecurityTrustResourceUrl: () => {} +} as any as DomSanitizer; diff --git a/lib/content-services/src/lib/testing/mat-icon-registry-mock.ts b/lib/content-services/src/lib/testing/mat-icon-registry-mock.ts new file mode 100644 index 0000000000..edd316b98b --- /dev/null +++ b/lib/content-services/src/lib/testing/mat-icon-registry-mock.ts @@ -0,0 +1,5 @@ +import { MatIconRegistry } from '@angular/material/icon'; + +export const matIconRegistryMock = { + addSvgIconInNamespace: () => {} +} as any as MatIconRegistry; diff --git a/lib/core/assets/images/drag_indicator_24px.svg b/lib/core/assets/images/drag_indicator_24px.svg new file mode 100644 index 0000000000..b159244a60 --- /dev/null +++ b/lib/core/assets/images/drag_indicator_24px.svg @@ -0,0 +1 @@ + diff --git a/lib/core/data-column/data-column.component.ts b/lib/core/data-column/data-column.component.ts index 3b764815f3..4c9d4c3c26 100644 --- a/lib/core/data-column/data-column.component.ts +++ b/lib/core/data-column/data-column.component.ts @@ -25,6 +25,9 @@ import { Component, ContentChild, Input, OnInit, TemplateRef } from '@angular/co }) export class DataColumnComponent implements OnInit { + @Input() + id: string = ''; + /** Data source key. Can be either a column/property key like `title` * or a property path like `createdBy.name`. */ @@ -45,6 +48,10 @@ export class DataColumnComponent implements OnInit { @Input() sortable: boolean = true; + /* Enable drag and drop for header column */ + @Input() + draggable: boolean = false; + /** Display title of the column, typically used for column headers. You can use the * i18n resource key to get it translated automatically. */ diff --git a/lib/core/datatable/components/datatable/datatable.component.html b/lib/core/datatable/components/datatable/datatable.component.html index fd1d45e650..0e3a02a443 100644 --- a/lib/core/datatable/components/datatable/datatable.component.html +++ b/lib/core/datatable/components/datatable/datatable.component.html @@ -8,21 +8,26 @@ [class.adf-datatable--empty--header-visible]="isEmpty() && isHeaderVisible()">
+
{{ 'ADF-DATATABLE.ACCESSIBILITY.ACTIONS' | translate }}
+
{{ 'ADF-DATATABLE.ACCESSIBILITY.SELECT_ALL' | translate }}
+
- - {{ col.title | translate}} - {{ getSortLiveAnnouncement(col) | translate: { string: col.title | translate } }} + +
+ + + {{col.title | translate}} + + + {{ getSortLiveAnnouncement(col) | translate: { string: col.title | translate } }} + + - + + + +
+ + +
+ + +
+ +
+
{{ 'ADF-DATATABLE.ACCESSIBILITY.ACTIONS' | translate }} @@ -58,7 +108,10 @@
-
+
-
@@ -722,7 +725,7 @@ describe('DataTable', () => { }); it('should initialize default adapter', () => { - const table = new DataTableComponent(null, null); + const table = new DataTableComponent(null, null, matIconRegistryMock, domSanitizerMock); expect(table.data).toBeUndefined(); table.ngOnChanges({ data: new SimpleChange('123', {}, true) }); expect(table.data).toEqual(jasmine.any(ObjectDataTableAdapter)); @@ -1605,3 +1608,115 @@ describe('Accesibility', () => { expect(cell.getAttribute('tabindex')).toBe('0'); }); }); + +describe('Drag&Drop column header', () => { + let fixture: ComponentFixture; + let dataTable: DataTableComponent; + let data: { id: number; name: string }[] = []; + let dataTableSchema: DataColumn[] = []; + + setupTestBed({ + imports: [ + TranslateModule.forRoot(), + CoreTestingModule + ], + declarations: [CustomColumnTemplateComponent], + schemas: [NO_ERRORS_SCHEMA] + }); + + beforeEach(() => { + fixture = TestBed.createComponent(DataTableComponent); + dataTable = fixture.componentInstance; + data = [ + { id: 1, name: 'name1' }, + { id: 2, name: 'name2' } + ]; + + dataTableSchema = [ + new ObjectDataColumn({ key: 'id', title: 'ID', draggable: false }), + new ObjectDataColumn({ key: 'name', title: 'Name', draggable: true }) + ]; + + dataTable.data = new ObjectDataTableAdapter( + [...data], + [...dataTableSchema] + ); + }); + + it('should show/hide drag indicator icon', () => { + fixture.detectChanges(); + + const hedaderColumn = fixture.debugElement.nativeElement.querySelector('[data-automation-id="auto_id_name"]'); + hedaderColumn.dispatchEvent(new MouseEvent('mouseenter')); + fixture.detectChanges(); + + let dragIcon = fixture.debugElement.nativeElement.querySelector('[data-automation-id="adf-datatable-cell-header-drag-icon-name"]'); + let dragIconPlaceholder = fixture.debugElement.nativeElement.querySelector('[data-automation-id="adf-datatable-cell-header-drag-icon-placeholder-name"]'); + expect(dragIcon).toBeTruthy(); + expect(dragIconPlaceholder).toBeTruthy(); + + hedaderColumn.dispatchEvent(new MouseEvent('mouseleave')); + fixture.detectChanges(); + + dragIcon = fixture.debugElement.nativeElement.querySelector('[data-automation-id="adf-datatable-cell-header-drag-icon-name"]'); + dragIconPlaceholder = fixture.debugElement.nativeElement.querySelector('[data-automation-id="adf-datatable-cell-header-drag-icon-placeholder-name"]'); + expect(dragIcon).toBeFalsy(); + expect(dragIconPlaceholder).toBeFalsy(); + }); + + it('should not show drag indicator icon, when drag and drop is disabled', () => { + fixture.detectChanges(); + + const hedaderColumn = fixture.debugElement.nativeElement.querySelector('[data-automation-id="auto_id_id"]'); + hedaderColumn.dispatchEvent(new MouseEvent('mouseenter')); + fixture.detectChanges(); + + const dragIcon = fixture.debugElement.nativeElement.querySelector('[data-automation-id="adf-datatable-cell-header-drag-icon-id"]'); + const dragIconPlaceholder = fixture.debugElement.nativeElement.querySelector('[data-automation-id="adf-datatable-cell-header-drag-icon-placeholder-id"]'); + + expect(dragIcon).toBeFalsy(); + expect(dragIconPlaceholder).toBeFalsy(); + }); + + it('should emit on change column order', () => { + const columnOrderChangedSpy = spyOn(dataTable.columnOrderChanged, 'emit'); + const dropEvent: CdkDragDrop = { + previousIndex: 0, + currentIndex: 1, + item: undefined, + container: undefined, + previousContainer: undefined, + isPointerOverContainer: true, + distance: { x: 0, y: 0 } + }; + + dataTable.onDropHeaderColumn(dropEvent); + + expect(columnOrderChangedSpy).toHaveBeenCalledWith(dataTableSchema.reverse()); + }); + + it('should change columns order', () => { + const dropEvent: CdkDragDrop = { + previousIndex: 0, + currentIndex: 1, + item: undefined, + container: undefined, + previousContainer: undefined, + isPointerOverContainer: true, + distance: { x: 0, y: 0 } + }; + + dataTable.onDropHeaderColumn(dropEvent); + + fixture.detectChanges(); + + const columns = dataTable.data.getColumns(); + const headerCells = fixture.debugElement.nativeElement.querySelectorAll('.adf-datatable-cell--text.adf-datatable-cell-header'); + + expect(columns[0].key).toEqual(dataTableSchema[1].key); + expect(columns[1].key).toEqual(dataTableSchema[0].key); + + expect(headerCells[0].innerText).toBe(dataTableSchema[1].title); + expect(headerCells[1].innerText).toBe(dataTableSchema[0].title); + }); +}); diff --git a/lib/core/datatable/components/datatable/datatable.component.ts b/lib/core/datatable/components/datatable/datatable.component.ts index ecb168e36b..461407709d 100644 --- a/lib/core/datatable/components/datatable/datatable.component.ts +++ b/lib/core/datatable/components/datatable/datatable.component.ts @@ -20,7 +20,7 @@ import { ViewChildren, QueryList, HostListener, AfterContentInit, Component, ContentChild, DoCheck, ElementRef, EventEmitter, Input, - IterableDiffers, OnChanges, Output, SimpleChange, SimpleChanges, TemplateRef, ViewEncapsulation, OnDestroy, AfterViewInit + IterableDiffers, OnChanges, Output, SimpleChange, SimpleChanges, TemplateRef, ViewEncapsulation, OnDestroy, AfterViewInit, OnInit } from '@angular/core'; import { FocusKeyManager } from '@angular/cdk/a11y'; import { MatCheckboxChange } from '@angular/material/checkbox'; @@ -40,6 +40,9 @@ import { ObjectDataTableAdapter } from '../../data/object-datatable-adapter'; import { DataCellEvent } from '../data-cell.event'; import { DataRowActionEvent } from '../data-row-action.event'; import { share, buffer, map, filter, debounceTime } from 'rxjs/operators'; +import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; +import { MatIconRegistry } from '@angular/material/icon'; +import { DomSanitizer } from '@angular/platform-browser'; // eslint-disable-next-line no-shadow export enum DisplayMode { @@ -61,7 +64,7 @@ export enum ShowHeaderMode { encapsulation: ViewEncapsulation.None, host: { class: 'adf-datatable' } }) -export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck, OnDestroy, AfterViewInit { +export class DataTableComponent implements OnInit, AfterContentInit, OnChanges, DoCheck, OnDestroy, AfterViewInit { @ViewChildren(DataTableRowComponent) rowsList: QueryList; @@ -160,6 +163,9 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck, @Output() executeRowAction = new EventEmitter(); + @Output() + columnOrderChanged = new EventEmitter(); + /** Flag that indicates if the datatable is in loading state and needs to show the * loading template (see the docs to learn how to configure a loading template). */ @@ -199,6 +205,9 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck, isSelectAllChecked: boolean = false; selection = new Array(); + isDraggingHeaderColumn = false; + hoveredHeaderColumnIndex = -1; + /** This array of fake rows fix the flex layout for the gallery view */ fakeRows = []; @@ -220,14 +229,21 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck, } constructor(private elementRef: ElementRef, - differs: IterableDiffers) { + differs: IterableDiffers, + private matIconRegistry: MatIconRegistry, + private sanitizer: DomSanitizer) { if (differs) { this.differ = differs.find([]).create(null); } + this.click$ = new Observable((observer) => this.clickObserver = observer) .pipe(share()); } + ngOnInit(): void { + this.registerDragHandleIcon(); + } + ngAfterContentInit() { if (this.columnList) { this.subscriptions.push( @@ -260,13 +276,18 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck, if (dataChanges) { this.data = changes['data'].currentValue; this.resetSelection(); - } else if (rowChanges) { + } + + if (rowChanges) { this.setTableRows(changes['rows'].currentValue); this.setTableSorting(this.sorting); - } else { + } + + if (columnChanges) { this.setTableColumns(changes['columns'].currentValue); } } + return; } @@ -291,6 +312,14 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck, return column.key === this.data.getSorting().key; } + onDropHeaderColumn(event: CdkDragDrop): void { + const columns = this.data.getColumns(); + moveItemInArray(columns, event.previousIndex, event.currentIndex); + + this.columnOrderChanged.emit(columns); + this.isDraggingHeaderColumn = false; + } + ngDoCheck() { const changes = this.differ.diff(this.rows); if (changes) { @@ -849,6 +878,18 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck, 'ADF-DATATABLE.ACCESSIBILITY.SORT_ASCENDING_BY' : 'ADF-DATATABLE.ACCESSIBILITY.SORT_DESCENDING_BY'; } + + private registerDragHandleIcon(): void { + const iconUrl = this.sanitizer.bypassSecurityTrustResourceUrl( + './assets/images/drag_indicator_24px.svg' + ); + + this.matIconRegistry.addSvgIconInNamespace( + 'adf', + 'drag_indicator', + iconUrl + ); + } } export interface DataTableDropEvent { diff --git a/lib/core/datatable/data/data-column.model.ts b/lib/core/datatable/data/data-column.model.ts index 995dfc574b..3eff6ed68a 100644 --- a/lib/core/datatable/data/data-column.model.ts +++ b/lib/core/datatable/data/data-column.model.ts @@ -30,6 +30,7 @@ export interface DataColumnTypes { export type DataColumnType = keyof DataColumnTypes; export interface DataColumn { + id?: string; key: string; type: DataColumnType; format?: string; @@ -44,4 +45,5 @@ export interface DataColumn { focus?: boolean; sortingKey?: string; header?: TemplateRef; + draggable?: boolean; } diff --git a/lib/core/datatable/data/data-table.schema.ts b/lib/core/datatable/data/data-table.schema.ts index 8abbc6858b..7a5d4d1ca0 100644 --- a/lib/core/datatable/data/data-table.schema.ts +++ b/lib/core/datatable/data/data-table.schema.ts @@ -16,6 +16,7 @@ */ import { ContentChild, Input, Directive } from '@angular/core'; +import { ReplaySubject } from 'rxjs'; import { AppConfigService } from '../../app-config/app-config.service'; import { DataColumnListComponent } from '../../data-column/data-column-list.component'; import { DataColumn } from './data-column.model'; @@ -34,19 +35,34 @@ export abstract class DataTableSchema { columns: any; + protected columnsOrder: string[] | undefined; + protected columnsOrderedByKey: string = 'id'; + private layoutPresets = {}; + private columnsSchemaSubject$ = new ReplaySubject(); + isColumnSchemaCreated$ = this.columnsSchemaSubject$.asObservable(); + constructor(private appConfigService: AppConfigService, protected presetKey: string, protected presetsModel: any) { } public createDatatableSchema(): void { this.loadLayoutPresets(); + if (!this.columns || this.columns.length === 0) { - this.columns = this.mergeJsonAndHtmlSchema(); + this.createColumns(); + this.columnsSchemaSubject$.next(true); + } else { + this.columnsSchemaSubject$.next(false); } } + public createColumns(): void { + const columns = this.mergeJsonAndHtmlSchema(); + this.columns = this.sortColumnsByKey(columns); + } + public loadLayoutPresets(): void { const externalSettings = this.appConfigService.get(this.presetKey, null); if (externalSettings) { @@ -57,10 +73,18 @@ export abstract class DataTableSchema { } public mergeJsonAndHtmlSchema(): any { - let customSchemaColumns = this.getSchemaFromConfig(this.presetColumn).concat(this.getSchemaFromHtml(this.columnList)); + const configSchemaColumns = this.getSchemaFromConfig(this.presetColumn); + const htmlSchemaColumns = this.getSchemaFromHtml(this.columnList); + + let customSchemaColumns = [ + ...configSchemaColumns, + ...htmlSchemaColumns + ]; + if (customSchemaColumns.length === 0) { customSchemaColumns = this.getDefaultLayoutPreset(); } + return customSchemaColumns; } @@ -87,4 +111,20 @@ export abstract class DataTableSchema { public setPresetsModel(presetsModel: any) { this.presetsModel = presetsModel; } + + private sortColumnsByKey(columns: any[]): any[] { + const defaultColumns = [...columns]; + const columnsWithProperOrder = []; + + (this.columnsOrder ?? []).forEach(columnKey => { + const originalColumnIndex = defaultColumns.findIndex(defaultColumn => defaultColumn[this.columnsOrderedByKey] === columnKey); + + if (originalColumnIndex > -1) { + columnsWithProperOrder.push(defaultColumns[originalColumnIndex]); + defaultColumns.splice(originalColumnIndex, 1); + } + }); + + return [...columnsWithProperOrder, ...defaultColumns]; + } } diff --git a/lib/core/datatable/data/object-datacolumn.model.ts b/lib/core/datatable/data/object-datacolumn.model.ts index a8fcd4fb46..075c2a3cb1 100644 --- a/lib/core/datatable/data/object-datacolumn.model.ts +++ b/lib/core/datatable/data/object-datacolumn.model.ts @@ -20,7 +20,7 @@ import { DataColumn, DataColumnType } from './data-column.model'; // Simple implementation of the DataColumn interface. export class ObjectDataColumn implements DataColumn { - + id?: string; key: string; type: DataColumnType; format: string; @@ -33,8 +33,10 @@ export class ObjectDataColumn implements DataColumn { focus?: boolean; sortingKey?: string; header?: TemplateRef; + draggable: boolean; constructor(input: any) { + this.id = input.id ?? ''; this.key = input.key; this.type = input.type || 'text'; this.format = input.format; @@ -47,5 +49,6 @@ export class ObjectDataColumn implements DataColumn { this.focus = input.focus; this.sortingKey = input.sortingKey; this.header = input.header; + this.draggable = input.draggable ?? false; } } diff --git a/lib/core/datatable/datatable.module.ts b/lib/core/datatable/datatable.module.ts index b72dcff565..d4a9e2f43a 100644 --- a/lib/core/datatable/datatable.module.ts +++ b/lib/core/datatable/datatable.module.ts @@ -46,6 +46,8 @@ import { JsonCellComponent } from './components/json-cell/json-cell.component'; import { ClipboardModule } from '../clipboard/clipboard.module'; import { DropZoneDirective } from './directives/drop-zone.directive'; import { DataColumnModule } from '../data-column/data-column.module'; +import { DragDropModule } from '@angular/cdk/drag-drop'; +import { IconModule } from '../icon/icon.module'; @NgModule({ imports: [ @@ -57,7 +59,9 @@ import { DataColumnModule } from '../data-column/data-column.module'; ContextMenuModule, PipeModule, DirectiveModule, - ClipboardModule + ClipboardModule, + DragDropModule, + IconModule ], declarations: [ DataTableComponent, @@ -101,6 +105,5 @@ import { DataColumnModule } from '../data-column/data-column.module'; CustomNoPermissionTemplateDirective, DropZoneDirective ] - }) export class DataTableModule {} diff --git a/lib/process-services-cloud/src/lib/process-services-cloud.module.ts b/lib/process-services-cloud/src/lib/process-services-cloud.module.ts index bbb4d3ee27..d970477418 100644 --- a/lib/process-services-cloud/src/lib/process-services-cloud.module.ts +++ b/lib/process-services-cloud/src/lib/process-services-cloud.module.ts @@ -27,7 +27,9 @@ import { LocalPreferenceCloudService, PreferenceCloudServiceInterface, PROCESS_FILTERS_SERVICE_TOKEN, - TASK_FILTERS_SERVICE_TOKEN + TASK_FILTERS_SERVICE_TOKEN, + PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN, + TASK_LIST_PREFERENCES_SERVICE_TOKEN } from './services/public-api'; import { PeopleCloudModule } from './people/people-cloud.module'; import { CloudFormRenderingService } from './form/components/cloud-form-rendering.service'; @@ -67,7 +69,10 @@ import { ProcessServicesCloudPipeModule } from './pipes/process-services-cloud-p ] }) export class ProcessServicesCloudModule { - static forRoot(preferenceServiceInstance?: PreferenceCloudServiceInterface): ModuleWithProviders { + static forRoot( + filterPreferenceServiceInstance?: PreferenceCloudServiceInterface, + listPreferenceServiceInstance?: PreferenceCloudServiceInterface + ): ModuleWithProviders { return { ngModule: ProcessServicesCloudModule, providers: [ @@ -79,8 +84,10 @@ export class ProcessServicesCloudModule { source: 'assets/adf-process-services-cloud' } }, - { provide: PROCESS_FILTERS_SERVICE_TOKEN, useExisting: preferenceServiceInstance ?? LocalPreferenceCloudService }, - { provide: TASK_FILTERS_SERVICE_TOKEN, useExisting: preferenceServiceInstance ?? LocalPreferenceCloudService }, + { provide: PROCESS_FILTERS_SERVICE_TOKEN, useExisting: filterPreferenceServiceInstance ?? LocalPreferenceCloudService }, + { provide: TASK_FILTERS_SERVICE_TOKEN, useExisting: filterPreferenceServiceInstance ?? LocalPreferenceCloudService }, + { provide: PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN, useExisting: listPreferenceServiceInstance ?? LocalPreferenceCloudService }, + { provide: TASK_LIST_PREFERENCES_SERVICE_TOKEN, useExisting: listPreferenceServiceInstance ?? LocalPreferenceCloudService }, FormRenderingService, { provide: FormRenderingService, useClass: CloudFormRenderingService } ] diff --git a/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.html b/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.html index 056ee6148f..9776c10c82 100644 --- a/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.html +++ b/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.html @@ -16,7 +16,8 @@ (row-select)="onRowSelect($any($event))" (row-unselect)="onRowUnselect($any($event))" (row-keyup)="onRowKeyUp($any($event))" - (sorting-changed)="onSortingChanged($any($event))"> + (sorting-changed)="onSortingChanged($any($event))" + (columnOrderChanged)="onColumnOrderChanged($event)"> { } } }); + + component.isColumnSchemaCreated$ = of(true).pipe(shareReplay(1)); }); afterEach(() => fixture.destroy()); diff --git a/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.ts b/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.ts index 0c8fab23cc..341968a057 100644 --- a/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.ts @@ -15,16 +15,20 @@ * limitations under the License. */ -import { Component, ViewEncapsulation, OnChanges, AfterContentInit, ContentChild, Output, EventEmitter, SimpleChanges, Input, ViewChild } from '@angular/core'; +import { Component, ViewEncapsulation, OnChanges, AfterContentInit, ContentChild, Output, EventEmitter, SimpleChanges, Input, ViewChild, Inject } from '@angular/core'; import { DataTableSchema, PaginatedComponent, CustomEmptyContentTemplateDirective, AppConfigService, UserPreferencesService, PaginationModel, - UserPreferenceValues, DataRowEvent, CustomLoadingContentTemplateDirective, DataCellEvent, DataRowActionEvent, DataTableComponent } from '@alfresco/adf-core'; + UserPreferenceValues, DataRowEvent, CustomLoadingContentTemplateDirective, DataCellEvent, DataRowActionEvent, DataTableComponent, DataColumn } from '@alfresco/adf-core'; import { ProcessListCloudService } from '../services/process-list-cloud.service'; -import { BehaviorSubject } from 'rxjs'; +import { BehaviorSubject, combineLatest } from 'rxjs'; import { processCloudPresetsDefaultModel } from '../models/process-cloud-preset.model'; import { ProcessQueryCloudRequestModel } from '../models/process-cloud-query-request.model'; import { ProcessListCloudSortingModel } from '../models/process-list-sorting.model'; +import { map, take } from 'rxjs/operators'; +import { PreferenceCloudServiceInterface } from '../../../services/preference-cloud.interface'; +import { PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN } from '../../../services/cloud-token.service'; +import { ProcessListCloudPreferences } from '../models/process-cloud-preferences'; const PRESET_KEY = 'adf-cloud-process-list.presets'; @@ -189,14 +193,17 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan currentInstanceId: string; selectedInstances: any[]; isLoading = true; + rows: any[] = []; formattedSorting: any[]; requestNode: ProcessQueryCloudRequestModel; + private defaultSorting = { key: 'startDate', direction: 'desc' }; constructor(private processListCloudService: ProcessListCloudService, appConfigService: AppConfigService, - private userPreferences: UserPreferencesService) { + private userPreferences: UserPreferencesService, + @Inject(PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN) private cloudPreferenceService: PreferenceCloudServiceInterface) { super(appConfigService, PRESET_KEY, processCloudPresetsDefaultModel); this.size = userPreferences.paginationSize; this.userPreferences.select(UserPreferenceValues.PaginationSize).subscribe((pageSize) => { @@ -210,7 +217,23 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan } ngAfterContentInit() { - this.createDatatableSchema(); + this.cloudPreferenceService.getPreferences(this.appName) + .pipe( + take(1), + map((preferences => { + const preferencesList = preferences?.list?.entries ?? []; + const columnsOrder = preferencesList.find(preference => preference.entry.key === ProcessListCloudPreferences.columnOrder); + + return { + columnsOrder: columnsOrder ? JSON.parse(columnsOrder.entry.value) : undefined + }; + })) + ) + .subscribe(({ columnsOrder }) => { + this.columnsOrder = columnsOrder; + + this.createDatatableSchema(); + }); } ngOnChanges(changes: SimpleChanges) { @@ -237,16 +260,21 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan private load(requestNode: ProcessQueryCloudRequestModel) { this.isLoading = true; - this.processListCloudService.getProcessByRequest(requestNode).subscribe( - (processes) => { - this.rows = processes.list.entries; - this.success.emit(processes); - this.isLoading = false; - this.pagination.next(processes.list.pagination); - }, (error) => { - this.error.emit(error); - this.isLoading = false; - }); + + combineLatest([ + this.processListCloudService.getProcessByRequest(requestNode), + this.isColumnSchemaCreated$ + ]).pipe( + take(1) + ).subscribe(([processes]) => { + this.rows = processes.list.entries; + this.success.emit(processes); + this.isLoading = false; + this.pagination.next(processes.list.pagination); + }, (error) => { + this.error.emit(error); + this.isLoading = false; + }); } private isAnyPropertyChanged(changes: SimpleChanges): boolean { @@ -297,6 +325,17 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan this.reload(); } + onColumnOrderChanged(columnsWithNewOrder: DataColumn[]): void { + if (this.appName) { + const newColumnsOrder = columnsWithNewOrder.map(column => column.id); + this.cloudPreferenceService.updatePreference( + this.appName, + ProcessListCloudPreferences.columnOrder, + newColumnsOrder + ); + } + } + onRowClick(item: DataRowEvent) { this.currentInstanceId = item.value.getValue('id'); this.rowClick.emit(this.currentInstanceId); diff --git a/lib/process-services-cloud/src/lib/process/process-list/models/process-cloud-preferences.ts b/lib/process-services-cloud/src/lib/process/process-list/models/process-cloud-preferences.ts new file mode 100644 index 0000000000..dd3de35da5 --- /dev/null +++ b/lib/process-services-cloud/src/lib/process/process-list/models/process-cloud-preferences.ts @@ -0,0 +1,4 @@ +// eslint-disable-next-line no-shadow +export enum ProcessListCloudPreferences { + columnOrder = 'processes-cloud-list-columns-order' +} diff --git a/lib/process-services-cloud/src/lib/process/process-list/public-api.ts b/lib/process-services-cloud/src/lib/process/process-list/public-api.ts index 91c4213927..80a37cab4e 100644 --- a/lib/process-services-cloud/src/lib/process/process-list/public-api.ts +++ b/lib/process-services-cloud/src/lib/process/process-list/public-api.ts @@ -20,6 +20,7 @@ export * from './components/process-list-cloud.component'; export * from './models/process-cloud-query-request.model'; export * from './models/process-cloud-preset.model'; export * from './models/process-list-sorting.model'; +export * from './models/process-cloud-preferences'; export * from './services/process-list-cloud.service'; export * from './services/process-task-list-cloud.service'; diff --git a/lib/process-services-cloud/src/lib/services/cloud-token.service.ts b/lib/process-services-cloud/src/lib/services/cloud-token.service.ts index 89e3f4d1c9..086e99099e 100644 --- a/lib/process-services-cloud/src/lib/services/cloud-token.service.ts +++ b/lib/process-services-cloud/src/lib/services/cloud-token.service.ts @@ -19,6 +19,10 @@ import { InjectionToken } from '@angular/core'; import { PreferenceCloudServiceInterface } from './preference-cloud.interface'; import { TaskListCloudServiceInterface } from './task-list-cloud.service.interface'; +export const PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN = new InjectionToken('proccesses-list-preferences-cloud'); + +export const TASK_LIST_PREFERENCES_SERVICE_TOKEN = new InjectionToken('tasks-list-preferences-cloud'); + export const PROCESS_FILTERS_SERVICE_TOKEN = new InjectionToken('proccess-filters-cloud'); export const TASK_FILTERS_SERVICE_TOKEN = new InjectionToken('task-filters-cloud'); diff --git a/lib/process-services-cloud/src/lib/services/preference-cloud.interface.ts b/lib/process-services-cloud/src/lib/services/preference-cloud.interface.ts index c7c567cc06..a5305fbed7 100644 --- a/lib/process-services-cloud/src/lib/services/preference-cloud.interface.ts +++ b/lib/process-services-cloud/src/lib/services/preference-cloud.interface.ts @@ -18,11 +18,9 @@ import { Observable } from 'rxjs'; export interface PreferenceCloudServiceInterface { - getPreferences(appName: string, key?: string): Observable; getPreferenceByKey(appName: string, key: string): Observable; createPreference(appName: string, key: string, newPreference: any): Observable; updatePreference(appName: string, key: string, updatedPreference: any): Observable; - deletePreference(appName: string, key: any): Observable; - + deletePreference(appName: string, key: string): Observable; } diff --git a/lib/process-services-cloud/src/lib/task/task-list/components/base-task-list-cloud.component.html b/lib/process-services-cloud/src/lib/task/task-list/components/base-task-list-cloud.component.html index c7bdf1cae6..d7064950df 100644 --- a/lib/process-services-cloud/src/lib/task/task-list/components/base-task-list-cloud.component.html +++ b/lib/process-services-cloud/src/lib/task/task-list/components/base-task-list-cloud.component.html @@ -19,7 +19,8 @@ (row-unselect)="onRowUnselect($any($event))" (rowClick)="onRowClick($any($event))" (row-keyup)="onRowKeyUp($any($event))" - (sorting-changed)="onSortingChanged($any($event))"> + (sorting-changed)="onSortingChanged($any($event))" + (columnOrderChanged)="onColumnOrderChanged($event)"> diff --git a/lib/process-services-cloud/src/lib/task/task-list/components/base-task-list-cloud.component.ts b/lib/process-services-cloud/src/lib/task/task-list/components/base-task-list-cloud.component.ts index ab3b6da8b7..69cac13d68 100644 --- a/lib/process-services-cloud/src/lib/task/task-list/components/base-task-list-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/task/task-list/components/base-task-list-cloud.component.ts @@ -26,8 +26,10 @@ import { taskPresetsCloudDefaultModel } from '../models/task-preset-cloud.model' import { TaskQueryCloudRequestModel } from '../../../models/filter-cloud-model'; import { BehaviorSubject, Subject } from 'rxjs'; import { TaskListCloudSortingModel } from '../../../models/task-list-sorting.model'; -import { takeUntil } from 'rxjs/operators'; +import { map, take, takeUntil } from 'rxjs/operators'; import { TaskCloudService } from '../../services/task-cloud.service'; +import { PreferenceCloudServiceInterface } from '../../../services/preference-cloud.interface'; +import { TasksListCloudPreferences } from '../models/tasks-cloud-preferences'; @Directive() // eslint-disable-next-line @angular-eslint/directive-class-suffix @@ -120,7 +122,8 @@ export abstract class BaseTaskListCloudComponent extends DataTableSchema impleme constructor(appConfigService: AppConfigService, private taskCloudService: TaskCloudService, private userPreferences: UserPreferencesService, - presetKey: string) { + presetKey: string, + private cloudPreferenceService: PreferenceCloudServiceInterface) { super(appConfigService, presetKey, taskPresetsCloudDefaultModel); this.size = userPreferences.paginationSize; @@ -153,7 +156,18 @@ export abstract class BaseTaskListCloudComponent extends DataTableSchema impleme } ngAfterContentInit() { - this.createDatatableSchema(); + this.cloudPreferenceService.getPreferences(this.appName).pipe( + take(1), + map((preferences => { + const preferencesList = preferences?.list?.entries ?? []; + const searchedPreferences = preferencesList.find(preference => preference.entry.key === TasksListCloudPreferences.columnOrder); + return searchedPreferences ? JSON.parse(searchedPreferences.entry.value) : null; + })) + ).subscribe(columnsOrder => { + this.columnsOrder = columnsOrder; + this.createDatatableSchema(); + } + ); } reload() { @@ -235,6 +249,18 @@ export abstract class BaseTaskListCloudComponent extends DataTableSchema impleme this.executeRowAction.emit(row); } + onColumnOrderChanged(columnsWithNewOrder: DataColumn[]): void { + this.columnsOrder = columnsWithNewOrder.map(column => column.id); + + if (this.appName) { + this.cloudPreferenceService.updatePreference( + this.appName, + TasksListCloudPreferences.columnOrder, + this.columnsOrder + ); + } + } + setSorting(sortDetail) { const sorting = sortDetail ? { orderBy: sortDetail.key, diff --git a/lib/process-services-cloud/src/lib/task/task-list/components/service-task-list-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/task/task-list/components/service-task-list-cloud.component.spec.ts index 5215d77f83..1c4552efa0 100644 --- a/lib/process-services-cloud/src/lib/task/task-list/components/service-task-list-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/task/task-list/components/service-task-list-cloud.component.spec.ts @@ -25,7 +25,7 @@ import { of } from 'rxjs'; import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module'; import { TranslateModule } from '@ngx-translate/core'; import { TaskListCloudSortingModel } from '../../../models/task-list-sorting.model'; -import { skip } from 'rxjs/operators'; +import { shareReplay, skip } from 'rxjs/operators'; import { ServiceTaskListCloudService } from '../services/service-task-list-cloud.service'; @Component({ @@ -111,6 +111,8 @@ describe('ServiceTaskListCloudComponent', () => { } } }); + + component.isColumnSchemaCreated$ = of(true).pipe(shareReplay(1)); }); afterEach(() => { @@ -384,6 +386,8 @@ describe('ServiceTaskListCloudComponent', () => { componentCustom = fixtureCustom.componentInstance; customCopyComponent = copyFixture.componentInstance; element = copyFixture.debugElement.nativeElement; + + customCopyComponent.taskList.isColumnSchemaCreated$ = of(true); }); afterEach(() => { diff --git a/lib/process-services-cloud/src/lib/task/task-list/components/service-task-list-cloud.component.ts b/lib/process-services-cloud/src/lib/task/task-list/components/service-task-list-cloud.component.ts index f14e7c0295..f86781109c 100644 --- a/lib/process-services-cloud/src/lib/task/task-list/components/service-task-list-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/task/task-list/components/service-task-list-cloud.component.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Component, ViewEncapsulation, Input } from '@angular/core'; +import { Component, ViewEncapsulation, Input, Inject } from '@angular/core'; import { AppConfigService, UserPreferencesService } from '@alfresco/adf-core'; @@ -23,6 +23,9 @@ import { ServiceTaskQueryCloudRequestModel } from '../models/service-task-cloud. import { BaseTaskListCloudComponent } from './base-task-list-cloud.component'; import { ServiceTaskListCloudService } from '../services/service-task-list-cloud.service'; import { TaskCloudService } from '../../services/task-cloud.service'; +import { combineLatest } from 'rxjs'; +import { PreferenceCloudServiceInterface, TASK_LIST_PREFERENCES_SERVICE_TOKEN } from '../../../services/public-api'; +import { take } from 'rxjs/operators'; const PRESET_KEY = 'adf-cloud-service-task-list.presets'; @@ -39,14 +42,21 @@ export class ServiceTaskListCloudComponent extends BaseTaskListCloudComponent { constructor(private serviceTaskListCloudService: ServiceTaskListCloudService, appConfigService: AppConfigService, taskCloudService: TaskCloudService, - userPreferences: UserPreferencesService) { - super(appConfigService, taskCloudService, userPreferences, PRESET_KEY); + userPreferences: UserPreferencesService, + @Inject(TASK_LIST_PREFERENCES_SERVICE_TOKEN) cloudPreferenceService: PreferenceCloudServiceInterface) { + super(appConfigService, taskCloudService, userPreferences, PRESET_KEY, cloudPreferenceService); } load(requestNode: ServiceTaskQueryCloudRequestModel) { this.isLoading = true; - this.serviceTaskListCloudService.getServiceTaskByRequest(requestNode).subscribe( - (tasks) => { + + combineLatest([ + this.serviceTaskListCloudService.getServiceTaskByRequest(requestNode), + this.isColumnSchemaCreated$ + ]).pipe( + take(1) + ).subscribe( + ([tasks]) => { this.rows = tasks.list.entries; this.success.emit(tasks); this.isLoading = false; diff --git a/lib/process-services-cloud/src/lib/task/task-list/components/task-list-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/task/task-list/components/task-list-cloud.component.spec.ts index eb04eaafb6..a00fa36077 100644 --- a/lib/process-services-cloud/src/lib/task/task-list/components/task-list-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/task/task-list/components/task-list-cloud.component.spec.ts @@ -26,7 +26,7 @@ import { of } from 'rxjs'; import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module'; import { TranslateModule } from '@ngx-translate/core'; import { TaskListCloudSortingModel } from '../../../models/task-list-sorting.model'; -import { skip } from 'rxjs/operators'; +import { shareReplay, skip } from 'rxjs/operators'; import { TaskListCloudServiceInterface } from '../../../services/task-list-cloud.service.interface'; import { TASK_LIST_CLOUD_TOKEN } from '../../../services/cloud-token.service'; @@ -124,6 +124,8 @@ describe('TaskListCloudComponent', () => { } } }); + + component.isColumnSchemaCreated$ = of(true).pipe(shareReplay(1)); }); afterEach(() => { @@ -419,6 +421,8 @@ describe('TaskListCloudComponent', () => { componentCustom = fixtureCustom.componentInstance; customCopyComponent = copyFixture.componentInstance; element = copyFixture.debugElement.nativeElement; + + customCopyComponent.taskList.isColumnSchemaCreated$ = of(true); }); afterEach(() => { @@ -542,7 +546,9 @@ describe('TaskListCloudComponent', () => { element = fixture.debugElement.nativeElement; taskSpy = spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTask)); + component.isColumnSchemaCreated$ = of(true); }); + afterEach(() => { fixture.destroy(); }); diff --git a/lib/process-services-cloud/src/lib/task/task-list/components/task-list-cloud.component.ts b/lib/process-services-cloud/src/lib/task/task-list/components/task-list-cloud.component.ts index a552fe3edd..828baf5dec 100644 --- a/lib/process-services-cloud/src/lib/task/task-list/components/task-list-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/task/task-list/components/task-list-cloud.component.ts @@ -20,8 +20,11 @@ import { AppConfigService, UserPreferencesService } from '@alfresco/adf-core'; import { TaskQueryCloudRequestModel } from '../../../models/filter-cloud-model'; import { BaseTaskListCloudComponent } from './base-task-list-cloud.component'; import { TaskCloudService } from '../../services/task-cloud.service'; -import { TASK_LIST_CLOUD_TOKEN } from '../../../services/cloud-token.service'; +import { TASK_LIST_CLOUD_TOKEN, TASK_LIST_PREFERENCES_SERVICE_TOKEN } from '../../../services/cloud-token.service'; +import { PreferenceCloudServiceInterface } from '../../../services/preference-cloud.interface'; import { TaskListCloudServiceInterface } from '../../../services/task-list-cloud.service.interface'; +import { combineLatest } from 'rxjs'; +import { take } from 'rxjs/operators'; const PRESET_KEY = 'adf-cloud-task-list.presets'; @@ -135,14 +138,21 @@ export class TaskListCloudComponent extends BaseTaskListCloudComponent { constructor(@Inject(TASK_LIST_CLOUD_TOKEN) public taskListCloudService: TaskListCloudServiceInterface, appConfigService: AppConfigService, taskCloudService: TaskCloudService, - userPreferences: UserPreferencesService) { - super(appConfigService, taskCloudService, userPreferences, PRESET_KEY); + userPreferences: UserPreferencesService, + @Inject(TASK_LIST_PREFERENCES_SERVICE_TOKEN) cloudPreferenceService: PreferenceCloudServiceInterface) { + super(appConfigService, taskCloudService, userPreferences, PRESET_KEY, cloudPreferenceService); } load(requestNode: TaskQueryCloudRequestModel) { this.isLoading = true; - this.taskListCloudService.getTaskByRequest(requestNode).subscribe( - (tasks) => { + + combineLatest([ + this.taskListCloudService.getTaskByRequest(requestNode), + this.isColumnSchemaCreated$ + ]).pipe( + take(1) + ).subscribe( + ([tasks]) => { this.rows = tasks.list.entries; this.success.emit(tasks); this.isLoading = false; diff --git a/lib/process-services-cloud/src/lib/task/task-list/models/tasks-cloud-preferences.ts b/lib/process-services-cloud/src/lib/task/task-list/models/tasks-cloud-preferences.ts new file mode 100644 index 0000000000..1153870ae3 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task/task-list/models/tasks-cloud-preferences.ts @@ -0,0 +1,4 @@ +// eslint-disable-next-line no-shadow +export enum TasksListCloudPreferences { + columnOrder = 'tasks-list-cloud-columns-order' +} diff --git a/lib/process-services-cloud/src/lib/task/task-list/public-api.ts b/lib/process-services-cloud/src/lib/task/task-list/public-api.ts index b984c8ad0f..b77e928299 100644 --- a/lib/process-services-cloud/src/lib/task/task-list/public-api.ts +++ b/lib/process-services-cloud/src/lib/task/task-list/public-api.ts @@ -20,6 +20,7 @@ export * from './components/service-task-list-cloud.component'; export * from './models/service-task-cloud.model'; export * from './models/task-preset-cloud.model'; +export * from './models/tasks-cloud-preferences'; export * from './services/task-list-cloud.service'; export * from './services/service-task-list-cloud.service'; diff --git a/lib/process-services-cloud/src/lib/task/task-list/task-list-cloud.module.ts b/lib/process-services-cloud/src/lib/task/task-list/task-list-cloud.module.ts index cfc8b87aca..ca01f3c3c2 100644 --- a/lib/process-services-cloud/src/lib/task/task-list/task-list-cloud.module.ts +++ b/lib/process-services-cloud/src/lib/task/task-list/task-list-cloud.module.ts @@ -22,7 +22,7 @@ import { TaskListCloudComponent } from './components/task-list-cloud.component'; import { ServiceTaskListCloudComponent } from './components/service-task-list-cloud.component'; import { CoreModule } from '@alfresco/adf-core'; import { TASK_LIST_CLOUD_TOKEN } from '../../services/cloud-token.service'; -import { TaskListCloudService } from './public-api'; +import { TaskListCloudService } from './services/task-list-cloud.service'; @NgModule({ imports: [