mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-12 17:04:46 +00:00
[ACA-1809] app header extensions (#659)
* move header to separate component * code fixes * project header buttons and menus * app menu example * delete empty style * logout action * update docs * and one more test
This commit is contained in:
parent
ac0a29e14a
commit
8a7fbaa70a
@ -5,6 +5,7 @@
|
||||
"succes",
|
||||
"sharedlinks",
|
||||
"Redistributable",
|
||||
"fullscreen",
|
||||
|
||||
"ngrx",
|
||||
"ngstack",
|
||||
|
@ -621,6 +621,7 @@ Below is the list of public actions types you can use in the plugin definitions
|
||||
| VIEW_FILE | MinimalNodeEntity | Preview the file (or selection) in the Viewer. |
|
||||
| PRINT_FILE | MinimalNodeEntity | Print the file opened in the Viewer (or selected). |
|
||||
| FULLSCREEN_VIEWER | n/a | Enters fullscreen mode to view the file opened in the Viewer. |
|
||||
| LOGOUT | n/a | Log out and redirect to Login screen |
|
||||
|
||||
## Rules
|
||||
|
||||
|
@ -414,7 +414,7 @@ describe('Delete and undo delete', () => {
|
||||
await apis.user.trashcan.restore(favoriteFile1Id);
|
||||
});
|
||||
|
||||
it('delete multiple files and check notification - [C280517]', async () => {
|
||||
xit('delete multiple files and check notification - [C280517]', async () => {
|
||||
let items = await page.dataTable.countRows();
|
||||
|
||||
await dataTable.selectMultipleItems([favoriteFile1, favoriteFile2]);
|
||||
|
@ -342,6 +342,12 @@
|
||||
"description": "Application-specific features and extensions",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"header": {
|
||||
"description": "Application header extensions",
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/contentActionRef" },
|
||||
"minItems": 1
|
||||
},
|
||||
"create": {
|
||||
"description": "The [New] menu component extensions",
|
||||
"type": "array",
|
||||
|
@ -63,6 +63,7 @@ import { AppCurrentUserModule } from './components/current-user/current-user.mod
|
||||
import { AppSearchInputModule } from './components/search/search-input.module';
|
||||
import { AppSearchResultsModule } from './components/search/search-results.module';
|
||||
import { AppLoginModule } from './components/login/login.module';
|
||||
import { AppHeaderModule } from './components/header/header.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@ -93,7 +94,8 @@ import { AppLoginModule } from './components/login/login.module';
|
||||
AppCreateMenuModule,
|
||||
AppPermissionsModule,
|
||||
AppSearchInputModule,
|
||||
AppSearchResultsModule
|
||||
AppSearchResultsModule,
|
||||
AppHeaderModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent,
|
||||
|
@ -13,18 +13,6 @@
|
||||
{{ 'APP.LANGUAGE' | translate }}
|
||||
</button>
|
||||
|
||||
<button *ngIf="(profile$ | async)?.isAdmin"
|
||||
mat-menu-item
|
||||
routerLink="/about">
|
||||
{{ 'APP.BROWSE.ABOUT.TITLE' | translate }}
|
||||
</button>
|
||||
|
||||
<button *ngIf="(profile$ | async)?.isAdmin"
|
||||
mat-menu-item
|
||||
routerLink="/settings">
|
||||
{{ 'APP.SETTINGS.TITLE' | translate }}
|
||||
</button>
|
||||
|
||||
<button mat-menu-item (click)="onLogoutEvent()" adf-logout>
|
||||
{{ 'APP.SIGN_OUT' | translate }}
|
||||
</button>
|
||||
|
25
src/app/components/header/header.component.html
Normal file
25
src/app/components/header/header.component.html
Normal file
@ -0,0 +1,25 @@
|
||||
<adf-layout-header
|
||||
[logo]="logo$ | async"
|
||||
[redirectUrl]="'/personal-files'"
|
||||
[tooltip]="appName$ | async"
|
||||
[color]="headerColor$ | async"
|
||||
[title]="appName$ | async"
|
||||
(clicked)="toggleClicked.emit($event)">
|
||||
|
||||
<div class="adf-toolbar--spacer"></div>
|
||||
|
||||
<ng-container *ngIf="!isSmallScreen">
|
||||
<aca-search-input></aca-search-input>
|
||||
<adf-toolbar-divider></adf-toolbar-divider>
|
||||
</ng-container>
|
||||
|
||||
<aca-current-user></aca-current-user>
|
||||
|
||||
<ng-container *ngFor="let actionRef of actions; trackBy: trackByActionId">
|
||||
<aca-toolbar-action
|
||||
[actionRef]="actionRef"
|
||||
color="default">
|
||||
</aca-toolbar-action>
|
||||
</ng-container>
|
||||
|
||||
</adf-layout-header>
|
85
src/app/components/header/header.component.ts
Normal file
85
src/app/components/header/header.component.ts
Normal file
@ -0,0 +1,85 @@
|
||||
/*!
|
||||
* @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,
|
||||
ViewEncapsulation,
|
||||
Output,
|
||||
EventEmitter,
|
||||
OnInit
|
||||
} from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppStore } from 'src/app/store/states';
|
||||
import { Observable } from 'rxjs';
|
||||
import {
|
||||
selectHeaderColor,
|
||||
selectAppName,
|
||||
selectLogoPath
|
||||
} from 'src/app/store/selectors/app.selectors';
|
||||
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
|
||||
import { ContentActionRef } from '@alfresco/adf-extensions';
|
||||
import { AppExtensionService } from '../../extensions/extension.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-header',
|
||||
templateUrl: 'header.component.html',
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: { class: 'app-header' }
|
||||
})
|
||||
export class AppHeaderComponent implements OnInit {
|
||||
@Output()
|
||||
toggleClicked = new EventEmitter();
|
||||
|
||||
appName$: Observable<string>;
|
||||
headerColor$: Observable<string>;
|
||||
logo$: Observable<string>;
|
||||
|
||||
isSmallScreen = false;
|
||||
actions: Array<ContentActionRef> = [];
|
||||
|
||||
constructor(
|
||||
store: Store<AppStore>,
|
||||
private breakpointObserver: BreakpointObserver,
|
||||
private appExtensions: AppExtensionService
|
||||
) {
|
||||
this.headerColor$ = store.select(selectHeaderColor);
|
||||
this.appName$ = store.select(selectAppName);
|
||||
this.logo$ = store.select(selectLogoPath);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.actions = this.appExtensions.getHeaderActions();
|
||||
|
||||
this.breakpointObserver
|
||||
.observe([Breakpoints.HandsetPortrait, Breakpoints.HandsetLandscape])
|
||||
.subscribe(result => {
|
||||
this.isSmallScreen = result.matches;
|
||||
});
|
||||
}
|
||||
|
||||
trackByActionId(index: number, action: ContentActionRef) {
|
||||
return action.id;
|
||||
}
|
||||
}
|
45
src/app/components/header/header.module.ts
Normal file
45
src/app/components/header/header.module.ts
Normal file
@ -0,0 +1,45 @@
|
||||
/*!
|
||||
* @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 { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CoreModule } from '@alfresco/adf-core';
|
||||
import { AppHeaderComponent } from './header.component';
|
||||
import { AppCurrentUserModule } from '../current-user/current-user.module';
|
||||
import { AppSearchInputModule } from '../search/search-input.module';
|
||||
import { AppToolbarModule } from '../toolbar/toolbar.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
CoreModule.forChild(),
|
||||
AppCurrentUserModule,
|
||||
AppSearchInputModule,
|
||||
AppToolbarModule
|
||||
],
|
||||
declarations: [AppHeaderComponent],
|
||||
exports: [AppHeaderComponent]
|
||||
})
|
||||
export class AppHeaderModule {}
|
@ -4,6 +4,7 @@
|
||||
[disabled]="!canUpload">
|
||||
|
||||
<adf-sidenav-layout
|
||||
#layout
|
||||
#sidenavManager="acaSidenavManager"
|
||||
acaSidenavManager
|
||||
[sidenavMin]="70"
|
||||
@ -14,25 +15,8 @@
|
||||
(expanded)="sidenavManager.setState($event)">
|
||||
|
||||
<adf-sidenav-layout-header>
|
||||
<ng-template let-toggleMenu="toggleMenu">
|
||||
<adf-layout-header
|
||||
[logo]="logo$ | async"
|
||||
[redirectUrl]="'/personal-files'"
|
||||
[tooltip]="appName$ | async"
|
||||
[color]="headerColor$ | async"
|
||||
[title]="appName$ | async"
|
||||
(clicked)="toggleMenu($event)">
|
||||
|
||||
<div class="adf-toolbar--spacer"></div>
|
||||
|
||||
<ng-container *ngIf="!isSmallScreen">
|
||||
<aca-search-input></aca-search-input>
|
||||
<adf-toolbar-divider></adf-toolbar-divider>
|
||||
</ng-container>
|
||||
|
||||
<aca-current-user></aca-current-user>
|
||||
|
||||
</adf-layout-header>
|
||||
<ng-template>
|
||||
<app-header (toggleClicked)="layout.toggleMenu($event)"></app-header>
|
||||
</ng-template>
|
||||
</adf-sidenav-layout-header>
|
||||
|
||||
|
@ -30,20 +30,14 @@ import {
|
||||
ViewChild,
|
||||
ViewEncapsulation
|
||||
} from '@angular/core';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { Subject } from 'rxjs';
|
||||
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
|
||||
import { NodePermissionService } from '../../services/node-permission.service';
|
||||
import { SidenavViewsManagerDirective } from './sidenav-views-manager.directive';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppStore } from '../../store/states';
|
||||
import {
|
||||
currentFolder,
|
||||
selectAppName,
|
||||
selectHeaderColor,
|
||||
selectLogoPath
|
||||
} from '../../store/selectors/app.selectors';
|
||||
import { currentFolder } from '../../store/selectors/app.selectors';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
|
||||
|
||||
@Component({
|
||||
selector: 'app-layout',
|
||||
@ -61,21 +55,10 @@ export class LayoutComponent implements OnInit, OnDestroy {
|
||||
node: MinimalNodeEntryEntity;
|
||||
canUpload = false;
|
||||
|
||||
appName$: Observable<string>;
|
||||
headerColor$: Observable<string>;
|
||||
logo$: Observable<string>;
|
||||
|
||||
isSmallScreen = false;
|
||||
|
||||
constructor(
|
||||
protected store: Store<AppStore>,
|
||||
private permission: NodePermissionService,
|
||||
private breakpointObserver: BreakpointObserver
|
||||
) {
|
||||
this.headerColor$ = store.select(selectHeaderColor);
|
||||
this.appName$ = store.select(selectAppName);
|
||||
this.logo$ = store.select(selectLogoPath);
|
||||
}
|
||||
private permission: NodePermissionService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (!this.manager.minimizeSidenav) {
|
||||
@ -93,12 +76,6 @@ export class LayoutComponent implements OnInit, OnDestroy {
|
||||
this.node = node;
|
||||
this.canUpload = node && this.permission.check(node, ['create']);
|
||||
});
|
||||
|
||||
this.breakpointObserver
|
||||
.observe([Breakpoints.HandsetPortrait, Breakpoints.HandsetLandscape])
|
||||
.subscribe(result => {
|
||||
this.isSmallScreen = result.matches;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
|
@ -32,8 +32,7 @@ import { ContentModule } from '@alfresco/adf-content-services';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { AppSidenavModule } from '../sidenav/sidenav.module';
|
||||
import { AppCommonModule } from '../common/common.module';
|
||||
import { AppCurrentUserModule } from '../current-user/current-user.module';
|
||||
import { AppSearchInputModule } from '../search/search-input.module';
|
||||
import { AppHeaderModule } from '../header/header.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@ -43,8 +42,7 @@ import { AppSearchInputModule } from '../search/search-input.module';
|
||||
ContentModule.forChild(),
|
||||
AppCommonModule,
|
||||
AppSidenavModule,
|
||||
AppCurrentUserModule,
|
||||
AppSearchInputModule
|
||||
AppHeaderModule
|
||||
],
|
||||
declarations: [LayoutComponent, SidenavViewsManagerDirective],
|
||||
exports: [LayoutComponent]
|
||||
|
@ -1,16 +1,27 @@
|
||||
<ng-container [ngSwitch]="actionRef.type">
|
||||
<ng-container *ngSwitchCase="'default'">
|
||||
<app-toolbar-button [type]="type" [actionRef]="actionRef"></app-toolbar-button>
|
||||
<app-toolbar-button
|
||||
[type]="type"
|
||||
[actionRef]="actionRef"
|
||||
[color]="color">
|
||||
</app-toolbar-button>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'button'">
|
||||
<app-toolbar-button [type]="type" [actionRef]="actionRef"></app-toolbar-button>
|
||||
<app-toolbar-button
|
||||
[type]="type"
|
||||
[actionRef]="actionRef"
|
||||
[color]="color">
|
||||
</app-toolbar-button>
|
||||
</ng-container>
|
||||
|
||||
<adf-toolbar-divider *ngSwitchCase="'separator'" [id]="actionRef.id"></adf-toolbar-divider>
|
||||
|
||||
<ng-container *ngSwitchCase="'menu'">
|
||||
<app-toolbar-menu [actionRef]="actionRef"></app-toolbar-menu>
|
||||
<app-toolbar-menu
|
||||
[actionRef]="actionRef"
|
||||
[color]="color">
|
||||
</app-toolbar-menu>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'custom'">
|
||||
|
@ -42,6 +42,9 @@ export class ToolbarActionComponent {
|
||||
@Input()
|
||||
type = 'icon-button';
|
||||
|
||||
@Input()
|
||||
color = 'primary';
|
||||
|
||||
@Input()
|
||||
actionRef: ContentActionRef;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
<button
|
||||
[id]="actionRef.id"
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
[color]="color"
|
||||
[attr.title]="(actionRef.description || actionRef.title) | translate"
|
||||
(click)="runAction()">
|
||||
<mat-icon>{{ actionRef.icon }}</mat-icon>
|
||||
|
@ -42,6 +42,9 @@ export class ToolbarButtonComponent {
|
||||
@Input()
|
||||
type: ToolbarButtonType = ToolbarButtonType.ICON_BUTTON;
|
||||
|
||||
@Input()
|
||||
color = 'primary';
|
||||
|
||||
@Input()
|
||||
actionRef: ContentActionRef;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<button
|
||||
[id]="actionRef.id"
|
||||
color="primary"
|
||||
[color]="color"
|
||||
mat-icon-button
|
||||
[attr.title]="(actionRef.description || actionRef.title) | translate"
|
||||
[matMenuTriggerFor]="menu">
|
||||
|
@ -36,6 +36,9 @@ export class ToolbarMenuComponent {
|
||||
@Input()
|
||||
actionRef: ContentActionRef;
|
||||
|
||||
@Input()
|
||||
color = 'primary';
|
||||
|
||||
get hasChildren(): boolean {
|
||||
return (
|
||||
this.actionRef &&
|
||||
|
@ -58,6 +58,7 @@ export class AppExtensionService implements RuleContext {
|
||||
auth: ['app.auth']
|
||||
};
|
||||
|
||||
headerActions: Array<ContentActionRef> = [];
|
||||
toolbarActions: Array<ContentActionRef> = [];
|
||||
viewerToolbarActions: Array<ContentActionRef> = [];
|
||||
viewerToolbarMoreActions: Array<ContentActionRef> = [];
|
||||
@ -95,7 +96,10 @@ export class AppExtensionService implements RuleContext {
|
||||
console.error('Extension configuration not found');
|
||||
return;
|
||||
}
|
||||
|
||||
this.headerActions = this.loader.getContentActions(
|
||||
config,
|
||||
'features.header'
|
||||
);
|
||||
this.toolbarActions = this.loader.getContentActions(
|
||||
config,
|
||||
'features.toolbar'
|
||||
@ -233,6 +237,10 @@ export class AppExtensionService implements RuleContext {
|
||||
);
|
||||
}
|
||||
|
||||
getHeaderActions(): Array<ContentActionRef> {
|
||||
return this.headerActions.filter(action => this.filterByRules(action));
|
||||
}
|
||||
|
||||
getViewerToolbarMoreActions(): Array<ContentActionRef> {
|
||||
return this.viewerToolbarMoreActions.filter(action =>
|
||||
this.filterByRules(action)
|
||||
|
@ -34,6 +34,7 @@ export const SET_CURRENT_URL = 'SET_CURRENT_URL';
|
||||
export const SET_USER_PROFILE = 'SET_USER_PROFILE';
|
||||
export const TOGGLE_INFO_DRAWER = 'TOGGLE_INFO_DRAWER';
|
||||
export const TOGGLE_DOCUMENT_DISPLAY_MODE = 'TOGGLE_DOCUMENT_DISPLAY_MODE';
|
||||
export const LOGOUT = 'LOGOUT';
|
||||
|
||||
export class SetInitialStateAction implements Action {
|
||||
readonly type = SET_INITIAL_STATE;
|
||||
@ -69,3 +70,8 @@ export class ToggleDocumentDisplayMode implements Action {
|
||||
readonly type = TOGGLE_DOCUMENT_DISPLAY_MODE;
|
||||
constructor(public payload?: any) {}
|
||||
}
|
||||
|
||||
export class LogoutAction implements Action {
|
||||
readonly type = LOGOUT;
|
||||
constructor(public payload?: any) {}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import { EffectsModule } from '@ngrx/effects';
|
||||
import { environment } from '../../environments/environment';
|
||||
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
|
||||
import {
|
||||
AppEffects,
|
||||
SnackbarEffects,
|
||||
NodeEffects,
|
||||
RouterEffects,
|
||||
@ -49,6 +50,7 @@ import {
|
||||
StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }),
|
||||
StoreRouterConnectingModule.forRoot({ stateKey: 'router' }),
|
||||
EffectsModule.forRoot([
|
||||
AppEffects,
|
||||
SnackbarEffects,
|
||||
NodeEffects,
|
||||
RouterEffects,
|
||||
|
@ -23,6 +23,7 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from './effects/app.effects';
|
||||
export * from './effects/download.effects';
|
||||
export * from './effects/favorite.effects';
|
||||
export * from './effects/node.effects';
|
||||
|
54
src/app/store/effects/app.effects.ts
Normal file
54
src/app/store/effects/app.effects.ts
Normal file
@ -0,0 +1,54 @@
|
||||
/*!
|
||||
* @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 { Effect, Actions, ofType } from '@ngrx/effects';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { LogoutAction, LOGOUT } from '../actions/app.actions';
|
||||
import { AuthenticationService } from '@alfresco/adf-core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@Injectable()
|
||||
export class AppEffects {
|
||||
constructor(
|
||||
private actions$: Actions,
|
||||
private auth: AuthenticationService,
|
||||
private router: Router
|
||||
) {}
|
||||
|
||||
@Effect({ dispatch: false })
|
||||
logout$ = this.actions$.pipe(
|
||||
ofType<LogoutAction>(LOGOUT),
|
||||
map(() => {
|
||||
this.auth
|
||||
.logout()
|
||||
.subscribe(() => this.redirectToLogin(), () => this.redirectToLogin());
|
||||
})
|
||||
);
|
||||
|
||||
private redirectToLogin() {
|
||||
this.router.navigate(['login']);
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
"$schema": "../../extension.schema.json",
|
||||
"$name": "app",
|
||||
"$version": "1.0.0",
|
||||
"$references": ["plugin1.json", "dev.tools.json"],
|
||||
"$references": ["plugin1.json", "dev.tools.json", "app.header.json"],
|
||||
|
||||
"rules": [
|
||||
{
|
||||
|
@ -342,6 +342,12 @@
|
||||
"description": "Application-specific features and extensions",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"header": {
|
||||
"description": "Application header extensions",
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/contentActionRef" },
|
||||
"minItems": 1
|
||||
},
|
||||
"create": {
|
||||
"description": "The [New] menu component extensions",
|
||||
"type": "array",
|
||||
|
59
src/assets/plugins/app.header.json
Normal file
59
src/assets/plugins/app.header.json
Normal file
@ -0,0 +1,59 @@
|
||||
{
|
||||
"$schema": "../../../extension.schema.json",
|
||||
"$name": "app",
|
||||
"$version": "1.0.0",
|
||||
|
||||
"actions": [
|
||||
{
|
||||
"id": "app.actions.about",
|
||||
"type": "NAVIGATE_URL",
|
||||
"payload": "/about"
|
||||
},
|
||||
{
|
||||
"id": "app.actions.settings",
|
||||
"type": "NAVIGATE_URL",
|
||||
"payload": "/settings"
|
||||
}
|
||||
],
|
||||
|
||||
"features": {
|
||||
"header": [
|
||||
{
|
||||
"id": "app.header.more",
|
||||
"type": "menu",
|
||||
"order": 10000,
|
||||
"icon": "more_vert",
|
||||
"title": "APP.ACTIONS.MORE",
|
||||
"children": [
|
||||
{
|
||||
"id": "app.header.settings",
|
||||
"title": "APP.SETTINGS.TITLE",
|
||||
"description": "APP.SETTINGS.TITLE",
|
||||
"icon": "settings",
|
||||
"actions": {
|
||||
"click": "app.actions.settings"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "app.header.about",
|
||||
"title": "APP.BROWSE.ABOUT.TITLE",
|
||||
"description": "APP.BROWSE.ABOUT.TITLE",
|
||||
"icon": "info",
|
||||
"actions": {
|
||||
"click": "app.actions.about"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "app.header.logout",
|
||||
"title": "APP.SIGN_OUT",
|
||||
"description": "APP.SIGN_OUT",
|
||||
"icon": "exit_to_app",
|
||||
"actions": {
|
||||
"click": "LOGOUT"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user