[ACA-1226] Node info panel (#241)

* node metadata

* getNodeInfo over nodeInfo
This commit is contained in:
Cilibiu Bogdan
2018-03-19 13:16:20 +02:00
committed by Denys Vuika
parent 50d6147e81
commit 086d22b92d
20 changed files with 708 additions and 396 deletions

View File

@@ -38,6 +38,7 @@ import { NodeMoveDirective } from './directives/node-move.directive';
import { NodeRestoreDirective } from './directives/node-restore.directive'; import { NodeRestoreDirective } from './directives/node-restore.directive';
import { NodePermanentDeleteDirective } from './directives/node-permanent-delete.directive'; import { NodePermanentDeleteDirective } from './directives/node-permanent-delete.directive';
import { NodeUnshareDirective } from './directives/node-unshare.directive'; import { NodeUnshareDirective } from './directives/node-unshare.directive';
import { NodeInfoDirective} from './directives/node-info.directive';
import { ContentManagementService } from './services/content-management.service'; import { ContentManagementService } from './services/content-management.service';
import { BrowsingFilesService } from './services/browsing-files.service'; import { BrowsingFilesService } from './services/browsing-files.service';
@@ -61,7 +62,8 @@ export function declarations() {
NodeMoveDirective, NodeMoveDirective,
NodeRestoreDirective, NodeRestoreDirective,
NodePermanentDeleteDirective, NodePermanentDeleteDirective,
NodeUnshareDirective NodeUnshareDirective,
NodeInfoDirective
]; ];
} }

View File

@@ -0,0 +1,103 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2018 Alfresco Software Limited
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { Component } from '@angular/core';
import { ComponentFixture, TestBed, async, fakeAsync, tick } from '@angular/core/testing';
import { AlfrescoApiService } from '@alfresco/adf-core';
import { CommonModule } from '../common.module';
@Component({
template: '<div [app-node-info]="selection"></div>'
})
class TestComponent {
selection;
}
describe('NodeInfoDirective', () => {
let fixture: ComponentFixture<TestComponent>;
let component: TestComponent;
let apiService: AlfrescoApiService;
let nodeService;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
CommonModule
],
declarations: [
TestComponent
]
});
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
apiService = TestBed.get(AlfrescoApiService);
nodeService = apiService.getInstance().nodes;
fixture.detectChanges();
}));
beforeEach(() => {
spyOn(nodeService, 'getNodeInfo').and.returnValue(Promise.resolve({
entry: { name: 'borg' }
}));
});
it('should not get node info when selection is empty', () => {
component.selection = [];
fixture.detectChanges();
document.dispatchEvent(new CustomEvent('click'));
expect(nodeService.getNodeInfo).not.toHaveBeenCalled();
});
it('should get node info from selection', () => {
component.selection = [{ entry: { id: 'id' } }];
fixture.detectChanges();
document.dispatchEvent(new CustomEvent('click'));
expect(nodeService.getNodeInfo).toHaveBeenCalledWith('id');
});
it('should get node info of last entry when selecting multiple nodes', fakeAsync(() => {
component.selection = [
{ entry: { id: 'id1', isFile: true } },
{ entry: { id: 'id2', isFile: true } },
{ entry: { id: 'id3', isFile: true } }
];
fixture.detectChanges();
document.dispatchEvent(new CustomEvent('click'));
fixture.detectChanges();
tick();
expect(nodeService.getNodeInfo).toHaveBeenCalledWith('id3');
}));
});

View File

@@ -0,0 +1,76 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2018 Alfresco Software Limited
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { Directive, HostListener, Input, Output, EventEmitter } from '@angular/core';
import { AlfrescoApiService } from '@alfresco/adf-core';
import { MinimalNodeEntity, MinimalNodeEntryEntity, Node } from 'alfresco-js-api';
@Directive({
selector: '[app-node-info]',
exportAs: 'nodeInfo'
})
export class NodeInfoDirective {
@Input('app-node-info') selection: MinimalNodeEntity[];
@Output() changed: EventEmitter<null|Node> = new EventEmitter<null|Node>();
@Output() error: EventEmitter<null> = new EventEmitter<null>();
node: Node;
loading: boolean = null;
@HostListener('document:click', ['$event'])
onClick(event) {
this.getNodeInfo();
}
constructor(private apiService: AlfrescoApiService) {}
getNodeInfo() {
if (!this.selection.length) {
this.node = null;
this.loading = false;
this.changed.emit(null);
return;
}
const node = this.selection[this.selection.length - 1];
if (node) {
this.loading = true;
this.apiService.getInstance().nodes
.getNodeInfo((<any>node.entry).nodeId || node.entry.id)
.then((data: MinimalNodeEntryEntity) => {
this.node = data;
this.changed.emit(data);
this.loading = false;
})
.catch(() => {
this.error.emit();
this.loading = false;
});
}
}
}

View File

@@ -29,6 +29,13 @@
<mat-icon>create</mat-icon> <mat-icon>create</mat-icon>
</button> </button>
<button mat-icon-button
[color]="infoDrawerOpened ? 'primary' : 'accent'"
*ngIf="documentList.selection.length"
(click)="toggleSidebar()">
<mat-icon>info_outline</mat-icon>
</button>
<button <button
mat-icon-button mat-icon-button
*ngIf="hasSelection(documentList.selection)" *ngIf="hasSelection(documentList.selection)"
@@ -74,79 +81,93 @@
</adf-toolbar> </adf-toolbar>
</div> </div>
<div class="inner-layout__content"> <div class="inner-layout__content">
<div class="inner-layout__panel">
<adf-document-list #documentList
[attr.class]="documentList.isEmpty() ? 'empty-list' : ''"
currentFolderId="-favorites-"
selectionMode="multiple"
[navigate]="false"
[sorting]="sorting"
[contextMenuActions]="true"
[contentActions]="false"
(sorting-changed)="onSortingChanged($event)"
(node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)">
<adf-document-list #documentList <empty-folder-content>
[attr.class]="documentList.isEmpty() ? 'empty-list' : ''" <ng-template>
currentFolderId="-favorites-" <app-empty-folder
selectionMode="multiple" icon="star_rate"
[navigate]="false" title="APP.BROWSE.FAVORITES.EMPTY_STATE.TITLE"
[sorting]="sorting" subtitle="APP.BROWSE.FAVORITES.EMPTY_STATE.TEXT">
[contextMenuActions]="true" </app-empty-folder>
[contentActions]="false"
(sorting-changed)="onSortingChanged($event)"
(node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)">
<empty-folder-content>
<ng-template>
<app-empty-folder
icon="star_rate"
title="APP.BROWSE.FAVORITES.EMPTY_STATE.TITLE"
subtitle="APP.BROWSE.FAVORITES.EMPTY_STATE.TEXT">
</app-empty-folder>
</ng-template>
</empty-folder-content>
<data-columns>
<data-column
key="$thumbnail"
type="image"
[sortable]="false"
class="image-table-cell">
</data-column>
<data-column
class="adf-data-table-cell--ellipsis__name"
key="name"
title="APP.DOCUMENT_LIST.COLUMNS.NAME">
<ng-template let-value="value" let-context>
<span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
</ng-template> </ng-template>
</data-column> </empty-folder-content>
<data-column <data-columns>
key="path"
title="APP.DOCUMENT_LIST.COLUMNS.LOCATION">
<ng-template let-context>
<app-location-link [context]="context"></app-location-link>
</ng-template>
</data-column>
<data-column <data-column
key="sizeInBytes" key="$thumbnail"
title="APP.DOCUMENT_LIST.COLUMNS.SIZE" type="image"
type="fileSize"> [sortable]="false"
</data-column> class="image-table-cell">
</data-column>
<data-column <data-column
key="modifiedAt" class="adf-data-table-cell--ellipsis__name"
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_ON"> key="name"
<ng-template let-value="value"> title="APP.DOCUMENT_LIST.COLUMNS.NAME">
<span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span> <ng-template let-value="value" let-context>
</ng-template> <span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
</data-column> </ng-template>
</data-column>
<data-column <data-column
class="adf-data-table-cell--ellipsis" key="path"
key="modifiedByUser.displayName" title="APP.DOCUMENT_LIST.COLUMNS.LOCATION">
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_BY"> <ng-template let-context>
</data-column> <app-location-link [context]="context"></app-location-link>
</ng-template>
</data-column>
</data-columns> <data-column
</adf-document-list> key="sizeInBytes"
<adf-pagination [ngClass]="{ 'no-border' : documentList.isEmpty()}" title="APP.DOCUMENT_LIST.COLUMNS.SIZE"
[target]="documentList" type="fileSize">
(changePageSize)="onChangePageSize($event)"> </data-column>
</adf-pagination>
<data-column
key="modifiedAt"
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_ON">
<ng-template let-value="value">
<span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span>
</ng-template>
</data-column>
<data-column
class="adf-data-table-cell--ellipsis"
key="modifiedByUser.displayName"
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_BY">
</data-column>
</data-columns>
</adf-document-list>
<adf-pagination [ngClass]="{ 'no-border' : documentList.isEmpty()}"
[target]="documentList"
(changePageSize)="onChangePageSize($event)">
</adf-pagination>
</div>
<div class="inner-layout__side-panel"
*ngIf="infoDrawerOpened"
[app-node-info]="documentList.selection"
(changed)="toggleSidebar($event)"
#infoInstance=nodeInfo>
<adf-info-drawer title="Details">
<adf-info-drawer-tab label="Properties">
<adf-content-metadata-card [node]="infoInstance.node"></adf-content-metadata-card>
</adf-info-drawer-tab>
</adf-info-drawer>
</div>
</div> </div>
</div> </div>

View File

@@ -44,6 +44,7 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material';
import { DocumentListService } from '@alfresco/adf-content-services'; import { DocumentListService } from '@alfresco/adf-content-services';
import { ContentManagementService } from '../../common/services/content-management.service'; import { ContentManagementService } from '../../common/services/content-management.service';
import { NodeInfoDirective } from '../../common/directives/node-info.directive';
import { FavoritesComponent } from './favorites.component'; import { FavoritesComponent } from './favorites.component';
@@ -100,6 +101,7 @@ describe('Favorites Routed Component', () => {
TimeAgoPipe, TimeAgoPipe,
NodeNameTooltipPipe, NodeNameTooltipPipe,
NodeFavoriteDirective, NodeFavoriteDirective,
NodeInfoDirective,
DocumentListComponent, DocumentListComponent,
FavoritesComponent FavoritesComponent
], ],

View File

@@ -31,6 +31,13 @@
<mat-icon>create</mat-icon> <mat-icon>create</mat-icon>
</button> </button>
<button mat-icon-button
[color]="infoDrawerOpened ? 'primary' : 'accent'"
*ngIf="documentList.selection.length"
(click)="toggleSidebar()">
<mat-icon>info_outline</mat-icon>
</button>
<button <button
mat-icon-button mat-icon-button
*ngIf="hasSelection(documentList.selection)" *ngIf="hasSelection(documentList.selection)"
@@ -83,76 +90,91 @@
</div> </div>
<div [attr.class]="!isValidPath ? 'content--hide' : 'inner-layout__content'"> <div [attr.class]="!isValidPath ? 'content--hide' : 'inner-layout__content'">
<adf-upload-drag-area <div class="inner-layout__panel">
[parentId]="node?.id" <adf-upload-drag-area
[disabled]="!canCreateContent(node)"> [parentId]="node?.id"
[disabled]="!canCreateContent(node)">
<adf-document-list #documentList <adf-document-list #documentList
[attr.class]="documentList.isEmpty() ? 'empty-list' : ''" [attr.class]="documentList.isEmpty() ? 'empty-list' : ''"
[loading]="isLoading" [loading]="isLoading"
[node]="paging" [node]="paging"
[sorting]="sorting" [sorting]="sorting"
[allowDropFiles]="true" [allowDropFiles]="true"
[contextMenuActions]="true" [contextMenuActions]="true"
[contentActions]="false" [contentActions]="false"
[navigate]="false" [navigate]="false"
[selectionMode]="'multiple'" [selectionMode]="'multiple'"
[imageResolver]="imageResolver" [imageResolver]="imageResolver"
(sorting-changed)="onSortingChanged($event)" (sorting-changed)="onSortingChanged($event)"
(node-dblclick)="onNodeDoubleClick($event)" (node-dblclick)="onNodeDoubleClick($event)"
(node-select)="onNodeSelect($event, documentList)"> (node-select)="onNodeSelect($event, documentList)">
<data-columns> <data-columns>
<data-column <data-column
key="$thumbnail" key="$thumbnail"
type="image" type="image"
[sortable]="false" [sortable]="false"
class="image-table-cell"> class="image-table-cell">
</data-column> </data-column>
<data-column <data-column
class="adf-data-table-cell--ellipsis__name" class="adf-data-table-cell--ellipsis__name"
key="name" key="name"
title="APP.DOCUMENT_LIST.COLUMNS.NAME"> title="APP.DOCUMENT_LIST.COLUMNS.NAME">
<ng-template let-value="value" let-context> <ng-template let-value="value" let-context>
<span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span> <span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
</ng-template> </ng-template>
</data-column> </data-column>
<data-column <data-column
key="content.sizeInBytes" key="content.sizeInBytes"
title="APP.DOCUMENT_LIST.COLUMNS.SIZE"> title="APP.DOCUMENT_LIST.COLUMNS.SIZE">
<ng-template let-value="value"> <ng-template let-value="value">
<span title="{{ value }} bytes">{{ value | adfFileSize }}</span> <span title="{{ value }} bytes">{{ value | adfFileSize }}</span>
</ng-template> </ng-template>
</data-column> </data-column>
<data-column <data-column
key="modifiedAt" key="modifiedAt"
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_ON"> title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_ON">
<ng-template let-value="value"> <ng-template let-value="value">
<span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span> <span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span>
</ng-template> </ng-template>
</data-column> </data-column>
<data-column <data-column
class="adf-data-table-cell--ellipsis" class="adf-data-table-cell--ellipsis"
key="modifiedByUser.displayName" key="modifiedByUser.displayName"
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_BY"> title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_BY">
</data-column> </data-column>
</data-columns> </data-columns>
</adf-document-list> </adf-document-list>
<ng-container *ngIf="!isEmpty"> <ng-container *ngIf="!isEmpty">
<adf-pagination <adf-pagination
[supportedPageSizes]="documentList.supportedPageSizes" [supportedPageSizes]="documentList.supportedPageSizes"
[pagination]="pagination" [pagination]="pagination"
(change)="load(true, $event)" (change)="load(true, $event)"
(changePageSize)="onChangePageSize($event)"> (changePageSize)="onChangePageSize($event)">
</adf-pagination> </adf-pagination>
</ng-container> </ng-container>
</adf-upload-drag-area> </adf-upload-drag-area>
</div>
<div class="inner-layout__side-panel"
*ngIf="infoDrawerOpened"
[app-node-info]="documentList.selection"
(changed)="toggleSidebar($event)"
#infoInstance=nodeInfo>
<adf-info-drawer title="Details">
<adf-info-drawer-tab label="Properties">
<adf-content-metadata-card [node]="infoInstance.node"></adf-content-metadata-card>
</adf-info-drawer-tab>
</adf-info-drawer>
</div>
</div> </div>
</div> </div>

View File

@@ -45,6 +45,7 @@ import { DocumentListService } from '@alfresco/adf-content-services';
import { ContentManagementService } from '../../common/services/content-management.service'; import { ContentManagementService } from '../../common/services/content-management.service';
import { BrowsingFilesService } from '../../common/services/browsing-files.service'; import { BrowsingFilesService } from '../../common/services/browsing-files.service';
import { NodeActionsService } from '../../common/services/node-actions.service'; import { NodeActionsService } from '../../common/services/node-actions.service';
import { NodeInfoDirective } from '../../common/directives/node-info.directive';
import { FilesComponent } from './files.component'; import { FilesComponent } from './files.component';
@@ -79,6 +80,7 @@ describe('FilesComponent', () => {
TimeAgoPipe, TimeAgoPipe,
NodeNameTooltipPipe, NodeNameTooltipPipe,
NodeFavoriteDirective, NodeFavoriteDirective,
NodeInfoDirective,
DocumentListComponent, DocumentListComponent,
FileSizePipe FileSizePipe
], ],

View File

@@ -7,68 +7,69 @@
</div> </div>
<div class="inner-layout__content"> <div class="inner-layout__content">
<div class="inner-layout__panel">
<adf-document-list #documentList
[attr.class]="documentList.isEmpty() ? 'empty-list' : ''"
currentFolderId="-mysites-"
selectionMode="none"
[navigate]="false"
[sorting]="sorting"
[contextMenuActions]="true"
[contentActions]="false"
(sorting-changed)="onSortingChanged($event)"
(node-dblclick)="onNodeDoubleClick($event)">
<adf-document-list #documentList <empty-folder-content>
[attr.class]="documentList.isEmpty() ? 'empty-list' : ''" <ng-template>
currentFolderId="-mysites-" <app-empty-folder
selectionMode="none" icon="group_work"
[navigate]="false" title="APP.BROWSE.LIBRARIES.EMPTY_STATE.TITLE"
[sorting]="sorting" subtitle="APP.BROWSE.LIBRARIES.EMPTY_STATE.TEXT">
[contextMenuActions]="true" </app-empty-folder>
[contentActions]="false"
(sorting-changed)="onSortingChanged($event)"
(node-dblclick)="onNodeDoubleClick($event)">
<empty-folder-content>
<ng-template>
<app-empty-folder
icon="group_work"
title="APP.BROWSE.LIBRARIES.EMPTY_STATE.TITLE"
subtitle="APP.BROWSE.LIBRARIES.EMPTY_STATE.TEXT">
</app-empty-folder>
</ng-template>
</empty-folder-content>
<data-columns>
<data-column
key="$thumbnail"
type="image"
[sortable]="false"
class="image-table-cell">
</data-column>
<data-column
class="adf-data-table-cell--ellipsis__name"
key="title"
title="APP.DOCUMENT_LIST.COLUMNS.TITLE">
<ng-template let-context>
<span class="adf-datatable-cell" title="{{ makeLibraryTooltip(context.row.obj.entry) }}">
{{ makeLibraryTitle(context.row.obj.entry) }}
</span>
</ng-template> </ng-template>
</data-column> </empty-folder-content>
<data-column <data-columns>
key="visibility" <data-column
title="APP.DOCUMENT_LIST.COLUMNS.STATUS"> key="$thumbnail"
<ng-template let-value="value"> type="image"
<span *ngIf="(value == 'PUBLIC')" title="{{ 'APP.SITES_VISIBILITY.PUBLIC' | translate }}"> [sortable]="false"
{{ 'APP.SITES_VISIBILITY.PUBLIC' | translate }} class="image-table-cell">
</span> </data-column>
<span *ngIf="(value == 'PRIVATE')" title="{{ 'APP.SITES_VISIBILITY.PRIVATE' | translate }}">
{{ 'APP.SITES_VISIBILITY.PRIVATE' | translate }}
</span>
<span *ngIf="(value == 'MODERATED')" title="{{ 'APP.SITES_VISIBILITY.MODERATED' | translate }}">
{{ 'APP.SITES_VISIBILITY.MODERATED' | translate }}
</span>
</ng-template>
</data-column>
</data-columns>
</adf-document-list>
<adf-pagination [ngClass]="{ 'no-border' : documentList.isEmpty()}" <data-column
[target]="documentList" class="adf-data-table-cell--ellipsis__name"
(changePageSize)="onChangePageSize($event)"> key="title"
</adf-pagination> title="APP.DOCUMENT_LIST.COLUMNS.TITLE">
<ng-template let-context>
<span class="adf-datatable-cell" title="{{ makeLibraryTooltip(context.row.obj.entry) }}">
{{ makeLibraryTitle(context.row.obj.entry) }}
</span>
</ng-template>
</data-column>
<data-column
key="visibility"
title="APP.DOCUMENT_LIST.COLUMNS.STATUS">
<ng-template let-value="value">
<span *ngIf="(value == 'PUBLIC')" title="{{ 'APP.SITES_VISIBILITY.PUBLIC' | translate }}">
{{ 'APP.SITES_VISIBILITY.PUBLIC' | translate }}
</span>
<span *ngIf="(value == 'PRIVATE')" title="{{ 'APP.SITES_VISIBILITY.PRIVATE' | translate }}">
{{ 'APP.SITES_VISIBILITY.PRIVATE' | translate }}
</span>
<span *ngIf="(value == 'MODERATED')" title="{{ 'APP.SITES_VISIBILITY.MODERATED' | translate }}">
{{ 'APP.SITES_VISIBILITY.MODERATED' | translate }}
</span>
</ng-template>
</data-column>
</data-columns>
</adf-document-list>
<adf-pagination [ngClass]="{ 'no-border' : documentList.isEmpty()}"
[target]="documentList"
(changePageSize)="onChangePageSize($event)">
</adf-pagination>
</div>
</div> </div>
</div> </div>

View File

@@ -33,6 +33,7 @@ export abstract class PageComponent {
isLoading = false; isLoading = false;
isEmpty = true; isEmpty = true;
infoDrawerOpened = false;
paging: NodePaging; paging: NodePaging;
pagination: Pagination; pagination: Pagination;
@@ -204,4 +205,11 @@ export abstract class PageComponent {
return null; return null;
} }
toggleSidebar(event) {
if (event) {
return;
}
this.infoDrawerOpened = !this.infoDrawerOpened;
}
} }

View File

@@ -21,6 +21,13 @@
<mat-icon>get_app</mat-icon> <mat-icon>get_app</mat-icon>
</button> </button>
<button mat-icon-button
[color]="infoDrawerOpened ? 'primary' : 'accent'"
*ngIf="documentList.selection.length"
(click)="toggleSidebar()">
<mat-icon>info_outline</mat-icon>
</button>
<button <button
mat-icon-button mat-icon-button
*ngIf="hasSelection(documentList.selection)" *ngIf="hasSelection(documentList.selection)"
@@ -68,74 +75,88 @@
</div> </div>
<div class="inner-layout__content"> <div class="inner-layout__content">
<div class="inner-layout__panel">
<adf-document-list #documentList
[attr.class]="documentList.isEmpty() ? 'empty-list' : ''"
currentFolderId="-recent-"
selectionMode="multiple"
[navigate]="false"
[sorting]="sorting"
[contextMenuActions]="true"
[contentActions]="false"
[imageResolver]="imageResolver"
(sorting-changed)="onSortingChanged($event)"
(node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)"
(node-select)="onNodeSelect($event, documentList)">
<adf-document-list #documentList <empty-folder-content>
[attr.class]="documentList.isEmpty() ? 'empty-list' : ''" <ng-template>
currentFolderId="-recent-" <app-empty-folder
selectionMode="multiple" icon="access_time"
[navigate]="false" title="APP.BROWSE.RECENT.EMPTY_STATE.TITLE"
[sorting]="sorting" subtitle="APP.BROWSE.RECENT.EMPTY_STATE.TEXT">
[contextMenuActions]="true" </app-empty-folder>
[contentActions]="false"
[imageResolver]="imageResolver"
(sorting-changed)="onSortingChanged($event)"
(node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)"
(node-select)="onNodeSelect($event, documentList)">
<empty-folder-content>
<ng-template>
<app-empty-folder
icon="access_time"
title="APP.BROWSE.RECENT.EMPTY_STATE.TITLE"
subtitle="APP.BROWSE.RECENT.EMPTY_STATE.TEXT">
</app-empty-folder>
</ng-template>
</empty-folder-content>
<data-columns>
<data-column
key="$thumbnail"
type="image"
[sortable]="false"
class="image-table-cell">
</data-column>
<data-column
class="adf-data-table-cell--ellipsis__name"
key="name"
title="APP.DOCUMENT_LIST.COLUMNS.NAME">
<ng-template let-value="value" let-context>
<span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
</ng-template> </ng-template>
</data-column> </empty-folder-content>
<data-column <data-columns>
key="path" <data-column
title="APP.DOCUMENT_LIST.COLUMNS.LOCATION"> key="$thumbnail"
<ng-template let-context> type="image"
<app-location-link [context]="context"></app-location-link> [sortable]="false"
</ng-template> class="image-table-cell">
</data-column> </data-column>
<data-column <data-column
key="content.sizeInBytes" class="adf-data-table-cell--ellipsis__name"
type="fileSize" key="name"
title="APP.DOCUMENT_LIST.COLUMNS.SIZE"> title="APP.DOCUMENT_LIST.COLUMNS.NAME">
</data-column> <ng-template let-value="value" let-context>
<span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
</ng-template>
</data-column>
<data-column <data-column
key="modifiedAt" key="path"
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_ON"> title="APP.DOCUMENT_LIST.COLUMNS.LOCATION">
<ng-template let-value="value"> <ng-template let-context>
<span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span> <app-location-link [context]="context"></app-location-link>
</ng-template> </ng-template>
</data-column> </data-column>
</data-columns>
</adf-document-list> <data-column
<adf-pagination [ngClass]="{'no-border' : documentList.isEmpty()}" key="content.sizeInBytes"
[target]="documentList" type="fileSize"
(changePageSize)="onChangePageSize($event)"> title="APP.DOCUMENT_LIST.COLUMNS.SIZE">
</adf-pagination> </data-column>
<data-column
key="modifiedAt"
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_ON">
<ng-template let-value="value">
<span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span>
</ng-template>
</data-column>
</data-columns>
</adf-document-list>
<adf-pagination [ngClass]="{'no-border' : documentList.isEmpty()}"
[target]="documentList"
(changePageSize)="onChangePageSize($event)">
</adf-pagination>
</div>
<div class="inner-layout__side-panel"
*ngIf="infoDrawerOpened"
[app-node-info]="documentList.selection"
(changed)="toggleSidebar($event)"
#infoInstance=nodeInfo>
<adf-info-drawer title="Details">
<adf-info-drawer-tab label="Properties">
<adf-content-metadata-card [node]="infoInstance.node"></adf-content-metadata-card>
</adf-info-drawer-tab>
</adf-info-drawer>
</div>
</div> </div>
</div> </div>

View File

@@ -41,6 +41,7 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material';
import { DocumentListService } from '@alfresco/adf-content-services'; import { DocumentListService } from '@alfresco/adf-content-services';
import { ContentManagementService } from '../../common/services/content-management.service'; import { ContentManagementService } from '../../common/services/content-management.service';
import { NodeInfoDirective } from '../../common/directives/node-info.directive';
import { RecentFilesComponent } from './recent-files.component'; import { RecentFilesComponent } from './recent-files.component';
@@ -80,6 +81,7 @@ describe('RecentFiles Routed Component', () => {
TimeAgoPipe, TimeAgoPipe,
NodeNameTooltipPipe, NodeNameTooltipPipe,
NodeFavoriteDirective, NodeFavoriteDirective,
NodeInfoDirective,
DocumentListComponent, DocumentListComponent,
RecentFilesComponent RecentFilesComponent
], ],

View File

@@ -21,6 +21,13 @@
<mat-icon>get_app</mat-icon> <mat-icon>get_app</mat-icon>
</button> </button>
<button mat-icon-button
[color]="infoDrawerOpened ? 'primary' : 'accent'"
*ngIf="documentList.selection.length"
(click)="toggleSidebar()">
<mat-icon>info_outline</mat-icon>
</button>
<button <button
mat-icon-button mat-icon-button
*ngIf="hasSelection(documentList.selection)" *ngIf="hasSelection(documentList.selection)"
@@ -77,82 +84,97 @@
</div> </div>
<div class="inner-layout__content"> <div class="inner-layout__content">
<adf-document-list #documentList <div class="inner-layout__panel">
[attr.class]="documentList.isEmpty() ? 'empty-list' : ''" <adf-document-list #documentList
currentFolderId="-sharedlinks-" [attr.class]="documentList.isEmpty() ? 'empty-list' : ''"
selectionMode="multiple" currentFolderId="-sharedlinks-"
[sorting]="sorting" selectionMode="multiple"
[contextMenuActions]="true" [sorting]="sorting"
[contentActions]="false" [contextMenuActions]="true"
(sorting-changed)="onSortingChanged($event)" [contentActions]="false"
(node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)"> (sorting-changed)="onSortingChanged($event)"
(node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)">
<empty-folder-content> <empty-folder-content>
<ng-template> <ng-template>
<app-empty-folder <app-empty-folder
icon="people" icon="people"
title="APP.BROWSE.SHARED.EMPTY_STATE.TITLE" title="APP.BROWSE.SHARED.EMPTY_STATE.TITLE"
subtitle="APP.BROWSE.SHARED.EMPTY_STATE.TEXT"> subtitle="APP.BROWSE.SHARED.EMPTY_STATE.TEXT">
</app-empty-folder> </app-empty-folder>
</ng-template>
</empty-folder-content>
<data-columns>
<data-column
key="$thumbnail"
type="image"
[sortable]="false"
class="image-table-cell">
</data-column>
<data-column
class="adf-data-table-cell--ellipsis__name"
key="name"
title="APP.DOCUMENT_LIST.COLUMNS.NAME">
<ng-template let-value="value" let-context>
<span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
</ng-template> </ng-template>
</data-column> </empty-folder-content>
<data-column <data-columns>
key="path" <data-column
title="APP.DOCUMENT_LIST.COLUMNS.LOCATION"> key="$thumbnail"
<ng-template let-context> type="image"
<app-location-link [context]="context"></app-location-link> [sortable]="false"
</ng-template> class="image-table-cell">
</data-column> </data-column>
<data-column <data-column
key="content.sizeInBytes" class="adf-data-table-cell--ellipsis__name"
title="APP.DOCUMENT_LIST.COLUMNS.SIZE" key="name"
type="fileSize"> title="APP.DOCUMENT_LIST.COLUMNS.NAME">
</data-column> <ng-template let-value="value" let-context>
<span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
</ng-template>
</data-column>
<data-column <data-column
key="modifiedAt" key="path"
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_ON"> title="APP.DOCUMENT_LIST.COLUMNS.LOCATION">
<ng-template let-value="value"> <ng-template let-context>
<span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span> <app-location-link [context]="context"></app-location-link>
</ng-template> </ng-template>
</data-column> </data-column>
<data-column <data-column
class="adf-data-table-cell--ellipsis" key="content.sizeInBytes"
key="modifiedByUser.displayName" title="APP.DOCUMENT_LIST.COLUMNS.SIZE"
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_BY"> type="fileSize">
</data-column> </data-column>
<data-column <data-column
class="adf-data-table-cell--ellipsis" key="modifiedAt"
key="sharedByUser.displayName" title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_ON">
title="APP.DOCUMENT_LIST.COLUMNS.SHARED_BY"> <ng-template let-value="value">
</data-column> <span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span>
</ng-template>
</data-column>
</data-columns> <data-column
</adf-document-list> class="adf-data-table-cell--ellipsis"
<adf-pagination [ngClass]="{ 'no-border' :documentList.isEmpty()}" key="modifiedByUser.displayName"
[target]="documentList" title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_BY">
(changePageSize)="onChangePageSize($event)"> </data-column>
</adf-pagination>
<data-column
class="adf-data-table-cell--ellipsis"
key="sharedByUser.displayName"
title="APP.DOCUMENT_LIST.COLUMNS.SHARED_BY">
</data-column>
</data-columns>
</adf-document-list>
<adf-pagination [ngClass]="{ 'no-border' :documentList.isEmpty()}"
[target]="documentList"
(changePageSize)="onChangePageSize($event)">
</adf-pagination>
</div>
<div class="inner-layout__side-panel"
*ngIf="infoDrawerOpened"
[app-node-info]="documentList.selection"
(changed)="toggleSidebar($event)"
#infoInstance=nodeInfo>
<adf-info-drawer title="Details">
<adf-info-drawer-tab label="Properties">
<adf-content-metadata-card [node]="infoInstance.node"></adf-content-metadata-card>
</adf-info-drawer-tab>
</adf-info-drawer>
</div>
</div> </div>
</div> </div>

View File

@@ -41,6 +41,7 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material';
import { DocumentListService } from '@alfresco/adf-content-services'; import { DocumentListService } from '@alfresco/adf-content-services';
import { ContentManagementService } from '../../common/services/content-management.service'; import { ContentManagementService } from '../../common/services/content-management.service';
import { NodeInfoDirective } from '../../common/directives/node-info.directive';
import { SharedFilesComponent } from './shared-files.component'; import { SharedFilesComponent } from './shared-files.component';
@@ -79,6 +80,7 @@ describe('SharedFilesComponent', () => {
TimeAgoPipe, TimeAgoPipe,
NodeNameTooltipPipe, NodeNameTooltipPipe,
NodeFavoriteDirective, NodeFavoriteDirective,
NodeInfoDirective,
DocumentListComponent, DocumentListComponent,
SharedFilesComponent SharedFilesComponent
], ],

View File

@@ -25,80 +25,81 @@
</div> </div>
<div class="inner-layout__content"> <div class="inner-layout__content">
<div class="inner-layout__panel">
<adf-document-list #documentList
[attr.class]="documentList.isEmpty() ? 'empty-list' : ''"
currentFolderId="-trashcan-"
selectionMode="multiple"
[navigate]="false"
[sorting]="sorting"
[contextMenuActions]="true"
[contentActions]="false"
(sorting-changed)="onSortingChanged($event)">
<adf-document-list #documentList <empty-folder-content>
[attr.class]="documentList.isEmpty() ? 'empty-list' : ''" <ng-template>
currentFolderId="-trashcan-" <app-empty-folder
selectionMode="multiple" icon="delete"
[navigate]="false" title="APP.BROWSE.TRASHCAN.EMPTY_STATE.TITLE">
[sorting]="sorting" <p class="app-empty-folder__text">{{ 'APP.BROWSE.TRASHCAN.EMPTY_STATE.FIRST_TEXT' | translate }}</p>
[contextMenuActions]="true" <p class="app-empty-folder__text">{{ 'APP.BROWSE.TRASHCAN.EMPTY_STATE.SECOND_TEXT' | translate }}</p>
[contentActions]="false" </app-empty-folder>
(sorting-changed)="onSortingChanged($event)">
<empty-folder-content>
<ng-template>
<app-empty-folder
icon="delete"
title="APP.BROWSE.TRASHCAN.EMPTY_STATE.TITLE">
<p class="app-empty-folder__text">{{ 'APP.BROWSE.TRASHCAN.EMPTY_STATE.FIRST_TEXT' | translate }}</p>
<p class="app-empty-folder__text">{{ 'APP.BROWSE.TRASHCAN.EMPTY_STATE.SECOND_TEXT' | translate }}</p>
</app-empty-folder>
</ng-template>
</empty-folder-content>
<data-columns>
<data-column
key="$thumbnail"
type="image"
[sortable]="false"
class="image-table-cell">
</data-column>
<data-column
class="adf-data-table-cell--ellipsis__name"
key="name"
title="APP.DOCUMENT_LIST.COLUMNS.NAME">
<ng-template let-value="value" let-context>
<span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
</ng-template> </ng-template>
</data-column> </empty-folder-content>
<data-column <data-columns>
key="path"
title="APP.DOCUMENT_LIST.COLUMNS.LOCATION">
<ng-template let-context>
<app-location-link [context]="context"></app-location-link>
</ng-template>
</data-column>
<data-column <data-column
key="content.sizeInBytes" key="$thumbnail"
title="APP.DOCUMENT_LIST.COLUMNS.SIZE" type="image"
type="fileSize"> [sortable]="false"
</data-column> class="image-table-cell">
</data-column>
<data-column <data-column
key="archivedAt" class="adf-data-table-cell--ellipsis__name"
title="APP.DOCUMENT_LIST.COLUMNS.DELETED_ON"> key="name"
<ng-template let-value="value"> title="APP.DOCUMENT_LIST.COLUMNS.NAME">
<span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span> <ng-template let-value="value" let-context>
</ng-template> <span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
</data-column> </ng-template>
</data-column>
<data-column <data-column
class="adf-data-table-cell--ellipsis" key="path"
key="archivedByUser.displayName" title="APP.DOCUMENT_LIST.COLUMNS.LOCATION">
title="APP.DOCUMENT_LIST.COLUMNS.DELETED_BY"> <ng-template let-context>
</data-column> <app-location-link [context]="context"></app-location-link>
</ng-template>
</data-column>
</data-columns> <data-column
key="content.sizeInBytes"
title="APP.DOCUMENT_LIST.COLUMNS.SIZE"
type="fileSize">
</data-column>
</adf-document-list> <data-column
<adf-pagination [ngClass]="{ 'no-border' : documentList.isEmpty()}" key="archivedAt"
[target]="documentList" title="APP.DOCUMENT_LIST.COLUMNS.DELETED_ON">
(changePageSize)="onChangePageSize($event)"> <ng-template let-value="value">
</adf-pagination> <span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span>
</ng-template>
</data-column>
<data-column
class="adf-data-table-cell--ellipsis"
key="archivedByUser.displayName"
title="APP.DOCUMENT_LIST.COLUMNS.DELETED_BY">
</data-column>
</data-columns>
</adf-document-list>
<adf-pagination [ngClass]="{ 'no-border' : documentList.isEmpty()}"
[target]="documentList"
(changePageSize)="onChangePageSize($event)">
</adf-pagination>
</div>
</div> </div>
</div> </div>

View File

@@ -41,6 +41,7 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material';
import { DocumentListService } from '@alfresco/adf-content-services'; import { DocumentListService } from '@alfresco/adf-content-services';
import { ContentManagementService } from '../../common/services/content-management.service'; import { ContentManagementService } from '../../common/services/content-management.service';
import { NodeInfoDirective } from '../../common/directives/node-info.directive';
import { TrashcanComponent } from './trashcan.component'; import { TrashcanComponent } from './trashcan.component';
@@ -76,6 +77,7 @@ describe('TrashcanComponent', () => {
TimeAgoPipe, TimeAgoPipe,
NodeNameTooltipPipe, NodeNameTooltipPipe,
NodeFavoriteDirective, NodeFavoriteDirective,
NodeInfoDirective,
DocumentListComponent, DocumentListComponent,
TrashcanComponent TrashcanComponent
], ],

View File

@@ -29,19 +29,25 @@ $app-inner-layout--footer-height: 48px;
} }
.content--hide { .content--hide {
display: none; display: none !important;
} }
} }
.inner-layout { .inner-layout {
.no-border {
border: unset
}
display: flex; display: flex;
flex: 1; flex: 1;
flex-direction: column; flex-direction: column;
.adf-info-drawer {
width: 350px;
height: 100%;
overflow-y: auto;
}
.no-border {
border: unset
}
&--scroll { &--scroll {
overflow: auto; overflow: auto;
} }
@@ -62,12 +68,27 @@ $app-inner-layout--footer-height: 48px;
&__content { &__content {
display: flex; display: flex;
flex-direction: column; flex-direction: row;
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
background: #fff; background: #fff;
} }
&__panel {
width: 100%;
height: 100%;
display: flex;
flex:1;
flex-direction: column;
border-right: 1px solid rgba(0, 0, 0, 0.07);
}
&__side-panel {
display: flex;
width: 350px;
height: 100%;
}
&__content--scroll { &__content--scroll {
overflow: auto; overflow: auto;
} }

View File

@@ -26,3 +26,4 @@ app-root > ng-component {
@import './overrides/alfresco-upload-dialog'; @import './overrides/alfresco-upload-dialog';
@import './overrides/toolbar'; @import './overrides/toolbar';
@import './overrides/breadcrumb'; @import './overrides/breadcrumb';
@import './overrides/adf-info-drawer';

View File

@@ -0,0 +1,3 @@
.adf-info-drawer-layout {
height: 100%;
}

View File

@@ -35,6 +35,7 @@ adf-upload-drag-area:first-child {
adf-upload-drag-area { adf-upload-drag-area {
height: 100%; height: 100%;
width: 100%;
& > div { & > div {
height: 100%; height: 100%;

View File

@@ -4,8 +4,7 @@
// TODO: review and remove once ADF 2.0.0 is out // TODO: review and remove once ADF 2.0.0 is out
&.inline { &.inline {
.mat-toolbar { .mat-toolbar {
border-left: none !important; border: none !important;
border-right: none !important;
background: $alfresco-gray-background; background: $alfresco-gray-background;
padding: 0; padding: 0;
height: 48px; height: 48px;