[ACA-1830] create menu enhancements (#670)

* nested menus for create button

* evaluate sub-menu permissions

* demo plugin

* "create library" action

* unit tests and proper effect name
This commit is contained in:
Denys Vuika
2018-09-27 09:07:24 +01:00
committed by GitHub
parent 23df2ad6a2
commit 457fa74048
22 changed files with 347 additions and 186 deletions
+1 -2
View File
@@ -49,8 +49,7 @@
"cardview", "cardview",
"webm", "webm",
"keycodes", "keycodes",
"denysvuika", "denysvuika"
"fdescribe"
], ],
"dictionaries": ["html", "en-gb", "en_US"] "dictionaries": ["html", "en-gb", "en_US"]
} }
+1
View File
@@ -612,6 +612,7 @@ Below is the list of public actions types you can use in the plugin definitions
| NAVIGATE_ROUTE | any[] | Navigate to a particular Route (supports parameters) | | NAVIGATE_ROUTE | any[] | Navigate to a particular Route (supports parameters) |
| NAVIGATE_FOLDER | MinimalNodeEntity | Navigate to a folder based on the Node properties. | | NAVIGATE_FOLDER | MinimalNodeEntity | Navigate to a folder based on the Node properties. |
| NAVIGATE_PARENT_FOLDER | MinimalNodeEntity | Navigate to a containing folder based on the Node properties. | | NAVIGATE_PARENT_FOLDER | MinimalNodeEntity | Navigate to a containing folder based on the Node properties. |
| NAVIGATE_LIBRARY | string | Navigate to library |
| SEARCH_BY_TERM | string | Perform a simple search by the term and navigate to Search results. | | SEARCH_BY_TERM | string | Perform a simple search by the term and navigate to Search results. |
| SNACKBAR_INFO | string | Show information snackbar with the message provided. | | SNACKBAR_INFO | string | Show information snackbar with the message provided. |
| SNACKBAR_WARNING | string | Show warning snackbar with the message provided. | | SNACKBAR_WARNING | string | Show warning snackbar with the message provided. |
+1 -1
View File
@@ -33,7 +33,7 @@ export class Sidenav extends Component {
link: '.sidenav-menu__item', link: '.sidenav-menu__item',
label: '.menu__item--label', label: '.menu__item--label',
activeLink: '.menu__item--active', activeLink: '.menu__item--active',
newButton: '.adf-sidebar-action-menu-button' newButton: '[data-automation-id="create-button"]'
}; };
links: ElementArrayFinder = this.component.all(by.css(Sidenav.selectors.link)); links: ElementArrayFinder = this.component.all(by.css(Sidenav.selectors.link));
@@ -1,14 +1,26 @@
<adf-sidebar-action-menu <ng-container *ngIf="expanded">
[expanded]="showLabel" <button
[attr.title]="'APP.NEW_MENU.TOOLTIP' | translate" data-automation-id="create-button"
[title]="'APP.NEW_MENU.LABEL' | translate"> mat-raised-button
<mat-icon sidebar-menu-title-icon>arrow_drop_down</mat-icon> [matMenuTriggerFor]="rootMenu"
<div sidebar-menu-expand-icon> title="{{ 'APP.NEW_MENU.TOOLTIP' | translate }}">
<mat-icon [title]="'APP.NEW_MENU.TOOLTIP' | translate">queue</mat-icon> <span class="app-create-menu__text">{{ 'APP.NEW_MENU.LABEL' | translate }}</span>
</div> <mat-icon title="{{ 'APP.NEW_MENU.TOOLTIP' | translate }}">arrow_drop_down</mat-icon>
<div sidebar-menu-options> </button>
<ng-container *ngFor="let action of createActions; trackBy: trackById"> </ng-container>
<app-toolbar-menu-item [actionRef]="action"></app-toolbar-menu-item>
</ng-container> <ng-container *ngIf="!expanded">
</div> <button
</adf-sidebar-action-menu> class="app-create-menu--collapsed"
data-automation-id="create-button"
[matMenuTriggerFor]="rootMenu"
title="{{ 'APP.NEW_MENU.TOOLTIP' | translate }}">
<mat-icon title="{{ 'APP.NEW_MENU.TOOLTIP' | translate }}">queue</mat-icon>
</button>
</ng-container>
<mat-menu #rootMenu="matMenu" class="app-create-menu__root-menu app-create-menu__sub-menu" [overlapTrigger]="false" yPosition="below">
<ng-container *ngFor="let action of createActions; trackBy: trackById">
<app-toolbar-menu-item [actionRef]="action"></app-toolbar-menu-item>
</ng-container>
</mat-menu>
@@ -1,3 +1,87 @@
.app-create-menu { @mixin app-create-menu-theme($theme) {
width: 100%; $foreground: map-get($theme, foreground);
$accent: map-get($theme, accent);
$primary: map-get($theme, primary);
.app-create-menu {
width: 100%;
.mat-raised-button {
width: 100%;
display: block;
box-shadow: none !important;
height: 37.5px;
background-color: mat-color($accent);
color: mat-color($primary, default-contrast) !important;
border-radius: 4px;
font-size: 12.7px;
font-weight: normal;
text-transform: uppercase;
.mat-icon {
width: 24px;
height: 25px;
color: mat-color($primary, default-contrast) !important;
}
&__text {
width: 100%;
height: 20px;
text-align: left;
}
}
&__root-menu {
max-width: 290px !important;
width: 290px;
display: flex;
align-items: center;
justify-content: center;
& > .mat-menu-content {
width: 100%;
}
}
&--collapsed {
color: mat-color($foreground, text, 0.54);
cursor: pointer;
&:hover {
color: mat-color($primary);
}
margin: 0;
border: none;
background: none;
}
&__sub-menu {
.mat-menu-item {
display: flex;
flex-direction: row;
align-items: center;
font-size: 14px;
color: mat-color($foreground, text, 0.54);
line-height: 48px;
box-shadow: none;
transform: none;
transition: unset;
font-weight: normal;
text-transform: capitalize;
color: mat-color($primary);
&:hover {
color: mat-color($accent);
}
}
.mat-menu-item[disabled],
.mat-menu-item[disabled]:hover {
color: mat-color($foreground, text, 0.38);
.mat-icon {
color: mat-color($foreground, text, 0.38);
}
}
}
}
} }
@@ -52,6 +52,9 @@ export class CreateMenuComponent implements OnInit, OnDestroy {
@Input() @Input()
showLabel: boolean; showLabel: boolean;
@Input()
expanded: boolean;
constructor( constructor(
private store: Store<AppStore>, private store: Store<AppStore>,
private extensions: AppExtensionService private extensions: AppExtensionService
@@ -41,6 +41,8 @@ import { LibrariesComponent } from './libraries.component';
import { AppTestingModule } from '../../testing/app-testing.module'; import { AppTestingModule } from '../../testing/app-testing.module';
import { ContentApiService } from '../../services/content-api.service'; import { ContentApiService } from '../../services/content-api.service';
import { ExperimentalDirective } from '../../directives/experimental.directive'; import { ExperimentalDirective } from '../../directives/experimental.directive';
import { EffectsModule } from '@ngrx/effects';
import { LibraryEffects } from 'src/app/store/effects';
describe('LibrariesComponent', () => { describe('LibrariesComponent', () => {
let fixture: ComponentFixture<LibrariesComponent>; let fixture: ComponentFixture<LibrariesComponent>;
@@ -69,7 +71,7 @@ describe('LibrariesComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [AppTestingModule], imports: [AppTestingModule, EffectsModule.forRoot([LibraryEffects])],
declarations: [ declarations: [
DataTableComponent, DataTableComponent,
TimeAgoPipe, TimeAgoPipe,
@@ -153,13 +155,8 @@ describe('LibrariesComponent', () => {
}); });
describe('Node navigation', () => { describe('Node navigation', () => {
let routerSpy;
beforeEach(() => {
routerSpy = spyOn(router, 'navigate');
});
it('does not navigate when id is not passed', () => { it('does not navigate when id is not passed', () => {
spyOn(router, 'navigate').and.stub();
component.navigate(null); component.navigate(null);
expect(router.navigate).not.toHaveBeenCalled(); expect(router.navigate).not.toHaveBeenCalled();
@@ -167,11 +164,12 @@ describe('LibrariesComponent', () => {
it('navigates to node id', () => { it('navigates to node id', () => {
const document = { id: 'documentId' }; const document = { id: 'documentId' };
spyOn(router, 'navigate').and.stub();
spyOn(contentApi, 'getNode').and.returnValue(of({ entry: document })); spyOn(contentApi, 'getNode').and.returnValue(of({ entry: document }));
component.navigate(node.id); component.navigate(node.id);
expect(routerSpy.calls.argsFor(0)[0]).toEqual(['./', document.id]); expect(router.navigate).toHaveBeenCalledWith(['libraries', 'documentId']);
}); });
}); });
@@ -24,18 +24,15 @@
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { ShareDataRow } from '@alfresco/adf-content-services'; import { ShareDataRow } from '@alfresco/adf-content-services';
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
import { PageComponent } from '../page.component'; import { PageComponent } from '../page.component';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppStore } from '../../store/states/app.state'; import { AppStore } from '../../store/states/app.state';
import { SiteEntry } from 'alfresco-js-api'; import { SiteEntry } from 'alfresco-js-api';
import { ContentManagementService } from '../../services/content-management.service'; import { ContentManagementService } from '../../services/content-management.service';
import { ContentApiService } from '../../services/content-api.service';
import { AppExtensionService } from '../../extensions/extension.service'; import { AppExtensionService } from '../../extensions/extension.service';
import { map } from 'rxjs/operators'; import { NavigateLibraryAction } from 'src/app/store/actions';
@Component({ @Component({
templateUrl: './libraries.component.html' templateUrl: './libraries.component.html'
@@ -44,12 +41,9 @@ export class LibrariesComponent extends PageComponent implements OnInit {
isSmallScreen = false; isSmallScreen = false;
constructor( constructor(
private route: ActivatedRoute,
content: ContentManagementService, content: ContentManagementService,
private contentApi: ContentApiService,
store: Store<AppStore>, store: Store<AppStore>,
extensions: AppExtensionService, extensions: AppExtensionService,
private router: Router,
private breakpointObserver: BreakpointObserver private breakpointObserver: BreakpointObserver
) { ) {
super(store, extensions, content); super(store, extensions, content);
@@ -60,9 +54,6 @@ export class LibrariesComponent extends PageComponent implements OnInit {
this.subscriptions.push( this.subscriptions.push(
this.content.libraryDeleted.subscribe(() => this.reload()), this.content.libraryDeleted.subscribe(() => this.reload()),
this.content.libraryCreated.subscribe((node: SiteEntry) => {
this.navigate(node.entry.guid);
}),
this.breakpointObserver this.breakpointObserver
.observe([Breakpoints.HandsetPortrait, Breakpoints.HandsetLandscape]) .observe([Breakpoints.HandsetPortrait, Breakpoints.HandsetLandscape])
@@ -101,15 +92,6 @@ export class LibrariesComponent extends PageComponent implements OnInit {
} }
navigate(libraryId: string) { navigate(libraryId: string) {
if (libraryId) { this.store.dispatch(new NavigateLibraryAction(libraryId));
this.contentApi
.getNode(libraryId, { relativePath: '/documentLibrary' })
.pipe(map(node => node.entry))
.subscribe(documentLibrary => {
this.router.navigate(['./', documentLibrary.id], {
relativeTo: this.route
});
});
}
} }
} }
@@ -1,6 +1,6 @@
<div class="sidenav"> <div class="sidenav">
<div class="sidenav__section sidenav__section sidenav_action-menu"> <div class="sidenav__section sidenav__section sidenav_action-menu">
<app-create-menu [showLabel]="showLabel"></app-create-menu> <app-create-menu [expanded]="showLabel"></app-create-menu>
</div> </div>
<div *ngFor="let group of groups; trackBy: trackById" <div *ngFor="let group of groups; trackBy: trackById"
@@ -1,14 +1,46 @@
<button <ng-container [ngSwitch]="actionRef.type">
[id]="actionRef.id"
mat-menu-item <ng-container *ngSwitchCase="'menu'">
color="primary" <button
[disabled]="actionRef.disabled" mat-menu-item
[attr.title]="( [disabled]="actionRef.disabled"
actionRef.disabled [matMenuTriggerFor]="childMenu">
? actionRef['description-disabled'] <mat-icon>{{ actionRef.icon }}</mat-icon>
: actionRef.description || actionRef.title <span>{{ actionRef.title | translate }}</span>
) | translate" </button>
(click)="runAction()">
<mat-icon>{{ actionRef.icon }}</mat-icon> <mat-menu #childMenu="matMenu" class="app-create-menu__sub-menu">
<span>{{ actionRef.title | translate }}</span> <ng-container *ngFor="let child of actionRef.children; trackBy: trackById">
</button> <app-toolbar-menu-item [actionRef]="child"></app-toolbar-menu-item>
</ng-container>
</mat-menu>
</ng-container>
<ng-container *ngSwitchCase="'separator'">
<mat-divider></mat-divider>
</ng-container>
<ng-container *ngSwitchCase="'custom'">
<adf-dynamic-component [id]="actionRef.component"></adf-dynamic-component>
</ng-container>
<ng-container *ngSwitchDefault>
<button
[id]="actionRef.id"
mat-menu-item
color="primary"
[disabled]="actionRef.disabled"
[attr.title]="(
actionRef.disabled
? actionRef['description-disabled']
: actionRef.description || actionRef.title
) | translate"
(click)="runAction()">
<mat-icon>{{ actionRef.icon }}</mat-icon>
<span>{{ actionRef.title | translate }}</span>
</button>
</ng-container>
</ng-container>
@@ -51,4 +51,8 @@ export class ToolbarMenuItemComponent {
} }
return false; return false;
} }
trackById(index: number, obj: { id: string }) {
return obj.id;
}
} }
+35 -1
View File
@@ -196,7 +196,8 @@ export class AppExtensionService implements RuleContext {
getCreateActions(): Array<ContentActionRef> { getCreateActions(): Array<ContentActionRef> {
return this.createActions return this.createActions
.filter(action => this.filterByRules(action)) .map(action => this.copyAction(action))
.map(action => this.buildMenu(action))
.map(action => { .map(action => {
let disabled = false; let disabled = false;
@@ -211,6 +212,39 @@ export class AppExtensionService implements RuleContext {
}); });
} }
private buildMenu(actionRef: ContentActionRef): ContentActionRef {
if (
actionRef.type === ContentActionType.menu &&
actionRef.children &&
actionRef.children.length > 0
) {
const children = actionRef.children
.filter(action => this.filterByRules(action))
.map(action => this.buildMenu(action));
actionRef.children = children
.map(action => {
let disabled = false;
if (action.rules && action.rules.enabled) {
disabled = !this.extensions.evaluateRule(
action.rules.enabled,
this
);
}
return {
...action,
disabled
};
})
.reduce(reduceEmptyMenus, [])
.reduce(reduceSeparators, []);
}
return actionRef;
}
// evaluates content actions for the selection and parent folder node // evaluates content actions for the selection and parent folder node
getAllowedToolbarActions(): Array<ContentActionRef> { getAllowedToolbarActions(): Array<ContentActionRef> {
return this.toolbarActions return this.toolbarActions
@@ -234,7 +234,7 @@ export class ContentManagementService {
}); });
} }
createLibrary() { createLibrary(): Observable<SiteEntry> {
const dialogInstance = this.dialogRef.open(LibraryDialogComponent, { const dialogInstance = this.dialogRef.open(LibraryDialogComponent, {
width: '400px' width: '400px'
}); });
@@ -243,11 +243,9 @@ export class ContentManagementService {
this.store.dispatch(new SnackbarErrorAction(message)); this.store.dispatch(new SnackbarErrorAction(message));
}); });
dialogInstance.afterClosed().subscribe((node: SiteEntry) => { return dialogInstance
if (node) { .afterClosed()
this.libraryCreated.next(node); .pipe(tap(node => this.libraryCreated.next(node)));
}
});
} }
deleteLibrary(id: string): void { deleteLibrary(id: string): void {
+6
View File
@@ -27,6 +27,7 @@ import { Action } from '@ngrx/store';
export const DELETE_LIBRARY = 'DELETE_LIBRARY'; export const DELETE_LIBRARY = 'DELETE_LIBRARY';
export const CREATE_LIBRARY = 'CREATE_LIBRARY'; export const CREATE_LIBRARY = 'CREATE_LIBRARY';
export const NAVIGATE_LIBRARY = 'NAVIGATE_LIBRARY';
export class DeleteLibraryAction implements Action { export class DeleteLibraryAction implements Action {
readonly type = DELETE_LIBRARY; readonly type = DELETE_LIBRARY;
@@ -37,3 +38,8 @@ export class CreateLibraryAction implements Action {
readonly type = CREATE_LIBRARY; readonly type = CREATE_LIBRARY;
constructor() {} constructor() {}
} }
export class NavigateLibraryAction implements Action {
readonly type = NAVIGATE_LIBRARY;
constructor(public payload?: string) {}
}
+2 -2
View File
@@ -39,7 +39,7 @@ import {
DownloadEffects, DownloadEffects,
ViewerEffects, ViewerEffects,
SearchEffects, SearchEffects,
SiteEffects, LibraryEffects,
UploadEffects, UploadEffects,
FavoriteEffects, FavoriteEffects,
ModalsEffects ModalsEffects
@@ -57,7 +57,7 @@ import {
DownloadEffects, DownloadEffects,
ViewerEffects, ViewerEffects,
SearchEffects, SearchEffects,
SiteEffects, LibraryEffects,
UploadEffects, UploadEffects,
FavoriteEffects, FavoriteEffects,
ModalsEffects ModalsEffects
+27 -6
View File
@@ -25,24 +25,30 @@
import { Effect, Actions, ofType } from '@ngrx/effects'; import { Effect, Actions, ofType } from '@ngrx/effects';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { map, take } from 'rxjs/operators'; import { map, take, switchMap } from 'rxjs/operators';
import { import {
DeleteLibraryAction, DeleteLibraryAction,
DELETE_LIBRARY, DELETE_LIBRARY,
CreateLibraryAction, CreateLibraryAction,
CREATE_LIBRARY CREATE_LIBRARY,
NavigateLibraryAction,
NAVIGATE_LIBRARY
} from '../actions'; } from '../actions';
import { ContentManagementService } from '../../services/content-management.service'; import { ContentManagementService } from '../../services/content-management.service';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppStore } from '../states'; import { AppStore } from '../states';
import { appSelection } from '../selectors/app.selectors'; import { appSelection } from '../selectors/app.selectors';
import { ContentApiService } from '../../services/content-api.service';
import { Router } from '@angular/router';
@Injectable() @Injectable()
export class SiteEffects { export class LibraryEffects {
constructor( constructor(
private store: Store<AppStore>, private store: Store<AppStore>,
private actions$: Actions, private actions$: Actions,
private content: ContentManagementService private content: ContentManagementService,
private contentApi: ContentApiService,
private router: Router
) {} ) {}
@Effect({ dispatch: false }) @Effect({ dispatch: false })
@@ -64,11 +70,26 @@ export class SiteEffects {
}) })
); );
@Effect({ dispatch: false }) @Effect()
createLibrary$ = this.actions$.pipe( createLibrary$ = this.actions$.pipe(
ofType<CreateLibraryAction>(CREATE_LIBRARY), ofType<CreateLibraryAction>(CREATE_LIBRARY),
switchMap(() => this.content.createLibrary()),
map(node => new NavigateLibraryAction(node.entry.guid))
);
@Effect({ dispatch: false })
navigateLibrary$ = this.actions$.pipe(
ofType<NavigateLibraryAction>(NAVIGATE_LIBRARY),
map(action => { map(action => {
this.content.createLibrary(); const libraryId = action.payload;
if (libraryId) {
this.contentApi
.getNode(libraryId, { relativePath: '/documentLibrary' })
.pipe(map(node => node.entry))
.subscribe(documentLibrary => {
this.router.navigate(['libraries', documentLibrary.id]);
});
}
}) })
); );
} }
+2 -2
View File
@@ -10,12 +10,12 @@
@import '../components/permissions/permission-manager/permission-manager.component.theme'; @import '../components/permissions/permission-manager/permission-manager.component.theme';
@import '../components/context-menu/context-menu.component.theme'; @import '../components/context-menu/context-menu.component.theme';
@import '../dialogs/node-versions/node-versions.dialog.theme'; @import '../dialogs/node-versions/node-versions.dialog.theme';
@import '../components/create-menu/create-menu.component.scss';
@import './overrides/adf-toolbar.theme'; @import './overrides/adf-toolbar.theme';
@import './overrides/adf-search-filter.theme'; @import './overrides/adf-search-filter.theme';
@import './overrides/adf-info-drawer.theme'; @import './overrides/adf-info-drawer.theme';
@import './overrides/adf-upload-button.theme'; @import './overrides/adf-upload-button.theme';
@import './overrides/adf-sidebar-action-menu.theme';
@import './overrides/adf-upload-dialog.theme'; @import './overrides/adf-upload-dialog.theme';
@import './overrides/adf-pagination.theme'; @import './overrides/adf-pagination.theme';
@import './overrides/adf-sidenav-layout.theme'; @import './overrides/adf-sidenav-layout.theme';
@@ -74,7 +74,6 @@ $custom-theme: mat-light-theme($custom-theme-primary, $custom-theme-accent);
@include adf-search-filter-theme($theme); @include adf-search-filter-theme($theme);
@include adf-info-drawer-theme($theme); @include adf-info-drawer-theme($theme);
@include adf-upload-button-theme($theme); @include adf-upload-button-theme($theme);
@include adf-sidebar-action-menu-theme($theme);
@include adf-pagination-theme($theme); @include adf-pagination-theme($theme);
@include adf-sidenav-layout-theme($theme); @include adf-sidenav-layout-theme($theme);
@include adf-document-list-theme($theme); @include adf-document-list-theme($theme);
@@ -95,4 +94,5 @@ $custom-theme: mat-light-theme($custom-theme-primary, $custom-theme-accent);
@include aca-about-component-theme($theme); @include aca-about-component-theme($theme);
@include aca-current-user-theme($theme); @include aca-current-user-theme($theme);
@include aca-context-menu-theme($theme); @include aca-context-menu-theme($theme);
@include app-create-menu-theme($theme);
} }
@@ -1,74 +0,0 @@
@mixin adf-sidebar-action-menu-theme($theme) {
$foreground: map-get($theme, foreground);
$accent: map-get($theme, accent);
$primary: map-get($theme, primary);
.adf-sidebar-action-menu {
.adf-sidebar-action-menu-button {
font-size: 12.7px;
font-weight: normal;
text-transform: uppercase;
}
}
.mat-menu-panel.adf-sidebar-action-menu-panel {
max-width: 290px !important;
}
.adf-sidebar-action-menu-panel {
width: 290px;
display: flex;
align-items: center;
justify-content: center;
}
.adf-sidebar-action-menu-panel .mat-menu-content {
width: 100%;
}
.adf-sidebar-action-menu-icon {
margin: 0;
}
.adf-sidebar-action-menu-icon div[sidebar-menu-expand-icon] {
display: flex;
align-items: center;
justify-content: center;
}
.adf-sidebar-action-menu {
width: 100%;
}
.adf-sidebar-action-menu-options {
width: 100% !important;
.mat-menu-item {
display: flex;
flex-direction: row;
align-items: center;
font-size: 14px;
color: mat-color($foreground, text, 0.54);
line-height: 48px;
box-shadow: none;
transform: none;
transition: unset;
font-weight: normal;
text-transform: capitalize;
color: mat-color($primary);
&:hover {
color: mat-color($accent);
}
}
.mat-menu-item[disabled],
.mat-menu-item[disabled]:hover {
color: mat-color($foreground, text, 0.38);
.mat-icon {
color: mat-color($foreground, text, 0.38);
}
}
}
}
+37 -29
View File
@@ -2,7 +2,12 @@
"$schema": "../../extension.schema.json", "$schema": "../../extension.schema.json",
"$name": "app", "$name": "app",
"$version": "1.0.0", "$version": "1.0.0",
"$references": ["plugin1.json", "dev.tools.json", "app.header.json"], "$references": [
"plugin1.json",
"dev.tools.json",
"app.header.json",
"app.create.json"
],
"rules": [ "rules": [
{ {
@@ -132,23 +137,9 @@
"features": { "features": {
"create": [ "create": [
{
"id": "app.create.folder",
"order": 100,
"icon": "create_new_folder",
"title": "APP.NEW_MENU.MENU_ITEMS.CREATE_FOLDER",
"description": "APP.NEW_MENU.TOOLTIPS.CREATE_FOLDER",
"description-disabled": "APP.NEW_MENU.TOOLTIPS.CREATE_FOLDER_NOT_ALLOWED",
"actions": {
"click": "CREATE_FOLDER"
},
"rules": {
"enabled": "app.navigation.folder.canCreate"
}
},
{ {
"id": "app.create.uploadFile", "id": "app.create.uploadFile",
"order": 200, "order": 100,
"icon": "file_upload", "icon": "file_upload",
"title": "APP.NEW_MENU.MENU_ITEMS.UPLOAD_FILE", "title": "APP.NEW_MENU.MENU_ITEMS.UPLOAD_FILE",
"description": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FILES", "description": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FILES",
@@ -162,7 +153,7 @@
}, },
{ {
"id": "app.create.uploadFolder", "id": "app.create.uploadFolder",
"order": 300, "order": 200,
"icon": "file_upload", "icon": "file_upload",
"title": "APP.NEW_MENU.MENU_ITEMS.UPLOAD_FOLDER", "title": "APP.NEW_MENU.MENU_ITEMS.UPLOAD_FOLDER",
"description": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FOLDERS", "description": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FOLDERS",
@@ -173,6 +164,35 @@
"rules": { "rules": {
"enabled": "app.navigation.folder.canUpload" "enabled": "app.navigation.folder.canUpload"
} }
},
{
"id": "app.create.separator.1",
"type": "separator",
"order": 300
},
{
"id": "app.create.folder",
"order": 400,
"icon": "create_new_folder",
"title": "APP.NEW_MENU.MENU_ITEMS.CREATE_FOLDER",
"description": "APP.NEW_MENU.TOOLTIPS.CREATE_FOLDER",
"description-disabled": "APP.NEW_MENU.TOOLTIPS.CREATE_FOLDER_NOT_ALLOWED",
"actions": {
"click": "CREATE_FOLDER"
},
"rules": {
"enabled": "app.navigation.folder.canCreate"
}
},
{
"id": "app.create.library",
"order": 600,
"title": "APP.NEW_MENU.MENU_ITEMS.CREATE_LIBRARY",
"description": "APP.NEW_MENU.TOOLTIPS.CREATE_LIBRARY",
"icon": "create_new_folder",
"actions": {
"click": "CREATE_LIBRARY"
}
} }
], ],
"navbar": [ "navbar": [
@@ -296,18 +316,6 @@
"visible": "app.trashcan.hasSelection" "visible": "app.trashcan.hasSelection"
} }
}, },
{
"id": "app.toolbar.createLibrary",
"order": 600,
"title": "Create Library",
"icon": "create_new_folder",
"actions": {
"click": "CREATE_LIBRARY"
},
"rules": {
"visible": "app.navigation.isLibraries"
}
},
{ {
"id": "app.toolbar.info", "id": "app.toolbar.info",
"type": "custom", "type": "custom",
+4 -2
View File
@@ -22,7 +22,8 @@
"MENU_ITEMS": { "MENU_ITEMS": {
"CREATE_FOLDER": "Create folder", "CREATE_FOLDER": "Create folder",
"UPLOAD_FILE": "Upload file", "UPLOAD_FILE": "Upload file",
"UPLOAD_FOLDER": "Upload folder" "UPLOAD_FOLDER": "Upload folder",
"CREATE_LIBRARY": "Create Library"
}, },
"TOOLTIPS": { "TOOLTIPS": {
"CREATE_FOLDER": "Create new folder", "CREATE_FOLDER": "Create new folder",
@@ -30,7 +31,8 @@
"UPLOAD_FILES": "Select files to upload", "UPLOAD_FILES": "Select files to upload",
"UPLOAD_FILES_NOT_ALLOWED": "Files cannot be uploaded whilst viewing the current items", "UPLOAD_FILES_NOT_ALLOWED": "Files cannot be uploaded whilst viewing the current items",
"UPLOAD_FOLDERS": "Select folders to upload", "UPLOAD_FOLDERS": "Select folders to upload",
"UPLOAD_FOLDERS_NOT_ALLOWED": "Folders cannot be uploaded whilst viewing the current items" "UPLOAD_FOLDERS_NOT_ALLOWED": "Folders cannot be uploaded whilst viewing the current items",
"CREATE_LIBRARY": "Create a new File Library"
} }
}, },
"BROWSE": { "BROWSE": {
+50
View File
@@ -0,0 +1,50 @@
{
"$schema": "../../../extension.schema.json",
"$name": "app.create",
"$version": "1.0.0",
"features": {
"create": [
{
"id": "app.test.create1",
"order": 10,
"icon": "extension",
"title": "Custom Create",
"type": "menu",
"children": [
{
"id": "level1.1",
"icon": "extension",
"title": "Level 1.1"
},
{
"id": "level1.separator",
"type": "separator"
},
{
"id": "level1.2",
"icon": "extension",
"title": "Level 1.2",
"type": "menu",
"children": [
{
"id": "level2.1",
"icon": "extension",
"title": "Level 2.1"
}
],
"rules": {
"enabled": "app.navigation.folder.canCreate"
}
}
]
},
{
"id": "app.create.separator",
"order": 20,
"type": "separator"
}
]
}
}
+3 -2
View File
@@ -3,9 +3,10 @@
@import '~@alfresco/adf-core/prebuilt-themes/adf-blue-orange.css'; @import '~@alfresco/adf-core/prebuilt-themes/adf-blue-orange.css';
@import 'app/ui/application'; @import 'app/ui/application';
body, html { body,
html {
height: 100%; height: 100%;
font-family: 'Muli', "Helvetica", "Arial", sans-serif !important; font-family: 'Muli', 'Helvetica', 'Arial', sans-serif !important;
} }
body { body {