mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-12 17:04:46 +00:00
[ACA-20] Favorite Libraries (#789)
* libraries submenu config * fix item id * favorite libraries columns * libraries submenu text * columns text * submenu schema * submenu routes * role column component * favorite libraries list api * register favorite libraries presets * favorite libraries list component * register role column component * dl custom node list is library route * empty state message icon * remove custom id * merge subscriptions * adapt to child route * fix component selector * revert to favorite library route * sidenav main links font weight * libraries children contants * library expand panel method * update e2e * libraries children columns consistency * isLibrary workaround for custom node list * update isLibrary evaluator * update e2e * lint * Update src/assets/app.extensions.json Co-Authored-By: pionnegru <pionnegru@users.noreply.github.com> * Update src/app/extensions/extension.service.ts Co-Authored-By: pionnegru <pionnegru@users.noreply.github.com> * Update src/app/extensions/extension.service.ts Co-Authored-By: pionnegru <pionnegru@users.noreply.github.com> * Update src/app/extensions/extension.service.ts Co-Authored-By: pionnegru <pionnegru@users.noreply.github.com> * Update src/app/extensions/extension.service.ts Co-Authored-By: pionnegru <pionnegru@users.noreply.github.com> * use correct preset * update e2e * update page titles values * find child active link * fix expected value * update expected * role column tests * check if menu is expanded
This commit is contained in:
parent
76fe33d734
commit
4a420cc9f9
@ -23,7 +23,7 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ElementFinder, ElementArrayFinder, by } from 'protractor';
|
||||
import { ElementFinder, ElementArrayFinder, by, element } from 'protractor';
|
||||
import { Menu } from '../menu/menu';
|
||||
import { Component } from '../component';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
@ -33,6 +33,8 @@ export class Sidenav extends Component {
|
||||
root: 'app-sidenav',
|
||||
link: '.menu__item',
|
||||
label: '.item--label',
|
||||
expansion_panel: ".mat-expansion-panel-header",
|
||||
expansion_panel_content: ".mat-expansion-panel-body",
|
||||
activeLink: '.item--active',
|
||||
newButton: '[data-automation-id="create-button"]'
|
||||
};
|
||||
@ -64,6 +66,12 @@ export class Sidenav extends Component {
|
||||
return className.includes(Sidenav.selectors.activeLink.replace('.', ''));
|
||||
}
|
||||
|
||||
async childIsActiveByLabel(label: string) {
|
||||
const labelElement = await this.getLinkByLabel(label).element(by.css('span'));
|
||||
return (await labelElement.getAttribute('class'))
|
||||
.includes(Sidenav.selectors.activeLink.replace('.', ''));
|
||||
}
|
||||
|
||||
getLink(label: string) {
|
||||
return this.component.element(by.cssContainingText(Sidenav.selectors.link, label));
|
||||
}
|
||||
@ -84,7 +92,24 @@ export class Sidenav extends Component {
|
||||
return await link.click();
|
||||
|
||||
} catch (e){
|
||||
console.log('---- sidebar navigation catch : ', e);
|
||||
console.log('---- sidebar navigation catch navigateToLinkByLabel: ', e);
|
||||
}
|
||||
}
|
||||
|
||||
async expandMenu(label: string) {
|
||||
try{
|
||||
|
||||
if (await element(by.cssContainingText('.mat-expanded', label)).isPresent()) {
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
const link = this.getLinkByLabel(label);
|
||||
await Utils.waitUntilElementClickable(link);
|
||||
await link.click();
|
||||
await element(by.css(Sidenav.selectors.expansion_panel_content)).isPresent();
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.log('---- sidebar navigation catch expandMenu: ', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ export const E2E_ROOT_PATH = __dirname;
|
||||
// Application Routes
|
||||
export const APP_ROUTES = {
|
||||
FAVORITES: '/favorites',
|
||||
FILE_LIBRARIES: '/libraries',
|
||||
MY_LIBRARIES: '/libraries',
|
||||
LOGIN: '/login',
|
||||
LOGOUT: '/logout',
|
||||
PERSONAL_FILES: '/personal-files',
|
||||
@ -58,6 +58,8 @@ export const APP_ROUTES = {
|
||||
export const SIDEBAR_LABELS = {
|
||||
PERSONAL_FILES: 'Personal Files',
|
||||
FILE_LIBRARIES: 'File Libraries',
|
||||
MY_LIBRARIES: 'My Libraries',
|
||||
FAVORITE_LIBRARIES: 'Favorite Libraries',
|
||||
SHARED_FILES: 'Shared',
|
||||
RECENT_FILES: 'Recent Files',
|
||||
FAVORITES: 'Favorites',
|
||||
@ -67,7 +69,8 @@ export const SIDEBAR_LABELS = {
|
||||
// Page titles
|
||||
export const PAGE_TITLES = {
|
||||
VIEWER: 'Preview',
|
||||
SEARCH: 'Search Results'
|
||||
SEARCH: 'Search Results',
|
||||
MY_LIBRARIES: 'File Libraries'
|
||||
};
|
||||
|
||||
// Site visibility
|
||||
|
@ -53,12 +53,14 @@ export class BrowsingPage extends Page {
|
||||
|
||||
|
||||
async clickFileLibrariesAndWait() {
|
||||
await this.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES);
|
||||
await this.sidenav.expandMenu(SIDEBAR_LABELS.FILE_LIBRARIES);
|
||||
await this.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.MY_LIBRARIES);
|
||||
await this.dataTable.waitForHeader();
|
||||
}
|
||||
|
||||
async clickFileLibraries() {
|
||||
await this.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES);
|
||||
await this.sidenav.expandMenu(SIDEBAR_LABELS.FILE_LIBRARIES);
|
||||
await this.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.MY_LIBRARIES);
|
||||
}
|
||||
|
||||
|
||||
|
@ -81,10 +81,12 @@ describe('Page titles', () => {
|
||||
});
|
||||
|
||||
it('File Libraries page - [C217158]', async () => {
|
||||
const label = SIDEBAR_LABELS.FILE_LIBRARIES;
|
||||
const parent = SIDEBAR_LABELS.FILE_LIBRARIES;
|
||||
const label = SIDEBAR_LABELS.MY_LIBRARIES;
|
||||
|
||||
await page.sidenav.expandMenu(parent);
|
||||
await page.sidenav.navigateToLinkByLabel(label);
|
||||
expect(await browser.getTitle()).toContain(label);
|
||||
expect(await browser.getTitle()).toContain(PAGE_TITLES.MY_LIBRARIES);
|
||||
});
|
||||
|
||||
it('Shared Files page - [C217159]', async () => {
|
||||
|
@ -80,10 +80,10 @@ describe('File Libraries', () => {
|
||||
});
|
||||
|
||||
it('has the correct columns - [C217095]', async () => {
|
||||
const labels = [ 'Title', 'Visibility' ];
|
||||
const labels = [ 'Name', 'My Role', 'Visibility' ];
|
||||
const elements = labels.map(label => dataTable.getColumnHeaderByLabel(label));
|
||||
|
||||
expect(await dataTable.getColumnHeaders().count()).toBe(2 + 1, 'Incorrect number of columns');
|
||||
expect(await dataTable.getColumnHeaders().count()).toBe(3 + 1, 'Incorrect number of columns');
|
||||
|
||||
await elements.forEach(async (element, index) => {
|
||||
expect(await element.isPresent()).toBe(true, `"${labels[index]}" is missing`);
|
||||
@ -106,7 +106,7 @@ describe('File Libraries', () => {
|
||||
return row.all(dataTable.cell).map(async cell => await cell.getText());
|
||||
});
|
||||
const sitesList = rowCells.reduce((acc, cell) => {
|
||||
acc[cell[1]] = cell[2].toUpperCase();
|
||||
acc[cell[1]] = cell[3].toUpperCase();
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
|
@ -45,8 +45,8 @@ describe('Sidebar', () => {
|
||||
|
||||
it('navigates to "File Libraries" - [C217150]', async () => {
|
||||
await page.clickFileLibraries();
|
||||
expect(await browser.getCurrentUrl()).toContain(APP_ROUTES.FILE_LIBRARIES);
|
||||
expect(await sidenav.isActiveByLabel(SIDEBAR_LABELS.FILE_LIBRARIES)).toBe(true);
|
||||
expect(await browser.getCurrentUrl()).toContain(APP_ROUTES.MY_LIBRARIES);
|
||||
expect(await sidenav.childIsActiveByLabel(SIDEBAR_LABELS.MY_LIBRARIES)).toBe(true);
|
||||
});
|
||||
|
||||
it('navigates to "Personal Files" - [C280409]', async () => {
|
||||
|
@ -202,7 +202,35 @@
|
||||
"children": {
|
||||
"description": "Navigation children items",
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/navBarLinkRef" },
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"title",
|
||||
"route"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Unique identifier",
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"description": "Element title",
|
||||
"type": "string"
|
||||
},
|
||||
"route": {
|
||||
"description": "Route reference identifier",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"not": {
|
||||
"required": ["children"]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"rules": {
|
||||
|
@ -44,6 +44,7 @@ import { APP_ROUTES } from './app.routes';
|
||||
|
||||
import { FilesComponent } from './components/files/files.component';
|
||||
import { LibrariesComponent } from './components/libraries/libraries.component';
|
||||
import { FavoriteLibrariesComponent } from './components/favorite-libraries/favorite-libraries.component';
|
||||
import { NodeVersionsDialogComponent } from './dialogs/node-versions/node-versions.dialog';
|
||||
import { LibraryDialogComponent } from './dialogs/library/library.dialog';
|
||||
|
||||
@ -107,6 +108,7 @@ import { environment } from '../environments/environment';
|
||||
AppComponent,
|
||||
FilesComponent,
|
||||
LibrariesComponent,
|
||||
FavoriteLibrariesComponent,
|
||||
NodeVersionsDialogComponent,
|
||||
LibraryDialogComponent
|
||||
],
|
||||
|
@ -27,6 +27,7 @@ import { Routes } from '@angular/router';
|
||||
import { AppLayoutComponent } from './components/layout/app-layout/app-layout.component';
|
||||
import { FilesComponent } from './components/files/files.component';
|
||||
import { LibrariesComponent } from './components/libraries/libraries.component';
|
||||
import { FavoriteLibrariesComponent } from './components/favorite-libraries/favorite-libraries.component';
|
||||
import { GenericErrorComponent } from './components/common/generic-error/generic-error.component';
|
||||
import { SearchResultsComponent } from './components/search/search-results/search-results.component';
|
||||
import { SearchLibrariesResultsComponent } from './components/search/search-libraries-results/search-libraries-results.component';
|
||||
@ -105,6 +106,14 @@ export const APP_ROUTES: Routes = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'favorite/libraries',
|
||||
component: FavoriteLibrariesComponent,
|
||||
data: {
|
||||
title: 'APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.TITLE',
|
||||
sortingPreferenceKey: 'favorite-libraries'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'personal-files',
|
||||
data: {
|
||||
|
@ -31,6 +31,7 @@ import { LocationLinkComponent } from './location-link/location-link.component';
|
||||
import { NameColumnComponent } from './name-column/name-column.component';
|
||||
import { LibraryNameColumnComponent } from './library-name-column/library-name-column.component';
|
||||
import { LibraryStatusColumnComponent } from './library-status-column/library-status-column.component';
|
||||
import { LibraryRoleColumnComponent } from './library-role-column/library-role-column.component';
|
||||
import { TrashcanNameColumnComponent } from './trashcan-name-column/trashcan-name-column.component';
|
||||
import { DynamicColumnComponent } from './dynamic-column/dynamic-column.component';
|
||||
|
||||
@ -42,6 +43,7 @@ import { DynamicColumnComponent } from './dynamic-column/dynamic-column.componen
|
||||
NameColumnComponent,
|
||||
LibraryNameColumnComponent,
|
||||
LibraryStatusColumnComponent,
|
||||
LibraryRoleColumnComponent,
|
||||
TrashcanNameColumnComponent,
|
||||
DynamicColumnComponent
|
||||
],
|
||||
@ -51,6 +53,7 @@ import { DynamicColumnComponent } from './dynamic-column/dynamic-column.componen
|
||||
NameColumnComponent,
|
||||
LibraryNameColumnComponent,
|
||||
LibraryStatusColumnComponent,
|
||||
LibraryRoleColumnComponent,
|
||||
TrashcanNameColumnComponent,
|
||||
DynamicColumnComponent
|
||||
],
|
||||
@ -59,6 +62,7 @@ import { DynamicColumnComponent } from './dynamic-column/dynamic-column.componen
|
||||
NameColumnComponent,
|
||||
LibraryNameColumnComponent,
|
||||
LibraryStatusColumnComponent,
|
||||
LibraryRoleColumnComponent,
|
||||
TrashcanNameColumnComponent
|
||||
]
|
||||
})
|
||||
|
@ -0,0 +1,83 @@
|
||||
/*!
|
||||
* @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 { LibraryRoleColumnComponent } from './library-role-column.component';
|
||||
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||
import { AppTestingModule } from '../../../testing/app-testing.module';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
|
||||
describe('LibraryNameColumnComponent', () => {
|
||||
let fixture: ComponentFixture<LibraryRoleColumnComponent>;
|
||||
let component: LibraryRoleColumnComponent;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [AppTestingModule],
|
||||
declarations: [LibraryRoleColumnComponent],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(LibraryRoleColumnComponent);
|
||||
component = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should render Manager', () => {
|
||||
component.context = { row: { node: { entry: { role: 'SiteManager' } } } };
|
||||
fixture.detectChanges();
|
||||
expect(component.displayText).toBe('APP.SITES_ROLE.MANAGER');
|
||||
});
|
||||
|
||||
it('should render Collaborator', () => {
|
||||
component.context = {
|
||||
row: { node: { entry: { role: 'SiteCollaborator' } } }
|
||||
};
|
||||
fixture.detectChanges();
|
||||
expect(component.displayText).toBe('APP.SITES_ROLE.COLLABORATOR');
|
||||
});
|
||||
|
||||
it('should render Contributor', () => {
|
||||
component.context = {
|
||||
row: { node: { entry: { role: 'SiteContributor' } } }
|
||||
};
|
||||
fixture.detectChanges();
|
||||
expect(component.displayText).toBe('APP.SITES_ROLE.CONTRIBUTOR');
|
||||
});
|
||||
|
||||
it('should render Consumer', () => {
|
||||
component.context = {
|
||||
row: { node: { entry: { role: 'SiteConsumer' } } }
|
||||
};
|
||||
fixture.detectChanges();
|
||||
expect(component.displayText).toBe('APP.SITES_ROLE.CONSUMER');
|
||||
});
|
||||
|
||||
it('should not render text for unknown', () => {
|
||||
component.context = {
|
||||
row: { node: { entry: { role: 'ROLE' } } }
|
||||
};
|
||||
fixture.detectChanges();
|
||||
expect(component.displayText).toBe('');
|
||||
});
|
||||
});
|
@ -0,0 +1,65 @@
|
||||
/*!
|
||||
* @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, OnInit, Input } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-library-role-column',
|
||||
template: `
|
||||
<span title="{{ displayText | translate }}">
|
||||
{{ displayText | translate }}
|
||||
</span>
|
||||
`
|
||||
})
|
||||
export class LibraryRoleColumnComponent implements OnInit {
|
||||
@Input()
|
||||
context: any;
|
||||
|
||||
displayText: string;
|
||||
|
||||
ngOnInit() {
|
||||
const node = this.context.row.node;
|
||||
if (node && node.entry) {
|
||||
const role: string = node.entry.role;
|
||||
switch (role) {
|
||||
case 'SiteManager':
|
||||
this.displayText = 'APP.SITES_ROLE.MANAGER';
|
||||
break;
|
||||
case 'SiteCollaborator':
|
||||
this.displayText = 'APP.SITES_ROLE.COLLABORATOR';
|
||||
break;
|
||||
case 'SiteContributor':
|
||||
this.displayText = 'APP.SITES_ROLE.CONTRIBUTOR';
|
||||
break;
|
||||
case 'SiteConsumer':
|
||||
this.displayText = 'APP.SITES_ROLE.CONSUMER';
|
||||
break;
|
||||
default:
|
||||
this.displayText = '';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
<app-page-layout>
|
||||
|
||||
<app-page-layout-header>
|
||||
<adf-breadcrumb root="APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.TITLE">
|
||||
</adf-breadcrumb>
|
||||
|
||||
<adf-toolbar class="inline">
|
||||
<app-document-display-mode *ifExperimental="'cardview'"></app-document-display-mode>
|
||||
|
||||
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
|
||||
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
|
||||
</ng-container>
|
||||
</adf-toolbar>
|
||||
</app-page-layout-header>
|
||||
|
||||
<app-page-layout-content>
|
||||
<div class="main-content">
|
||||
<adf-document-list #documentList acaDocumentList [display]="documentDisplayMode$ | async" [node]="favoriteList"
|
||||
[loading]="dataIsLoading" selectionMode="single" [navigate]="false" [sorting]="[ 'title', 'asc' ]"
|
||||
(node-dblclick)="navigateTo($event.detail?.node)" (name-click)="navigateTo($event.detail?.node)">
|
||||
|
||||
<empty-folder-content>
|
||||
<ng-template>
|
||||
<adf-empty-content icon="library_books" [title]="'APP.BROWSE.LIBRARIES.EMPTY_STATE.FAVORITE_LIBRARIES.TITLE'"
|
||||
subtitle="APP.BROWSE.LIBRARIES.EMPTY_STATE.FAVORITE_LIBRARIES.TEXT">
|
||||
</adf-empty-content>
|
||||
</ng-template>
|
||||
</empty-folder-content>
|
||||
|
||||
<data-columns>
|
||||
<ng-container *ngFor="let column of columns; trackBy: trackById">
|
||||
<ng-container *ngIf="column.template && !(column.desktopOnly && isSmallScreen)">
|
||||
<data-column [key]="column.key" [title]="column.title" [type]="column.type" [format]="column.format"
|
||||
[class]="column.class" [sortable]="column.sortable">
|
||||
<ng-template let-context>
|
||||
<app-dynamic-column [id]="column.template" [context]="context">
|
||||
</app-dynamic-column>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="!column.template && !(column.desktopOnly && isSmallScreen)">
|
||||
<data-column [key]="column.key" [title]="column.title" [type]="column.type" [format]="column.format"
|
||||
[class]="column.class" [sortable]="column.sortable">
|
||||
</data-column>
|
||||
</ng-container>
|
||||
|
||||
</ng-container>
|
||||
</data-columns>
|
||||
</adf-document-list>
|
||||
|
||||
<adf-pagination acaPagination [target]="documentList">
|
||||
</adf-pagination>
|
||||
</div>
|
||||
|
||||
<div class="sidebar" *ngIf="infoDrawerOpened$ | async">
|
||||
<aca-info-drawer [node]="selection.last"></aca-info-drawer>
|
||||
</div>
|
||||
</app-page-layout-content>
|
||||
</app-page-layout>
|
@ -0,0 +1,124 @@
|
||||
/*!
|
||||
* @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 { TestBed, ComponentFixture, async } from '@angular/core/testing';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import {
|
||||
AlfrescoApiService,
|
||||
TimeAgoPipe,
|
||||
NodeNameTooltipPipe,
|
||||
NodeFavoriteDirective,
|
||||
DataTableComponent,
|
||||
AppConfigPipe
|
||||
} from '@alfresco/adf-core';
|
||||
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
||||
import { FavoriteLibrariesComponent } from './favorite-libraries.component';
|
||||
import { AppTestingModule } from '../../testing/app-testing.module';
|
||||
import { ContentApiService } from '../../services/content-api.service';
|
||||
import { ExperimentalDirective } from '../../directives/experimental.directive';
|
||||
import { EffectsModule } from '@ngrx/effects';
|
||||
import { LibraryEffects } from '../../store/effects';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
describe('LibrariesComponent', () => {
|
||||
let fixture: ComponentFixture<FavoriteLibrariesComponent>;
|
||||
let component: FavoriteLibrariesComponent;
|
||||
let alfrescoApi: AlfrescoApiService;
|
||||
let contentApiService: ContentApiService;
|
||||
let router: Router;
|
||||
let page;
|
||||
|
||||
beforeEach(() => {
|
||||
page = {
|
||||
list: {
|
||||
entries: [{ entry: { id: 1 } }, { entry: { id: 2 } }],
|
||||
pagination: { data: 'data' }
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [AppTestingModule, EffectsModule.forRoot([LibraryEffects])],
|
||||
declarations: [
|
||||
DataTableComponent,
|
||||
TimeAgoPipe,
|
||||
NodeNameTooltipPipe,
|
||||
NodeFavoriteDirective,
|
||||
DocumentListComponent,
|
||||
FavoriteLibrariesComponent,
|
||||
AppConfigPipe,
|
||||
ExperimentalDirective
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(FavoriteLibrariesComponent);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
alfrescoApi = TestBed.get(AlfrescoApiService);
|
||||
contentApiService = TestBed.get(ContentApiService);
|
||||
alfrescoApi.reset();
|
||||
router = TestBed.get(Router);
|
||||
|
||||
spyOn(contentApiService, 'getNode').and.returnValue(
|
||||
of({ entry: { id: 'libraryId' } })
|
||||
);
|
||||
});
|
||||
|
||||
describe('Favorite libraries data', () => {
|
||||
it('should initialise with default data', () => {
|
||||
expect(component.node).toBe(undefined);
|
||||
expect(component.dataIsLoading).toBe(true);
|
||||
});
|
||||
|
||||
it('should get data on initialization', async(() => {
|
||||
spyOn(contentApiService, 'getFavoriteLibraries').and.returnValue(
|
||||
of(page)
|
||||
);
|
||||
fixture.autoDetectChanges();
|
||||
|
||||
expect(component.favoriteList).toEqual(page);
|
||||
expect(component.dataIsLoading).toBe(false);
|
||||
}));
|
||||
});
|
||||
|
||||
describe('Node navigation', () => {
|
||||
it('does not navigate when id is not passed', () => {
|
||||
spyOn(router, 'navigate').and.stub();
|
||||
component.navigateTo(null);
|
||||
|
||||
expect(router.navigate).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not navigate when id is not passed', () => {
|
||||
spyOn(router, 'navigate').and.stub();
|
||||
component.navigateTo({ entry: { guid: 'guid' } });
|
||||
|
||||
expect(router.navigate).toHaveBeenCalledWith(['libraries', 'libraryId']);
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,88 @@
|
||||
/*!
|
||||
* @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 { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { SiteEntry, FavoritePaging } from 'alfresco-js-api';
|
||||
import { AppExtensionService } from '../../extensions/extension.service';
|
||||
import { ContentManagementService } from '../../services/content-management.service';
|
||||
import { ContentApiService } from '../../services/content-api.service';
|
||||
import { NavigateLibraryAction } from '../../store/actions';
|
||||
import { AppStore } from '../../store/states/app.state';
|
||||
import { PageComponent } from '../page.component';
|
||||
|
||||
@Component({
|
||||
templateUrl: './favorite-libraries.component.html'
|
||||
})
|
||||
export class FavoriteLibrariesComponent extends PageComponent
|
||||
implements OnInit {
|
||||
favoriteList: FavoritePaging;
|
||||
dataIsLoading = true;
|
||||
isSmallScreen = false;
|
||||
columns: any[] = [];
|
||||
|
||||
constructor(
|
||||
content: ContentManagementService,
|
||||
store: Store<AppStore>,
|
||||
extensions: AppExtensionService,
|
||||
private contentApiService: ContentApiService,
|
||||
private breakpointObserver: BreakpointObserver
|
||||
) {
|
||||
super(store, extensions, content);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
super.ngOnInit();
|
||||
|
||||
this.contentApiService.getFavoriteLibraries().subscribe(
|
||||
(favoriteLibraries: FavoritePaging) => {
|
||||
this.favoriteList = favoriteLibraries;
|
||||
this.dataIsLoading = false;
|
||||
},
|
||||
() => {
|
||||
this.favoriteList = null;
|
||||
this.dataIsLoading = false;
|
||||
}
|
||||
);
|
||||
|
||||
this.subscriptions = this.subscriptions.concat([
|
||||
this.content.libraryDeleted.subscribe(() => this.reload()),
|
||||
this.content.libraryUpdated.subscribe(() => this.documentList.reload()),
|
||||
this.breakpointObserver
|
||||
.observe([Breakpoints.HandsetPortrait, Breakpoints.HandsetLandscape])
|
||||
.subscribe(result => {
|
||||
this.isSmallScreen = result.matches;
|
||||
})
|
||||
]);
|
||||
this.columns = this.extensions.documentListPresets.favoriteLibraries || [];
|
||||
}
|
||||
|
||||
navigateTo(node: SiteEntry) {
|
||||
if (node && node.entry && node.entry.guid) {
|
||||
this.store.dispatch(new NavigateLibraryAction(node.entry.guid));
|
||||
}
|
||||
}
|
||||
}
|
@ -26,9 +26,9 @@
|
||||
<empty-folder-content>
|
||||
<ng-template>
|
||||
<adf-empty-content
|
||||
icon="group_work"
|
||||
[title]="'APP.BROWSE.LIBRARIES.EMPTY_STATE.TITLE'"
|
||||
subtitle="APP.BROWSE.LIBRARIES.EMPTY_STATE.TEXT">
|
||||
icon="library_books"
|
||||
[title]="'APP.BROWSE.LIBRARIES.EMPTY_STATE.FILE_LIBRARIES.TITLE'"
|
||||
subtitle="APP.BROWSE.LIBRARIES.EMPTY_STATE.FILE_LIBRARIES.TEXT">
|
||||
</adf-empty-content>
|
||||
</ng-template>
|
||||
</empty-folder-content>
|
||||
|
@ -55,6 +55,7 @@ export class LibrariesComponent extends PageComponent implements OnInit {
|
||||
|
||||
this.subscriptions.push(
|
||||
this.content.libraryDeleted.subscribe(() => this.reload()),
|
||||
this.content.libraryUpdated.subscribe(() => this.documentList.reload()),
|
||||
|
||||
this.breakpointObserver
|
||||
.observe([Breakpoints.HandsetPortrait, Breakpoints.HandsetLandscape])
|
||||
@ -63,10 +64,6 @@ export class LibrariesComponent extends PageComponent implements OnInit {
|
||||
})
|
||||
);
|
||||
|
||||
this.subscriptions = this.subscriptions.concat([
|
||||
this.content.libraryUpdated.subscribe(() => this.documentList.reload())
|
||||
]);
|
||||
|
||||
this.columns = this.extensions.documentListPresets.libraries || [];
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
</button>
|
||||
|
||||
<span #rippleTrigger
|
||||
class="item--label"
|
||||
class="item--label item--parent"
|
||||
[routerLink]="item.url"
|
||||
[attr.aria-label]="item.title | translate"
|
||||
[ngClass]="{
|
||||
@ -40,10 +40,10 @@
|
||||
|
||||
<ng-container *ngIf="item.children && item.children.length">
|
||||
<mat-expansion-panel [expanded]="routerLink.isActive" [@.disabled]="true">
|
||||
<mat-expansion-panel-header expandedHeight="48px" collapsedHeight="48px" [id]="item.id">
|
||||
<mat-expansion-panel-header expandedHeight="48px" collapsedHeight="48px">
|
||||
<mat-panel-title [attr.title]="item.description | translate">
|
||||
<mat-icon [color]="routerLink.isActive? 'accent': 'primary'">{{ item.icon }}</mat-icon>
|
||||
<span class="item--label"
|
||||
<span class="item--label item--parent"
|
||||
[ngClass]="{
|
||||
'item--active': routerLink.isActive,
|
||||
'item--default': !routerLink.isActive
|
||||
|
@ -36,6 +36,10 @@
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.item--parent {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.item--label {
|
||||
cursor: pointer;
|
||||
width: 240px;
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
import { Directive, OnDestroy, OnInit, HostListener } from '@angular/core';
|
||||
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Store } from '@ngrx/store';
|
||||
@ -48,13 +48,17 @@ export class DocumentListDirective implements OnInit, OnDestroy {
|
||||
private store: Store<AppStore>,
|
||||
private documentList: DocumentListComponent,
|
||||
private preferences: UserPreferencesService,
|
||||
private route: ActivatedRoute
|
||||
private route: ActivatedRoute,
|
||||
private router: Router
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.documentList.includeFields = ['isFavorite', 'aspectNames'];
|
||||
this.documentList.allowDropFiles = false;
|
||||
this.isLibrary = this.documentList.currentFolderId === '-mysites-';
|
||||
this.isLibrary =
|
||||
this.documentList.currentFolderId === '-mysites-' ||
|
||||
// workaround for custom node list
|
||||
this.router.url.endsWith('/libraries');
|
||||
|
||||
if (this.sortingPreferenceKey) {
|
||||
const current = this.documentList.sorting;
|
||||
|
@ -42,6 +42,7 @@ import { ExtensionsModule, ExtensionService } from '@alfresco/adf-extensions';
|
||||
import { AppAuthGuard } from '../guards/auth.guard';
|
||||
import { NameColumnComponent } from '../components/common/name-column/name-column.component';
|
||||
import { LibraryNameColumnComponent } from '../components/common/library-name-column/library-name-column.component';
|
||||
import { LibraryRoleColumnComponent } from '../components/common/library-role-column/library-role-column.component';
|
||||
import { LibraryStatusColumnComponent } from '../components/common/library-status-column/library-status-column.component';
|
||||
import { TrashcanNameColumnComponent } from '../components/common/trashcan-name-column/trashcan-name-column.component';
|
||||
import { LocationLinkComponent } from '../components/common/location-link/location-link.component';
|
||||
@ -88,6 +89,7 @@ export class CoreExtensionsModule {
|
||||
'app.shared-link.toggleSharedLink': ToggleSharedComponent,
|
||||
'app.columns.name': NameColumnComponent,
|
||||
'app.columns.libraryName': LibraryNameColumnComponent,
|
||||
'app.columns.libraryRole': LibraryRoleColumnComponent,
|
||||
'app.columns.libraryStatus': LibraryStatusColumnComponent,
|
||||
'app.columns.trashcanName': TrashcanNameColumnComponent,
|
||||
'app.columns.location': LocationLinkComponent
|
||||
|
@ -75,6 +75,7 @@ export class AppExtensionService implements RuleContext {
|
||||
documentListPresets: {
|
||||
files: Array<DocumentListPresetRef>;
|
||||
libraries: Array<DocumentListPresetRef>;
|
||||
favoriteLibraries: Array<DocumentListPresetRef>;
|
||||
shared: Array<DocumentListPresetRef>;
|
||||
recent: Array<DocumentListPresetRef>;
|
||||
favorites: Array<DocumentListPresetRef>;
|
||||
@ -83,6 +84,7 @@ export class AppExtensionService implements RuleContext {
|
||||
} = {
|
||||
files: [],
|
||||
libraries: [],
|
||||
favoriteLibraries: [],
|
||||
shared: [],
|
||||
recent: [],
|
||||
favorites: [],
|
||||
@ -162,6 +164,10 @@ export class AppExtensionService implements RuleContext {
|
||||
this.documentListPresets = {
|
||||
files: this.getDocumentListPreset(config, 'files'),
|
||||
libraries: this.getDocumentListPreset(config, 'libraries'),
|
||||
favoriteLibraries: this.getDocumentListPreset(
|
||||
config,
|
||||
'favoriteLibraries'
|
||||
),
|
||||
shared: this.getDocumentListPreset(config, 'shared'),
|
||||
recent: this.getDocumentListPreset(config, 'recent'),
|
||||
favorites: this.getDocumentListPreset(config, 'favorites'),
|
||||
|
@ -42,6 +42,7 @@ import {
|
||||
SiteEntry,
|
||||
FavoriteBody
|
||||
} from 'alfresco-js-api';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@ -185,6 +186,24 @@ export class ContentApiService {
|
||||
return from(this.api.favoritesApi.getFavorites(personId, opts));
|
||||
}
|
||||
|
||||
getFavoriteLibraries(personId: string = '-me-'): Observable<FavoritePaging> {
|
||||
return this.getFavorites(personId, { where: '(EXISTS(target/site))' }).pipe(
|
||||
map((response: FavoritePaging) => {
|
||||
return {
|
||||
list: {
|
||||
entries: response.list.entries.map(({ entry }: any) => {
|
||||
entry.target.site.createdAt = entry.createdAt;
|
||||
return {
|
||||
entry: entry.target.site
|
||||
};
|
||||
}),
|
||||
pagination: response.list.pagination
|
||||
}
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
findSharedLinks(opts?: any): Observable<SharedLinkPaging> {
|
||||
return from(this.api.sharedLinksApi.findSharedLinks(opts));
|
||||
}
|
||||
|
@ -243,12 +243,27 @@
|
||||
"route": "personal-files"
|
||||
},
|
||||
{
|
||||
"id": "app.navbar.libraries",
|
||||
"id": "app.navbar.libraries.menu",
|
||||
"order": 200,
|
||||
"icon": "group_work",
|
||||
"icon": "library_books",
|
||||
"title": "APP.BROWSE.LIBRARIES.SIDENAV_LINK.LABEL",
|
||||
"description": "APP.BROWSE.LIBRARIES.SIDENAV_LINK.TOOLTIP",
|
||||
"route": "libraries"
|
||||
"children": [
|
||||
{
|
||||
"id": "app.navbar.libraries.files",
|
||||
"order": 100,
|
||||
"title": "APP.BROWSE.LIBRARIES.MENU.FILE_LIBRARIES.SIDENAV_LINK.LABEL",
|
||||
"description": "APP.BROWSE.LIBRARIES.MENU.FILE_LIBRARIES.SIDENAV_LINK.TOOLTIP",
|
||||
"route": "libraries"
|
||||
},
|
||||
{
|
||||
"id": "app.navbar.libraries.favorite",
|
||||
"order": 200,
|
||||
"title": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.LABEL",
|
||||
"description": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.TOOLTIP",
|
||||
"route": "favorite/libraries"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -863,7 +878,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "test",
|
||||
"id": "app.sidebar.library.properties",
|
||||
"order": 500,
|
||||
"title": "APP.INFO_DRAWER.TABS.LIBRARY_PROPERTIES",
|
||||
"component": "app.components.tabs.library.metadata",
|
||||
@ -962,13 +977,22 @@
|
||||
{
|
||||
"id": "app.libraries.name",
|
||||
"key": "title",
|
||||
"title": "APP.DOCUMENT_LIST.COLUMNS.TITLE",
|
||||
"title": "APP.DOCUMENT_LIST.COLUMNS.NAME",
|
||||
"type": "text",
|
||||
"class": "adf-data-table-cell--ellipsis__name",
|
||||
"sortable": true,
|
||||
"template": "app.columns.libraryName",
|
||||
"desktopOnly": false
|
||||
},
|
||||
{
|
||||
"id": "app.libraries.role",
|
||||
"key": "target.site.role",
|
||||
"title": "APP.DOCUMENT_LIST.COLUMNS.ROLE",
|
||||
"type": "text",
|
||||
"sortable": true,
|
||||
"template": "app.columns.libraryRole",
|
||||
"desktopOnly": false
|
||||
},
|
||||
{
|
||||
"id": "app.libraries.visibility",
|
||||
"key": "visibility",
|
||||
@ -979,6 +1003,44 @@
|
||||
"desktopOnly": true
|
||||
}
|
||||
],
|
||||
"favoriteLibraries": [
|
||||
{
|
||||
"id": "app.favorite.libraries.thumbnail",
|
||||
"key": "$thumbnail",
|
||||
"type": "image",
|
||||
"class": "image-table-cell",
|
||||
"sortable": false,
|
||||
"desktopOnly": false
|
||||
},
|
||||
{
|
||||
"id": "app.favorite.libraries.name",
|
||||
"key": "title",
|
||||
"title": "APP.DOCUMENT_LIST.COLUMNS.NAME",
|
||||
"type": "text",
|
||||
"class": "adf-data-table-cell--ellipsis__name",
|
||||
"sortable": true,
|
||||
"template": "app.columns.libraryName",
|
||||
"desktopOnly": false
|
||||
},
|
||||
{
|
||||
"id": "app.favorite.libraries.role",
|
||||
"key": "target.site.role",
|
||||
"title": "APP.DOCUMENT_LIST.COLUMNS.ROLE",
|
||||
"type": "text",
|
||||
"sortable": true,
|
||||
"template": "app.columns.libraryRole",
|
||||
"desktopOnly": false
|
||||
},
|
||||
{
|
||||
"id": "app.favorite.libraries.visibility",
|
||||
"key": "visibility",
|
||||
"title": "APP.DOCUMENT_LIST.COLUMNS.VISIBILITY",
|
||||
"type": "text",
|
||||
"sortable": true,
|
||||
"template": "app.columns.libraryStatus",
|
||||
"desktopOnly": true
|
||||
}
|
||||
],
|
||||
"shared": [
|
||||
{
|
||||
"id": "app.shared.thumbnail",
|
||||
|
@ -45,13 +45,36 @@
|
||||
},
|
||||
"LIBRARIES": {
|
||||
"TITLE": "File Libraries",
|
||||
"DESCRIPTION": "Access File Libraries",
|
||||
"SIDENAV_LINK": {
|
||||
"LABEL": "File Libraries",
|
||||
"TOOLTIP": "Access File Libraries"
|
||||
"TOOLTIP": "File Libraries"
|
||||
},
|
||||
"EMPTY_STATE": {
|
||||
"TITLE": "You aren't a member of any File Libraries yet",
|
||||
"TEXT": "Join libraries to upload, view, and share files."
|
||||
"FILE_LIBRARIES": {
|
||||
"TITLE": "You aren't a member of any File Libraries yet",
|
||||
"TEXT": "Join libraries to upload, view, and share files."
|
||||
},
|
||||
"FAVORITE_LIBRARIES": {
|
||||
"TITLE": "No Favorite Libraries",
|
||||
"TEXT": "Favorite a library that you want to find easily later."
|
||||
}
|
||||
},
|
||||
"MENU": {
|
||||
"FILE_LIBRARIES": {
|
||||
"TITLE": "My Libraries",
|
||||
"SIDENAV_LINK": {
|
||||
"LABEL": "My Libraries",
|
||||
"TOOLTIP": "Access My Libraries"
|
||||
}
|
||||
},
|
||||
"FAVORITE_LIBRARIES": {
|
||||
"TITLE": "Favorite Libraries",
|
||||
"SIDENAV_LINK": {
|
||||
"LABEL": "Favorite Libraries",
|
||||
"TOOLTIP": "Access Favorited Libraries"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"SHARED": {
|
||||
@ -150,7 +173,6 @@
|
||||
"DOCUMENT_LIST": {
|
||||
"COLUMNS": {
|
||||
"ID": "ID",
|
||||
"ROLE": "Role",
|
||||
"NAME": "Name",
|
||||
"SIZE": "Size",
|
||||
"MODIFIED_ON": "Modified",
|
||||
@ -160,7 +182,8 @@
|
||||
"LOCATION": "Location",
|
||||
"SHARED_BY": "Shared by",
|
||||
"DELETED_ON": "Deleted",
|
||||
"DELETED_BY": "Deleted by"
|
||||
"DELETED_BY": "Deleted by",
|
||||
"ROLE": "My Role"
|
||||
},
|
||||
"TOOLBAR": {
|
||||
"CARDVIEW": "Card view mode",
|
||||
@ -172,6 +195,12 @@
|
||||
"MODERATED": "Moderated",
|
||||
"PRIVATE": "Private"
|
||||
},
|
||||
"SITES_ROLE": {
|
||||
"MANAGER": "Manager",
|
||||
"COLLABORATOR": "Collaborator",
|
||||
"CONTRIBUTOR": "Contributor",
|
||||
"CONSUMER": "Consumer"
|
||||
},
|
||||
"MESSAGES": {
|
||||
"ERRORS":{
|
||||
"MISSING_CONTENT": "This file or folder no longer exists or you don't have permission to view it.",
|
||||
|
Loading…
x
Reference in New Issue
Block a user