diff --git a/docs/content-services/components/document-list.component.md b/docs/content-services/components/document-list.component.md
index 1b52e1ee028..71c36ab0a42 100644
--- a/docs/content-services/components/document-list.component.md
+++ b/docs/content-services/components/document-list.component.md
@@ -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. |
| 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 |
| 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 |
@@ -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. |
| 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). |
+| 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. |
| multiselect | `boolean` | false | Toggles multiselect mode |
| navigate | `boolean` | true | Toggles navigation to folder content or file preview |
diff --git a/lib/content-services/src/lib/document-list/components/document-list.component.html b/lib/content-services/src/lib/document-list/components/document-list.component.html
index d5ba61e536b..5eeb6a5c33e 100644
--- a/lib/content-services/src/lib/document-list/components/document-list.component.html
+++ b/lib/content-services/src/lib/document-list/components/document-list.component.html
@@ -8,6 +8,7 @@
[contextMenu]="contextMenuActions"
[rowStyle]="rowStyle"
[rowStyleClass]="rowStyleClass"
+ [showMainDatatableActions]="true"
[loading]="loading"
[display]="display"
[noPermission]="noPermission"
@@ -72,4 +73,16 @@
+
+
+
+
+
+
+
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 6afad064061..8ef5841fc37 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
@@ -132,57 +132,39 @@ describe('DocumentList', () => {
});
};
- it('should load -trashcan- preset', async () => {
- documentList.currentFolderId = '-trashcan-';
-
- fixture.detectChanges();
- await fixture.whenStable();
-
+ it('should load -trashcan- preset', () => {
+ documentList.presetColumn = '-trashcan-';
+ documentList.ngAfterContentInit();
validatePreset(['$thumbnail', 'name', 'path', 'content.sizeInBytes', 'archivedAt', 'archivedByUser.displayName']);
});
it('should load -sites- preset', async () => {
- documentList.currentFolderId = '-sites-';
-
- fixture.detectChanges();
- await fixture.whenStable();
-
+ documentList.presetColumn = '-sites-';
+ documentList.ngAfterContentInit();
validatePreset(['$thumbnail', 'title', 'visibility']);
});
it('shuld load -mysites- preset', async () => {
- documentList.currentFolderId = '-mysites-';
-
- fixture.detectChanges();
- await fixture.whenStable();
-
+ documentList.presetColumn = '-mysites-';
+ documentList.ngAfterContentInit();
validatePreset(['$thumbnail', 'title', 'visibility']);
});
it('should load -favorites- preset', async () => {
- documentList.currentFolderId = '-favorites-';
-
- fixture.detectChanges();
- await fixture.whenStable();
-
+ documentList.presetColumn = '-favorites-';
+ documentList.ngAfterContentInit();
validatePreset(['$thumbnail', 'name', 'path', 'content.sizeInBytes', 'modifiedAt', 'modifiedByUser.displayName']);
});
it('should load -recent- preset', async () => {
- documentList.currentFolderId = '-recent-';
-
- fixture.detectChanges();
- await fixture.whenStable();
-
+ documentList.presetColumn = '-recent-';
+ documentList.ngAfterContentInit();
validatePreset(['$thumbnail', 'name', 'path', 'content.sizeInBytes', 'modifiedAt']);
});
it('should load -sharedlinks- preset', async () => {
- documentList.currentFolderId = '-sharedlinks-';
-
- fixture.detectChanges();
- await fixture.whenStable();
-
+ documentList.presetColumn = '-sharedlinks-';
+ documentList.ngAfterContentInit();
validatePreset([
'$thumbnail',
'name',
@@ -195,11 +177,8 @@ describe('DocumentList', () => {
});
it('should load default preset', async () => {
- documentList.currentFolderId = 'f5dacdb9-6d07-4fe9-9f2a-dedc21bae603';
-
- fixture.detectChanges();
- await fixture.whenStable();
-
+ documentList.presetColumn = 'f5dacdb9-6d07-4fe9-9f2a-dedc21bae603';
+ documentList.ngAfterContentInit();
validatePreset(['$thumbnail', 'name', 'content.sizeInBytes', 'modifiedAt', 'modifiedByUser.displayName']);
});
});
diff --git a/lib/content-services/src/lib/document-list/components/document-list.component.ts b/lib/content-services/src/lib/document-list/components/document-list.component.ts
index df702a5040a..2417894819c 100644
--- a/lib/content-services/src/lib/document-list/components/document-list.component.ts
+++ b/lib/content-services/src/lib/document-list/components/document-list.component.ts
@@ -38,13 +38,11 @@ import { ContentService } from '../../common/services/content.service';
import {
DataCellEvent,
- DataColumn,
DataRowActionEvent,
DataSorting,
DataTableComponent,
DisplayMode,
ShowHeaderMode,
- ObjectDataColumn,
PaginatedComponent,
AppConfigService,
DataColumnListComponent,
@@ -58,7 +56,9 @@ import {
AlfrescoApiService,
UserPreferenceValues,
DataRow,
- DataTableService
+ DataTableService,
+ DataTableSchema,
+ DataColumn
} from '@alfresco/adf-core';
import { NodesApiService } from '../../common/services/nodes-api.service';
@@ -97,7 +97,7 @@ const BYTES_TO_MB_CONVERSION_VALUE = 1048576;
encapsulation: ViewEncapsulation.None,
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 DOUBLE_CLICK_NAVIGATION: string = 'dblclick';
@@ -315,6 +315,14 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
@Input()
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 */
@Output()
nodeClick = new EventEmitter();
@@ -371,7 +379,6 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
pagination: BehaviorSubject = new BehaviorSubject(this.DEFAULT_PAGINATION);
sortingSubject: BehaviorSubject = new BehaviorSubject(this.DEFAULT_SORTING);
- private layoutPresets = {};
private rowMenuCache: { [key: string]: ContentActionModel[] } = {};
private loadingTimeout: any;
private onDestroy$ = new Subject();
@@ -395,6 +402,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
private lockService: LockService,
private dialog: MatDialog
) {
+ super(appConfig, 'default', presetsDefaultModel);
this.nodeService.nodeUpdated.pipe(takeUntil(this.onDestroy$)).subscribe((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;
}
- private get hasCustomLayout(): boolean {
- return this.columnList?.columns?.length > 0;
- }
-
private getDefaultSorting(): DataSorting {
let defaultSorting: DataSorting;
if (Array.isArray(this.sorting)) {
@@ -437,9 +441,6 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
return defaultSorting;
}
- private getLayoutPreset(name: string = 'default'): DataColumn[] {
- return (this.layoutPresets[name] || this.layoutPresets['default']).map((col) => new ObjectDataColumn(col));
- }
isMobile(): boolean {
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) {
this.showHeader = ShowHeaderMode.Always;
}
+ if (this.columnsPresetKey) {
+ this.setPresetKey(this.columnsPresetKey);
+ }
}
ngAfterContentInit() {
if (this.columnList) {
- this.columnList.columns.changes.pipe(takeUntil(this.onDestroy$)).subscribe(() => this.setTableSchema());
- }
- this.setTableSchema();
- }
-
- 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);
+ this.columnList.columns.changes.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
+ this.createColumns();
+ this.data.setColumns(this.columns);
+ });
}
+ this.createDatatableSchema();
+ this.data.setColumns(this.columns);
}
-
ngOnChanges(changes: SimpleChanges) {
if (!changes['preselectNodes']) {
this.resetSelection();
@@ -718,10 +706,6 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
this.setLoadingState(true);
}
- if (!this.hasCustomLayout) {
- this.setupDefaultColumns(this.currentFolderId);
- }
-
if (this.documentListService.isCustomSourceService(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}`];
}
- /**
- * 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) {
if (node) {
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): void {
+ this.data.setColumns(updatedColumns);
+ }
onNodeClick(nodeEntry: NodeEntry) {
const domEvent = new CustomEvent('node-click', {
detail: {
@@ -932,10 +907,6 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
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) {
this.ready.emit(nodePaging);
diff --git a/lib/core/src/lib/datatable/components/columns-selector/columns-selector.component.html b/lib/core/src/lib/datatable/components/columns-selector/columns-selector.component.html
index 0c05eaa43de..2e71b7a9780 100644
--- a/lib/core/src/lib/datatable/components/columns-selector/columns-selector.component.html
+++ b/lib/core/src/lib/datatable/components/columns-selector/columns-selector.component.html
@@ -43,6 +43,7 @@
class="adf-columns-selector-column-checkbox"
[attr.data-automation-id]="'adf-columns-selector-column-checkbox-' + column.title"
[checked]="!column.isHidden"
+ [disabled]="isCheckboxDisabled(column)"
(change)="changeColumnVisibility(column)">
{{translatedTitle}}
diff --git a/lib/core/src/lib/datatable/components/columns-selector/columns-selector.component.spec.ts b/lib/core/src/lib/datatable/components/columns-selector/columns-selector.component.spec.ts
index b15f72930e4..790fbf17666 100644
--- a/lib/core/src/lib/datatable/components/columns-selector/columns-selector.component.spec.ts
+++ b/lib/core/src/lib/datatable/components/columns-selector/columns-selector.component.spec.ts
@@ -156,19 +156,35 @@ describe('ColumnsSelectorComponent', () => {
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();
+
+ const checkboxes = await loader.getAllHarnesses(MatCheckboxHarness);
+
+ expect(await checkboxes[0].isChecked()).toBe(true);
+ 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();
- expect(await checkboxes[0].isChecked()).toBe(true);
- expect(await checkboxes[1].isChecked()).toBe(true);
- expect(await checkboxes[2].isChecked()).toBe(true);
- expect(await checkboxes[3].isChecked()).toBe(false);
+ 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 = {
id: 'hiddenDataColumn',
title: 'hiddenDataColumn',
@@ -183,14 +199,27 @@ describe('ColumnsSelectorComponent', () => {
key: 'shownDataColumn',
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];
- menuOpenedTrigger.next();
- fixture.detectChanges();
+ const checkboxes = await loader.getAllHarnesses(MatCheckboxHarness);
- const checkboxes = await loader.getAllHarnesses(MatCheckboxHarness);
+ expect(await checkboxes[0].getLabelText()).toBe(shownDataColumn.title);
+ expect(await checkboxes[1].getLabelText()).toBe(hiddenDataColumn.title);
+ });
+
+ it('should NOT show hidden columns at the end of the list if sorting is disabled', async () => {
+ component.columns = [hiddenDataColumn, shownDataColumn];
+ component.columnsSorting = false;
+ 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(hiddenDataColumn.title);
+ expect(await checkboxes[1].getLabelText()).toBe(shownDataColumn.title);
+ });
});
});
diff --git a/lib/core/src/lib/datatable/components/columns-selector/columns-selector.component.ts b/lib/core/src/lib/datatable/components/columns-selector/columns-selector.component.ts
index 99e370d96cd..4761768fb38 100644
--- a/lib/core/src/lib/datatable/components/columns-selector/columns-selector.component.ts
+++ b/lib/core/src/lib/datatable/components/columns-selector/columns-selector.component.ts
@@ -34,6 +34,12 @@ export class ColumnsSelectorComponent implements OnInit, OnDestroy {
@Input()
mainMenuTrigger: MatMenuTrigger;
+ @Input()
+ columnsSorting = true;
+
+ @Input()
+ maxColumnsVisible?: number;
+
@Output()
submitColumnsVisibility = new EventEmitter();
@@ -47,7 +53,7 @@ export class ColumnsSelectorComponent implements OnInit, OnDestroy {
takeUntil(this.onDestroy$)
).subscribe(() => {
const columns = this.columns.map(column => ({...column}));
- this.columnItems = this.sortColumns(columns);
+ this.columnItems = this.columnsSorting ? this.sortColumns(columns) : columns;
});
this.mainMenuTrigger.menuClosed.pipe(
@@ -82,6 +88,10 @@ export class ColumnsSelectorComponent implements OnInit, OnDestroy {
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[] {
const shownColumns = columns.filter(column => !column.isHidden);
const hiddenColumns = columns.filter(column => column.isHidden);
diff --git a/lib/core/src/lib/datatable/data/data-table.schema.ts b/lib/core/src/lib/datatable/data/data-table.schema.ts
index 1615b5c2d63..693d753441f 100644
--- a/lib/core/src/lib/datatable/data/data-table.schema.ts
+++ b/lib/core/src/lib/datatable/data/data-table.schema.ts
@@ -49,7 +49,6 @@ export abstract class DataTableSchema {
public createDatatableSchema(): void {
this.loadLayoutPresets();
-
if (!this.columns || this.columns.length === 0) {
this.createColumns();
this.columnsSchemaSubject$.next(true);
@@ -98,7 +97,7 @@ export abstract class DataTableSchema {
}
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[] {
diff --git a/lib/extensions/src/lib/config/document-list.extensions.ts b/lib/extensions/src/lib/config/document-list.extensions.ts
index 863caa06b4d..1bce638bd0f 100644
--- a/lib/extensions/src/lib/config/document-list.extensions.ts
+++ b/lib/extensions/src/lib/config/document-list.extensions.ts
@@ -27,6 +27,7 @@ export interface DocumentListPresetRef extends ExtensionElement {
template: string;
desktopOnly: boolean;
sortingKey: string;
+ isHidden?: boolean;
rules?: {
[key: string]: string;
visible?: string;