mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-09-17 14:21:29 +00:00
[ACS-5566] - Add configurable columns to document list (#8968)
* [ACS-5566] - add configurable columns to document list * [ACS-5566] - add max visible columns * [ACS-5566] - add unit tests * [ACS-5566] - add docs * [ACS-5566] - style changes after CR * [ACS-5566] - changes for pipeline * [ACS-5566] - changes for pipeline * [ACS-5566] - changes for pipeline
This commit is contained in:
@@ -60,6 +60,7 @@ Displays the documents from a repository.
|
|||||||
| ---- | ---- | ------------- | ----------- |
|
| ---- | ---- | ------------- | ----------- |
|
||||||
| additionalSorting | [`DataSorting`](../../../lib/core/src/lib/datatable/data/data-sorting.model.ts) | | Defines default sorting. The format is an array of strings `[key direction, otherKey otherDirection]` i.e. `['name desc', 'nodeType asc']` or `['name asc']`. Set this value if you want a base rule to be added to the sorting apart from the one driven by the header. |
|
| additionalSorting | [`DataSorting`](../../../lib/core/src/lib/datatable/data/data-sorting.model.ts) | | Defines default sorting. The format is an array of strings `[key direction, otherKey otherDirection]` i.e. `['name desc', 'nodeType asc']` or `['name asc']`. Set this value if you want a base rule to be added to the sorting apart from the one driven by the header. |
|
||||||
| allowDropFiles | `boolean` | false | When true, this enables you to drop files directly into subfolders shown as items in the list or into another file to trigger updating it's version. When false, the dropped file will be added to the current folder (ie, the one containing all the items shown in the list). See the [Upload directive](../../core/directives/upload.directive.md) for further details about how the file drop is handled. |
|
| allowDropFiles | `boolean` | false | When true, this enables you to drop files directly into subfolders shown as items in the list or into another file to trigger updating it's version. When false, the dropped file will be added to the current folder (ie, the one containing all the items shown in the list). See the [Upload directive](../../core/directives/upload.directive.md) for further details about how the file drop is handled. |
|
||||||
|
| columnsPresetKey | `string` | | Key of columns preset set in extension.json|
|
||||||
| contentActions | `boolean` | false | Toggles content actions for each row |
|
| contentActions | `boolean` | false | Toggles content actions for each row |
|
||||||
| contentActionsPosition | `string` | "right" | Position of the content actions dropdown menu. Can be set to "left" or "right". |
|
| contentActionsPosition | `string` | "right" | Position of the content actions dropdown menu. Can be set to "left" or "right". |
|
||||||
| contextMenuActions | `boolean` | false | Toggles context menus for each row |
|
| contextMenuActions | `boolean` | false | Toggles context menus for each row |
|
||||||
@@ -72,6 +73,7 @@ Displays the documents from a repository.
|
|||||||
| includeFields | `string[]` | | Include additional information about the node in the server request. For example: association, isLink, isLocked and others. |
|
| includeFields | `string[]` | | Include additional information about the node in the server request. For example: association, isLink, isLocked and others. |
|
||||||
| loading | `boolean` | false | Toggles the loading state and animated spinners for the component. Used in combination with `navigate=false` to perform custom navigation and loading state indication. |
|
| loading | `boolean` | false | Toggles the loading state and animated spinners for the component. Used in combination with `navigate=false` to perform custom navigation and loading state indication. |
|
||||||
| locationFormat | `string` | "/" | The default route for all the location-based columns (if declared). |
|
| locationFormat | `string` | "/" | The default route for all the location-based columns (if declared). |
|
||||||
|
| maxColumnsVisible | `number` | | Limit of possible visible columns, including "$thumbnail" column if provided |
|
||||||
| maxItems | `number` | | Default value is stored in the user preference settings. Use this only if you are not using pagination. |
|
| maxItems | `number` | | Default value is stored in the user preference settings. Use this only if you are not using pagination. |
|
||||||
| multiselect | `boolean` | false | Toggles multiselect mode |
|
| multiselect | `boolean` | false | Toggles multiselect mode |
|
||||||
| navigate | `boolean` | true | Toggles navigation to folder content or file preview |
|
| navigate | `boolean` | true | Toggles navigation to folder content or file preview |
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
[contextMenu]="contextMenuActions"
|
[contextMenu]="contextMenuActions"
|
||||||
[rowStyle]="rowStyle"
|
[rowStyle]="rowStyle"
|
||||||
[rowStyleClass]="rowStyleClass"
|
[rowStyleClass]="rowStyleClass"
|
||||||
|
[showMainDatatableActions]="true"
|
||||||
[loading]="loading"
|
[loading]="loading"
|
||||||
[display]="display"
|
[display]="display"
|
||||||
[noPermission]="noPermission"
|
[noPermission]="noPermission"
|
||||||
@@ -72,4 +73,16 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</adf-loading-content-template>
|
</adf-loading-content-template>
|
||||||
|
|
||||||
|
<adf-main-menu-datatable-template>
|
||||||
|
<ng-template let-mainMenuTrigger>
|
||||||
|
<adf-datatable-column-selector
|
||||||
|
[columns]="data.getColumns()"
|
||||||
|
[mainMenuTrigger]="mainMenuTrigger"
|
||||||
|
[columnsSorting]="false"
|
||||||
|
[maxColumnsVisible]="maxColumnsVisible"
|
||||||
|
(submitColumnsVisibility)="onColumnsVisibilityChange($event)">
|
||||||
|
</adf-datatable-column-selector>
|
||||||
|
</ng-template>
|
||||||
|
</adf-main-menu-datatable-template>
|
||||||
|
|
||||||
</adf-datatable>
|
</adf-datatable>
|
||||||
|
@@ -132,57 +132,39 @@ describe('DocumentList', () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
it('should load -trashcan- preset', async () => {
|
it('should load -trashcan- preset', () => {
|
||||||
documentList.currentFolderId = '-trashcan-';
|
documentList.presetColumn = '-trashcan-';
|
||||||
|
documentList.ngAfterContentInit();
|
||||||
fixture.detectChanges();
|
|
||||||
await fixture.whenStable();
|
|
||||||
|
|
||||||
validatePreset(['$thumbnail', 'name', 'path', 'content.sizeInBytes', 'archivedAt', 'archivedByUser.displayName']);
|
validatePreset(['$thumbnail', 'name', 'path', 'content.sizeInBytes', 'archivedAt', 'archivedByUser.displayName']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load -sites- preset', async () => {
|
it('should load -sites- preset', async () => {
|
||||||
documentList.currentFolderId = '-sites-';
|
documentList.presetColumn = '-sites-';
|
||||||
|
documentList.ngAfterContentInit();
|
||||||
fixture.detectChanges();
|
|
||||||
await fixture.whenStable();
|
|
||||||
|
|
||||||
validatePreset(['$thumbnail', 'title', 'visibility']);
|
validatePreset(['$thumbnail', 'title', 'visibility']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shuld load -mysites- preset', async () => {
|
it('shuld load -mysites- preset', async () => {
|
||||||
documentList.currentFolderId = '-mysites-';
|
documentList.presetColumn = '-mysites-';
|
||||||
|
documentList.ngAfterContentInit();
|
||||||
fixture.detectChanges();
|
|
||||||
await fixture.whenStable();
|
|
||||||
|
|
||||||
validatePreset(['$thumbnail', 'title', 'visibility']);
|
validatePreset(['$thumbnail', 'title', 'visibility']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load -favorites- preset', async () => {
|
it('should load -favorites- preset', async () => {
|
||||||
documentList.currentFolderId = '-favorites-';
|
documentList.presetColumn = '-favorites-';
|
||||||
|
documentList.ngAfterContentInit();
|
||||||
fixture.detectChanges();
|
|
||||||
await fixture.whenStable();
|
|
||||||
|
|
||||||
validatePreset(['$thumbnail', 'name', 'path', 'content.sizeInBytes', 'modifiedAt', 'modifiedByUser.displayName']);
|
validatePreset(['$thumbnail', 'name', 'path', 'content.sizeInBytes', 'modifiedAt', 'modifiedByUser.displayName']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load -recent- preset', async () => {
|
it('should load -recent- preset', async () => {
|
||||||
documentList.currentFolderId = '-recent-';
|
documentList.presetColumn = '-recent-';
|
||||||
|
documentList.ngAfterContentInit();
|
||||||
fixture.detectChanges();
|
|
||||||
await fixture.whenStable();
|
|
||||||
|
|
||||||
validatePreset(['$thumbnail', 'name', 'path', 'content.sizeInBytes', 'modifiedAt']);
|
validatePreset(['$thumbnail', 'name', 'path', 'content.sizeInBytes', 'modifiedAt']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load -sharedlinks- preset', async () => {
|
it('should load -sharedlinks- preset', async () => {
|
||||||
documentList.currentFolderId = '-sharedlinks-';
|
documentList.presetColumn = '-sharedlinks-';
|
||||||
|
documentList.ngAfterContentInit();
|
||||||
fixture.detectChanges();
|
|
||||||
await fixture.whenStable();
|
|
||||||
|
|
||||||
validatePreset([
|
validatePreset([
|
||||||
'$thumbnail',
|
'$thumbnail',
|
||||||
'name',
|
'name',
|
||||||
@@ -195,11 +177,8 @@ describe('DocumentList', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should load default preset', async () => {
|
it('should load default preset', async () => {
|
||||||
documentList.currentFolderId = 'f5dacdb9-6d07-4fe9-9f2a-dedc21bae603';
|
documentList.presetColumn = 'f5dacdb9-6d07-4fe9-9f2a-dedc21bae603';
|
||||||
|
documentList.ngAfterContentInit();
|
||||||
fixture.detectChanges();
|
|
||||||
await fixture.whenStable();
|
|
||||||
|
|
||||||
validatePreset(['$thumbnail', 'name', 'content.sizeInBytes', 'modifiedAt', 'modifiedByUser.displayName']);
|
validatePreset(['$thumbnail', 'name', 'content.sizeInBytes', 'modifiedAt', 'modifiedByUser.displayName']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -38,13 +38,11 @@ import { ContentService } from '../../common/services/content.service';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
DataCellEvent,
|
DataCellEvent,
|
||||||
DataColumn,
|
|
||||||
DataRowActionEvent,
|
DataRowActionEvent,
|
||||||
DataSorting,
|
DataSorting,
|
||||||
DataTableComponent,
|
DataTableComponent,
|
||||||
DisplayMode,
|
DisplayMode,
|
||||||
ShowHeaderMode,
|
ShowHeaderMode,
|
||||||
ObjectDataColumn,
|
|
||||||
PaginatedComponent,
|
PaginatedComponent,
|
||||||
AppConfigService,
|
AppConfigService,
|
||||||
DataColumnListComponent,
|
DataColumnListComponent,
|
||||||
@@ -58,7 +56,9 @@ import {
|
|||||||
AlfrescoApiService,
|
AlfrescoApiService,
|
||||||
UserPreferenceValues,
|
UserPreferenceValues,
|
||||||
DataRow,
|
DataRow,
|
||||||
DataTableService
|
DataTableService,
|
||||||
|
DataTableSchema,
|
||||||
|
DataColumn
|
||||||
} from '@alfresco/adf-core';
|
} from '@alfresco/adf-core';
|
||||||
import { NodesApiService } from '../../common/services/nodes-api.service';
|
import { NodesApiService } from '../../common/services/nodes-api.service';
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ const BYTES_TO_MB_CONVERSION_VALUE = 1048576;
|
|||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
host: { class: 'adf-document-list' }
|
host: { class: 'adf-document-list' }
|
||||||
})
|
})
|
||||||
export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, AfterContentInit, PaginatedComponent, NavigableComponentInterface {
|
export class DocumentListComponent extends DataTableSchema implements OnInit, OnChanges, OnDestroy, AfterContentInit, PaginatedComponent, NavigableComponentInterface {
|
||||||
static SINGLE_CLICK_NAVIGATION: string = 'click';
|
static SINGLE_CLICK_NAVIGATION: string = 'click';
|
||||||
static DOUBLE_CLICK_NAVIGATION: string = 'dblclick';
|
static DOUBLE_CLICK_NAVIGATION: string = 'dblclick';
|
||||||
|
|
||||||
@@ -315,6 +315,14 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
@Input()
|
@Input()
|
||||||
maxItems: number = this.DEFAULT_PAGINATION.maxItems;
|
maxItems: number = this.DEFAULT_PAGINATION.maxItems;
|
||||||
|
|
||||||
|
/** Key of columns preset set in extension.json */
|
||||||
|
@Input()
|
||||||
|
columnsPresetKey?: string;
|
||||||
|
|
||||||
|
/** Limit of possible visible columns, including "$thumbnail" column if provided */
|
||||||
|
@Input()
|
||||||
|
maxColumnsVisible?: number;
|
||||||
|
|
||||||
/** Emitted when the user clicks a list node */
|
/** Emitted when the user clicks a list node */
|
||||||
@Output()
|
@Output()
|
||||||
nodeClick = new EventEmitter<NodeEntityEvent>();
|
nodeClick = new EventEmitter<NodeEntityEvent>();
|
||||||
@@ -371,7 +379,6 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
pagination: BehaviorSubject<PaginationModel> = new BehaviorSubject<PaginationModel>(this.DEFAULT_PAGINATION);
|
pagination: BehaviorSubject<PaginationModel> = new BehaviorSubject<PaginationModel>(this.DEFAULT_PAGINATION);
|
||||||
sortingSubject: BehaviorSubject<DataSorting[]> = new BehaviorSubject<DataSorting[]>(this.DEFAULT_SORTING);
|
sortingSubject: BehaviorSubject<DataSorting[]> = new BehaviorSubject<DataSorting[]>(this.DEFAULT_SORTING);
|
||||||
|
|
||||||
private layoutPresets = {};
|
|
||||||
private rowMenuCache: { [key: string]: ContentActionModel[] } = {};
|
private rowMenuCache: { [key: string]: ContentActionModel[] } = {};
|
||||||
private loadingTimeout: any;
|
private loadingTimeout: any;
|
||||||
private onDestroy$ = new Subject<boolean>();
|
private onDestroy$ = new Subject<boolean>();
|
||||||
@@ -395,6 +402,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
private lockService: LockService,
|
private lockService: LockService,
|
||||||
private dialog: MatDialog
|
private dialog: MatDialog
|
||||||
) {
|
) {
|
||||||
|
super(appConfig, 'default', presetsDefaultModel);
|
||||||
this.nodeService.nodeUpdated.pipe(takeUntil(this.onDestroy$)).subscribe((node) => {
|
this.nodeService.nodeUpdated.pipe(takeUntil(this.onDestroy$)).subscribe((node) => {
|
||||||
this.dataTableService.rowUpdate.next({ id: node.id, obj: { entry: node } });
|
this.dataTableService.rowUpdate.next({ id: node.id, obj: { entry: node } });
|
||||||
});
|
});
|
||||||
@@ -421,10 +429,6 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private get hasCustomLayout(): boolean {
|
|
||||||
return this.columnList?.columns?.length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getDefaultSorting(): DataSorting {
|
private getDefaultSorting(): DataSorting {
|
||||||
let defaultSorting: DataSorting;
|
let defaultSorting: DataSorting;
|
||||||
if (Array.isArray(this.sorting)) {
|
if (Array.isArray(this.sorting)) {
|
||||||
@@ -437,9 +441,6 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
return defaultSorting;
|
return defaultSorting;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getLayoutPreset(name: string = 'default'): DataColumn[] {
|
|
||||||
return (this.layoutPresets[name] || this.layoutPresets['default']).map((col) => new ObjectDataColumn(col));
|
|
||||||
}
|
|
||||||
|
|
||||||
isMobile(): boolean {
|
isMobile(): boolean {
|
||||||
return !!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
return !!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
||||||
@@ -477,34 +478,21 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
if (this.filterValue && Object.keys(this.filterValue).length > 0) {
|
if (this.filterValue && Object.keys(this.filterValue).length > 0) {
|
||||||
this.showHeader = ShowHeaderMode.Always;
|
this.showHeader = ShowHeaderMode.Always;
|
||||||
}
|
}
|
||||||
|
if (this.columnsPresetKey) {
|
||||||
|
this.setPresetKey(this.columnsPresetKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterContentInit() {
|
ngAfterContentInit() {
|
||||||
if (this.columnList) {
|
if (this.columnList) {
|
||||||
this.columnList.columns.changes.pipe(takeUntil(this.onDestroy$)).subscribe(() => this.setTableSchema());
|
this.columnList.columns.changes.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
|
||||||
|
this.createColumns();
|
||||||
|
this.data.setColumns(this.columns);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
this.setTableSchema();
|
this.createDatatableSchema();
|
||||||
|
this.data.setColumns(this.columns);
|
||||||
}
|
}
|
||||||
|
|
||||||
private setTableSchema() {
|
|
||||||
let schema: DataColumn[] = [];
|
|
||||||
|
|
||||||
if (this.hasCustomLayout) {
|
|
||||||
schema = this.columnList.columns.map((c) => c as DataColumn);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.data) {
|
|
||||||
this.data = new ShareDataTableAdapter(this.thumbnailService, this.contentService, schema, this.getDefaultSorting(), this.sortingMode);
|
|
||||||
} else if (schema && schema.length > 0) {
|
|
||||||
this.data.setColumns(schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
const columns = this.data.getColumns();
|
|
||||||
if (!columns || columns.length === 0) {
|
|
||||||
this.setupDefaultColumns(this.currentFolderId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (!changes['preselectNodes']) {
|
if (!changes['preselectNodes']) {
|
||||||
this.resetSelection();
|
this.resetSelection();
|
||||||
@@ -718,10 +706,6 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
this.setLoadingState(true);
|
this.setLoadingState(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.hasCustomLayout) {
|
|
||||||
this.setupDefaultColumns(this.currentFolderId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.documentListService.isCustomSourceService(this.currentFolderId)) {
|
if (this.documentListService.isCustomSourceService(this.currentFolderId)) {
|
||||||
this.updateCustomSourceData(this.currentFolderId);
|
this.updateCustomSourceData(this.currentFolderId);
|
||||||
}
|
}
|
||||||
@@ -772,17 +756,6 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
return [`${this.additionalSorting.key} ${this.additionalSorting.direction}`, `${currentKey} ${currentDirection}`];
|
return [`${this.additionalSorting.key} ${this.additionalSorting.direction}`, `${currentKey} ${currentDirection}`];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a set of predefined columns.
|
|
||||||
* @param preset preset to use
|
|
||||||
*/
|
|
||||||
private setupDefaultColumns(preset: string = 'default'): void {
|
|
||||||
if (this.data) {
|
|
||||||
const columns = this.getLayoutPreset(preset);
|
|
||||||
this.data.setColumns(columns);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onPreviewFile(node: NodeEntry) {
|
onPreviewFile(node: NodeEntry) {
|
||||||
if (node) {
|
if (node) {
|
||||||
const sizeInMB = node.entry?.content?.sizeInBytes / BYTES_TO_MB_CONVERSION_VALUE;
|
const sizeInMB = node.entry?.content?.sizeInBytes / BYTES_TO_MB_CONVERSION_VALUE;
|
||||||
@@ -797,7 +770,9 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onColumnsVisibilityChange(updatedColumns: Array<DataColumn>): void {
|
||||||
|
this.data.setColumns(updatedColumns);
|
||||||
|
}
|
||||||
onNodeClick(nodeEntry: NodeEntry) {
|
onNodeClick(nodeEntry: NodeEntry) {
|
||||||
const domEvent = new CustomEvent('node-click', {
|
const domEvent = new CustomEvent('node-click', {
|
||||||
detail: {
|
detail: {
|
||||||
@@ -932,10 +907,6 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
return canNavigateFolder;
|
return canNavigateFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadLayoutPresets(): void {
|
|
||||||
const externalSettings = this.appConfig.get('document-list.presets', null);
|
|
||||||
this.layoutPresets = externalSettings ? Object.assign({}, presetsDefaultModel, externalSettings) : presetsDefaultModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
private onDataReady(nodePaging: NodePaging) {
|
private onDataReady(nodePaging: NodePaging) {
|
||||||
this.ready.emit(nodePaging);
|
this.ready.emit(nodePaging);
|
||||||
|
@@ -43,6 +43,7 @@
|
|||||||
class="adf-columns-selector-column-checkbox"
|
class="adf-columns-selector-column-checkbox"
|
||||||
[attr.data-automation-id]="'adf-columns-selector-column-checkbox-' + column.title"
|
[attr.data-automation-id]="'adf-columns-selector-column-checkbox-' + column.title"
|
||||||
[checked]="!column.isHidden"
|
[checked]="!column.isHidden"
|
||||||
|
[disabled]="isCheckboxDisabled(column)"
|
||||||
(change)="changeColumnVisibility(column)">
|
(change)="changeColumnVisibility(column)">
|
||||||
<div class="adf-columns-selector-list-content">{{translatedTitle}}</div>
|
<div class="adf-columns-selector-list-content">{{translatedTitle}}</div>
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
|
@@ -156,19 +156,35 @@ describe('ColumnsSelectorComponent', () => {
|
|||||||
expect(toggledColumnItem.isHidden).toBe(true);
|
expect(toggledColumnItem.isHidden).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set proper default state for checkboxes', async () => {
|
|
||||||
menuOpenedTrigger.next();
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
const checkboxes = await loader.getAllHarnesses(MatCheckboxHarness);
|
describe('checkboxes', () => {
|
||||||
|
it('should have set proper default state', async () => {
|
||||||
|
menuOpenedTrigger.next();
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
expect(await checkboxes[0].isChecked()).toBe(true);
|
const checkboxes = await loader.getAllHarnesses(MatCheckboxHarness);
|
||||||
expect(await checkboxes[1].isChecked()).toBe(true);
|
|
||||||
expect(await checkboxes[2].isChecked()).toBe(true);
|
expect(await checkboxes[0].isChecked()).toBe(true);
|
||||||
expect(await checkboxes[3].isChecked()).toBe(false);
|
expect(await checkboxes[1].isChecked()).toBe(true);
|
||||||
|
expect(await checkboxes[2].isChecked()).toBe(true);
|
||||||
|
expect(await checkboxes[3].isChecked()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be disabled when visible columns limit is reached', async () => {
|
||||||
|
component.maxColumnsVisible = 4;
|
||||||
|
menuOpenedTrigger.next();
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const checkboxes = await loader.getAllHarnesses(MatCheckboxHarness);
|
||||||
|
|
||||||
|
expect(await checkboxes[0].isDisabled()).toBe(false);
|
||||||
|
expect(await checkboxes[1].isDisabled()).toBe(false);
|
||||||
|
expect(await checkboxes[2].isDisabled()).toBe(false);
|
||||||
|
expect(await checkboxes[3].isDisabled()).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show hidden columns at the end of the list', async () => {
|
describe('sorting', () => {
|
||||||
const hiddenDataColumn: DataColumn = {
|
const hiddenDataColumn: DataColumn = {
|
||||||
id: 'hiddenDataColumn',
|
id: 'hiddenDataColumn',
|
||||||
title: 'hiddenDataColumn',
|
title: 'hiddenDataColumn',
|
||||||
@@ -183,14 +199,27 @@ describe('ColumnsSelectorComponent', () => {
|
|||||||
key: 'shownDataColumn',
|
key: 'shownDataColumn',
|
||||||
type: 'text'
|
type: 'text'
|
||||||
};
|
};
|
||||||
|
it('should show hidden columns at the end of the list by default', async () => {
|
||||||
|
component.columns = [hiddenDataColumn, shownDataColumn];
|
||||||
|
menuOpenedTrigger.next();
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
component.columns = [hiddenDataColumn, shownDataColumn];
|
const checkboxes = await loader.getAllHarnesses(MatCheckboxHarness);
|
||||||
menuOpenedTrigger.next();
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
const checkboxes = await loader.getAllHarnesses(MatCheckboxHarness);
|
expect(await checkboxes[0].getLabelText()).toBe(shownDataColumn.title);
|
||||||
|
expect(await checkboxes[1].getLabelText()).toBe(hiddenDataColumn.title);
|
||||||
|
});
|
||||||
|
|
||||||
expect(await checkboxes[0].getLabelText()).toBe(shownDataColumn.title);
|
it('should NOT show hidden columns at the end of the list if sorting is disabled', async () => {
|
||||||
expect(await checkboxes[1].getLabelText()).toBe(hiddenDataColumn.title);
|
component.columns = [hiddenDataColumn, shownDataColumn];
|
||||||
|
component.columnsSorting = false;
|
||||||
|
menuOpenedTrigger.next();
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const checkboxes = await loader.getAllHarnesses(MatCheckboxHarness);
|
||||||
|
|
||||||
|
expect(await checkboxes[0].getLabelText()).toBe(hiddenDataColumn.title);
|
||||||
|
expect(await checkboxes[1].getLabelText()).toBe(shownDataColumn.title);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -34,6 +34,12 @@ export class ColumnsSelectorComponent implements OnInit, OnDestroy {
|
|||||||
@Input()
|
@Input()
|
||||||
mainMenuTrigger: MatMenuTrigger;
|
mainMenuTrigger: MatMenuTrigger;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
columnsSorting = true;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
maxColumnsVisible?: number;
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
submitColumnsVisibility = new EventEmitter<DataColumn[]>();
|
submitColumnsVisibility = new EventEmitter<DataColumn[]>();
|
||||||
|
|
||||||
@@ -47,7 +53,7 @@ export class ColumnsSelectorComponent implements OnInit, OnDestroy {
|
|||||||
takeUntil(this.onDestroy$)
|
takeUntil(this.onDestroy$)
|
||||||
).subscribe(() => {
|
).subscribe(() => {
|
||||||
const columns = this.columns.map(column => ({...column}));
|
const columns = this.columns.map(column => ({...column}));
|
||||||
this.columnItems = this.sortColumns(columns);
|
this.columnItems = this.columnsSorting ? this.sortColumns(columns) : columns;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.mainMenuTrigger.menuClosed.pipe(
|
this.mainMenuTrigger.menuClosed.pipe(
|
||||||
@@ -82,6 +88,10 @@ export class ColumnsSelectorComponent implements OnInit, OnDestroy {
|
|||||||
this.closeMenu();
|
this.closeMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isCheckboxDisabled(column: DataColumn): boolean {
|
||||||
|
return this.maxColumnsVisible && column.isHidden && this.maxColumnsVisible === this.columnItems.filter(dataColumn => !dataColumn.isHidden).length;
|
||||||
|
}
|
||||||
|
|
||||||
private sortColumns(columns: DataColumn[]): DataColumn[] {
|
private sortColumns(columns: DataColumn[]): DataColumn[] {
|
||||||
const shownColumns = columns.filter(column => !column.isHidden);
|
const shownColumns = columns.filter(column => !column.isHidden);
|
||||||
const hiddenColumns = columns.filter(column => column.isHidden);
|
const hiddenColumns = columns.filter(column => column.isHidden);
|
||||||
|
@@ -49,7 +49,6 @@ export abstract class DataTableSchema<T = unknown> {
|
|||||||
|
|
||||||
public createDatatableSchema(): void {
|
public createDatatableSchema(): void {
|
||||||
this.loadLayoutPresets();
|
this.loadLayoutPresets();
|
||||||
|
|
||||||
if (!this.columns || this.columns.length === 0) {
|
if (!this.columns || this.columns.length === 0) {
|
||||||
this.createColumns();
|
this.createColumns();
|
||||||
this.columnsSchemaSubject$.next(true);
|
this.columnsSchemaSubject$.next(true);
|
||||||
@@ -98,7 +97,7 @@ export abstract class DataTableSchema<T = unknown> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getSchemaFromConfig(presetColumn: string): DataColumn[] {
|
public getSchemaFromConfig(presetColumn: string): DataColumn[] {
|
||||||
return presetColumn ? this.layoutPresets[presetColumn].map((col) => new ObjectDataColumn(col)) : [];
|
return presetColumn && this.layoutPresets[presetColumn] ? this.layoutPresets[presetColumn].map((col) => new ObjectDataColumn(col)) : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
private getDefaultLayoutPreset(): DataColumn[] {
|
private getDefaultLayoutPreset(): DataColumn[] {
|
||||||
|
@@ -44,6 +44,7 @@ export interface DocumentListPresetRef extends ExtensionElement {
|
|||||||
template: string;
|
template: string;
|
||||||
desktopOnly: boolean;
|
desktopOnly: boolean;
|
||||||
sortingKey: string;
|
sortingKey: string;
|
||||||
|
isHidden?: boolean;
|
||||||
rules?: {
|
rules?: {
|
||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
visible?: string;
|
visible?: string;
|
||||||
|
Reference in New Issue
Block a user