diff --git a/docs/sites-dropdown.component.md b/docs/sites-dropdown.component.md index 8c4969a61f..93e7c7130e 100644 --- a/docs/sites-dropdown.component.md +++ b/docs/sites-dropdown.component.md @@ -29,6 +29,7 @@ Displays a dropdown menu to show and interact with the sites of the current user | Attribute | Type | Default | Description | | --- | --- | --- | --- | | hideMyFiles | boolean | false | Hide the "My Files" option added to the list by default | +| siteList | any[] | null | A custom list of sites to be displayed by the dropdown. If no value is given, the sites of the current user are displayed by default. A list of objects only with properties 'title' and 'guid' is enough to be able to display the dropdown. | ### Events diff --git a/lib/content-services/content-node-selector/content-node-selector.component.html b/lib/content-services/content-node-selector/content-node-selector.component.html index 536dbe4598..81145d2431 100644 --- a/lib/content-services/content-node-selector/content-node-selector.component.html +++ b/lib/content-services/content-node-selector/content-node-selector.component.html @@ -28,6 +28,8 @@ @@ -60,6 +62,7 @@ [allowDropFiles]="false" (folderChange)="onFolderChange()" (ready)="onFolderLoaded($event)" + (node-dblclick)="onNodeDoubleClick($event)" data-automation-id="content-node-selector-document-list"> diff --git a/lib/content-services/content-node-selector/content-node-selector.component.spec.ts b/lib/content-services/content-node-selector/content-node-selector.component.spec.ts index 4fe118d325..886c6ae49b 100644 --- a/lib/content-services/content-node-selector/content-node-selector.component.spec.ts +++ b/lib/content-services/content-node-selector/content-node-selector.component.spec.ts @@ -20,7 +20,7 @@ import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; import { By } from '@angular/platform-browser'; import { MinimalNodeEntryEntity } from 'alfresco-js-api'; -import { ContentService, TranslationService, SearchService, SiteModel, SitesApiService, UserPreferencesService } from '@alfresco/adf-core'; +import { AlfrescoApiService, ContentService, TranslationService, SearchService, SiteModel, SitesApiService, UserPreferencesService } from '@alfresco/adf-core'; import { DataTableModule } from '@alfresco/adf-core'; import { Observable } from 'rxjs/Rx'; import { MaterialModule } from '../material.module'; @@ -83,6 +83,7 @@ describe('ContentNodeSelectorComponent', () => { ContentNodeSelectorComponent ], providers: [ + AlfrescoApiService, ContentService, SitesApiService, TranslationService, @@ -173,13 +174,13 @@ describe('ContentNodeSelectorComponent', () => { }); it('should be shown if dialogRef is injected', () => { - const componentInstance = new ContentNodeSelectorComponent(null, null, fakePreference, data, dummyMdDialogRef); + const componentInstance = new ContentNodeSelectorComponent(null, null, null, fakePreference, data, dummyMdDialogRef); expect(componentInstance.inDialog).toBeTruthy(); }); it('should should call the close method in the injected dialogRef', () => { spyOn(dummyMdDialogRef, 'close'); - const componentInstance = new ContentNodeSelectorComponent(null, null, fakePreference, data, dummyMdDialogRef); + const componentInstance = new ContentNodeSelectorComponent(null, null, null, fakePreference, data, dummyMdDialogRef); componentInstance.close(); diff --git a/lib/content-services/content-node-selector/content-node-selector.component.ts b/lib/content-services/content-node-selector/content-node-selector.component.ts index 51a38fae61..18705a3672 100644 --- a/lib/content-services/content-node-selector/content-node-selector.component.ts +++ b/lib/content-services/content-node-selector/content-node-selector.component.ts @@ -16,7 +16,7 @@ */ import { Component, EventEmitter, Inject, Input, OnInit, Optional, Output, ViewChild, ViewEncapsulation } from '@angular/core'; -import { ContentService, HighlightDirective, SiteModel, UserPreferencesService } from '@alfresco/adf-core'; +import { AlfrescoApiService, ContentService, HighlightDirective, SiteModel, UserPreferencesService } from '@alfresco/adf-core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; import { MinimalNodeEntryEntity, NodePaging, Pagination } from 'alfresco-js-api'; import { DocumentListComponent, PaginationStrategy } from '../document-list/components/document-list.component'; @@ -28,6 +28,8 @@ import { ContentNodeSelectorService } from './content-node-selector.service'; export interface ContentNodeSelectorComponentData { title: string; currentFolderId?: string; + dropdownHideMyFiles?: boolean; + dropdownSiteList?: any[]; rowFilter?: RowFilter; imageResolver?: ImageResolver; select: EventEmitter; @@ -60,6 +62,12 @@ export class ContentNodeSelectorComponent implements OnInit { @Input() currentFolderId: string | null = null; + @Input() + dropdownHideMyFiles: boolean = false; + + @Input() + dropdownSiteList: any[] = null; + @Input() rowFilter: RowFilter = null; @@ -80,6 +88,7 @@ export class ContentNodeSelectorComponent implements OnInit { constructor(private contentNodeSelectorService: ContentNodeSelectorService, private contentService: ContentService, + private apiService: AlfrescoApiService, private preferences: UserPreferencesService, @Optional() @Inject(MAT_DIALOG_DATA) data?: ContentNodeSelectorComponentData, @Optional() private containingDialog?: MatDialogRef) { @@ -87,6 +96,8 @@ export class ContentNodeSelectorComponent implements OnInit { this.title = data.title; this.select = data.select; this.currentFolderId = data.currentFolderId; + this.dropdownHideMyFiles = data.dropdownHideMyFiles; + this.dropdownSiteList = data.dropdownSiteList; this.rowFilter = data.rowFilter; this.imageResolver = data.imageResolver; } @@ -295,4 +306,21 @@ export class ContentNodeSelectorComponent implements OnInit { close(): void { this.containingDialog.close(); } + + onNodeDoubleClick(e: CustomEvent) { + const node: any = e.detail.node.entry; + + if (node && node.guid) { + const options = { + maxItems: this.pageSize, + skipCount: this.skipCount, + include: ['path', 'properties', 'allowableOperations'] + }; + + this.apiService.nodesApi.getNode(node.guid, options) + .then(documentLibrary => { + this.documentList.performCustomSourceNavigation(documentLibrary); + }); + } + } } diff --git a/lib/content-services/document-list/components/document-list.component.ts b/lib/content-services/document-list/components/document-list.component.ts index 0377e70133..542e5ef471 100644 --- a/lib/content-services/document-list/components/document-list.component.ts +++ b/lib/content-services/document-list/components/document-list.component.ts @@ -287,7 +287,7 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni if (this.folderNode) { this.loadFolder(merge); } else if (this.currentFolderId) { - this.loadFolderByNodeId(this.currentFolderId); + this.loadFolderByNodeId(this.currentFolderId, merge); } else if (this.node) { this.data.loadPage(this.node); this.ready.emit(this.node); @@ -376,17 +376,29 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni performNavigation(node: MinimalNodeEntity): boolean { if (this.canNavigateFolder(node)) { - this.currentFolderId = node.entry.id; - this.folderNode = node.entry; - this.skipCount = 0; - this.currentNodeAllowableOperations = node.entry['allowableOperations'] ? node.entry['allowableOperations'] : []; - this.loadFolder(); - this.folderChange.emit(new NodeEntryEvent(node.entry)); + this.updateFolderData(node); return true; } return false; } + performCustomSourceNavigation(node: MinimalNodeEntity): boolean { + if (this.isCustomSource(this.currentFolderId)) { + this.updateFolderData(node); + return true; + } + return false; + } + + updateFolderData(node: MinimalNodeEntity): void { + this.currentFolderId = node.entry.id; + this.folderNode = node.entry; + this.skipCount = 0; + this.currentNodeAllowableOperations = node.entry['allowableOperations'] ? node.entry['allowableOperations'] : []; + this.loadFolder(); + this.folderChange.emit(new NodeEntryEvent(node.entry)); + } + /** * Invoked when executing content action for a document or folder. * @param node Node to be the context of the execution. @@ -418,28 +430,32 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni } let nodeId = this.folderNode ? this.folderNode.id : this.currentFolderId; + + if (!this.hasCustomLayout) { + this.setupDefaultColumns(nodeId); + } if (nodeId) { this.loadFolderNodesByFolderNodeId(nodeId, this.maxItems, this.skipCount, merge).catch(err => this.error.emit(err)); } } // gets folder node and its content - loadFolderByNodeId(nodeId: string) { + loadFolderByNodeId(nodeId: string, merge: boolean = false) { this.loading = true; this.resetSelection(); if (nodeId === '-trashcan-') { - this.loadTrashcan(); + this.loadTrashcan(merge); } else if (nodeId === '-sharedlinks-') { - this.loadSharedLinks(); + this.loadSharedLinks(merge); } else if (nodeId === '-sites-') { - this.loadSites(); + this.loadSites(merge); } else if (nodeId === '-mysites-') { - this.loadMemberSites(); + this.loadMemberSites(merge); } else if (nodeId === '-favorites-') { - this.loadFavorites(); + this.loadFavorites(merge); } else if (nodeId === '-recent-') { - this.loadRecent(); + this.loadRecent(merge); } else { this.documentListService .getFolderNode(nodeId) @@ -448,7 +464,7 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni this.currentFolderId = node.id; this.skipCount = 0; this.currentNodeAllowableOperations = node['allowableOperations'] ? node['allowableOperations'] : []; - return this.loadFolderNodesByFolderNodeId(node.id, this.maxItems, this.skipCount); + return this.loadFolderNodesByFolderNodeId(node.id, this.maxItems, this.skipCount, merge); }) .catch(err => { if (JSON.parse(err.message).error.statusCode === 403) { @@ -502,29 +518,29 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni changePage.maxItems.currentValue !== changePage.maxItems.previousValue; } - private loadTrashcan(): void { + private loadTrashcan(merge: boolean = false): void { const options = { include: ['path', 'properties'], maxItems: this.maxItems, skipCount: this.skipCount }; this.apiService.nodesApi.getDeletedNodes(options) - .then((page: DeletedNodesPaging) => this.onPageLoaded(page)) + .then((page: DeletedNodesPaging) => this.onPageLoaded(page, merge)) .catch(error => this.error.emit(error)); } - private loadSharedLinks(): void { + private loadSharedLinks(merge: boolean = false): void { const options = { include: ['properties', 'allowableOperations', 'path'], maxItems: this.maxItems, skipCount: this.skipCount }; this.apiService.sharedLinksApi.findSharedLinks(options) - .then((page: NodePaging) => this.onPageLoaded(page)) + .then((page: NodePaging) => this.onPageLoaded(page, merge)) .catch(error => this.error.emit(error)); } - private loadSites(): void { + private loadSites(merge: boolean = false): void { const options = { include: ['properties'], maxItems: this.maxItems, @@ -532,11 +548,11 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni }; this.apiService.sitesApi.getSites(options) - .then((page: NodePaging) => this.onPageLoaded(page)) + .then((page: NodePaging) => this.onPageLoaded(page, merge)) .catch(error => this.error.emit(error)); } - private loadMemberSites(): void { + private loadMemberSites(merge: boolean = false): void { const options = { include: ['properties'], maxItems: this.maxItems, @@ -548,19 +564,22 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni let page: NodePaging = { list: { entries: result.list.entries - .map(({ entry: { site } }: any) => ({ - entry: site - })), + .map(({entry: {site}}: any) => { + site.allowableOperations = site.allowableOperations ? site.allowableOperations : [this.CREATE_PERMISSION]; + return { + entry: site + }; + }), pagination: result.list.pagination } }; - this.onPageLoaded(page); + this.onPageLoaded(page, merge); }) .catch(error => this.error.emit(error)); } - private loadFavorites(): void { + private loadFavorites(merge: boolean = false): void { const options = { maxItems: this.maxItems, skipCount: this.skipCount, @@ -586,12 +605,12 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni pagination: result.list.pagination } }; - this.onPageLoaded(page); + this.onPageLoaded(page, merge); }) .catch(error => this.error.emit(error)); } - private loadRecent(): void { + private loadRecent(merge: boolean = false): void { this.apiService.peopleApi.getPerson('-me-') .then((person: PersonEntry) => { const username = person.entry.id; @@ -619,13 +638,13 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni return this.apiService.searchApi.search(query); }) - .then((page: NodePaging) => this.onPageLoaded(page)) + .then((page: NodePaging) => this.onPageLoaded(page, merge)) .catch(error => this.error.emit(error)); } - private onPageLoaded(page: NodePaging) { + private onPageLoaded(page: NodePaging, merge: boolean = false) { if (page) { - this.data.loadPage(page); + this.data.loadPage(page, merge); this.loading = false; this.ready.emit(page); } diff --git a/lib/content-services/site-dropdown/sites-dropdown.component.html b/lib/content-services/site-dropdown/sites-dropdown.component.html index d15d07f12c..64978c7eae 100644 --- a/lib/content-services/site-dropdown/sites-dropdown.component.html +++ b/lib/content-services/site-dropdown/sites-dropdown.component.html @@ -10,7 +10,7 @@ (ngModelChange)="selectedSite()"> {{'DROPDOWN.MY_FILES_OPTION' | translate}} - {{ site.title }} + {{ site.title | translate }} diff --git a/lib/content-services/site-dropdown/sites-dropdown.component.ts b/lib/content-services/site-dropdown/sites-dropdown.component.ts index 243ad63799..f9dc01e91a 100644 --- a/lib/content-services/site-dropdown/sites-dropdown.component.ts +++ b/lib/content-services/site-dropdown/sites-dropdown.component.ts @@ -28,22 +28,22 @@ export class DropdownSitesComponent implements OnInit { @Input() hideMyFiles: boolean = false; + @Input() + siteList: any[] = null; + @Output() change: EventEmitter = new EventEmitter(); public MY_FILES_VALUE = 'default'; - siteList = []; - public siteSelected: string; constructor(private sitesService: SitesApiService) {} ngOnInit() { - this.sitesService.getSites().subscribe((result) => { - this.siteList = result; - }, - (error) => {}); + if (!this.siteList) { + this.setDefaultSiteList(); + } } selectedSite() { @@ -56,4 +56,12 @@ export class DropdownSitesComponent implements OnInit { this.change.emit(siteFound); } + setDefaultSiteList() { + this.siteList = []; + this.sitesService.getSites().subscribe((result) => { + this.siteList = result; + }, + (error) => {}); + } + }