diff --git a/.github/plint.yml b/.github/plint.yml index 9972c5003..27172f700 100644 --- a/.github/plint.yml +++ b/.github/plint.yml @@ -2,11 +2,21 @@ modules: - pr.prettier - pr.spellcheck +prettier: + exclude: + - '*.json' + spellcheck: + dictionaries: + - html + - en-gb + - en_US words: - plint - ngrx - qshare - snackbar + - exif + - docx exclude: - src/assets/app.extensions.json diff --git a/docs/extending/application-features.md b/docs/extending/application-features.md index 6b318815d..2bca3efa0 100644 --- a/docs/extending/application-features.md +++ b/docs/extending/application-features.md @@ -363,6 +363,7 @@ Viewer component in ACA supports the following extension points: - Toolbar actions - `More` toolbar actions - `Open With` actions +- Rules ```json { @@ -547,6 +548,35 @@ and invoke it from the custom `Open With` menu entry called `Snackbar`. As with other content actions, custom plugins can disable, update or extend `Open With` actions. +### Rules + +You can provide global rules for the Viewer by utilizing the `features.viewer.rules` object: + +```ts +export interface ViewerRules { + /** + * Checks if user can preview the node. + */ + canPreview?: string; +} +``` + +For example: + +```json +{ + "features": { + "viewer": { + "rules": { + "canPreview": "customRule" + } + } + } +} +``` + +The rule should return `true` if node preview is allowed, otherwise `false`. + ## Content metadata presets The content metadata presets are needed by the [Content Metadata Component](https://www.alfresco.com/abn/adf/docs/content-services/content-metadata-card.component/) to render the properties of metadata aspects for a given node. diff --git a/extension.schema.json b/extension.schema.json index 678b8cc19..c8357a764 100644 --- a/extension.schema.json +++ b/extension.schema.json @@ -684,6 +684,16 @@ "description": "Viewer component extensions", "type": "object", "properties": { + "rules": { + "description": "Viewer rules", + "type": "object", + "properties": { + "canPreview": { + "description": "Controls whether preview is enabled for particular node", + "type": "string" + } + } + }, "openWith": { "description": "The [Open With] menu extensions", "type": "array", diff --git a/src/app/extensions/extension.service.ts b/src/app/extensions/extension.service.ts index d8cba2084..060f39c52 100644 --- a/src/app/extensions/extension.service.ts +++ b/src/app/extensions/extension.service.ts @@ -53,7 +53,8 @@ import { } from '@alfresco/adf-extensions'; import { AppConfigService, AuthenticationService } from '@alfresco/adf-core'; import { BehaviorSubject, Observable } from 'rxjs'; -import { RepositoryInfo } from '@alfresco/js-api'; +import { RepositoryInfo, NodeEntry } from '@alfresco/js-api'; +import { ViewerRules } from './viewer.rules'; @Injectable({ providedIn: 'root' @@ -76,6 +77,7 @@ export class AppExtensionService implements RuleContext { navbar: Array = []; sidebar: Array = []; contentMetadata: any; + viewerRules: ViewerRules = {}; documentListPresets: { files: Array; @@ -184,6 +186,10 @@ export class AppExtensionService implements RuleContext { searchLibraries: this.getDocumentListPreset(config, 'search-libraries') }; + if (config.features && config.features.viewer) { + this.viewerRules = (config.features.viewer['rules'] || {}); + } + this.registerIcons(config); const references = (config.$references || []) @@ -504,7 +510,37 @@ export class AppExtensionService implements RuleContext { } } + // todo: move to ADF/RuleService + isRuleDefined(ruleId: string): boolean { + return ruleId && this.getEvaluator(ruleId) ? true : false; + } + + // todo: move to ADF/RuleService + evaluateRule(ruleId: string, ...args: any[]): boolean { + const evaluator = this.getEvaluator(ruleId); + + if (evaluator) { + return evaluator(this, ...args); + } + + return false; + } + getEvaluator(key: string): RuleEvaluator { return this.extensions.getEvaluator(key); } + + canPreviewNode(node: NodeEntry) { + const rules = this.viewerRules; + + if (this.isRuleDefined(rules.canPreview)) { + const canPreview = this.evaluateRule(rules.canPreview, node); + + if (!canPreview) { + return false; + } + } + + return true; + } } diff --git a/src/app/extensions/viewer.rules.ts b/src/app/extensions/viewer.rules.ts new file mode 100644 index 000000000..500ce6585 --- /dev/null +++ b/src/app/extensions/viewer.rules.ts @@ -0,0 +1,31 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2019 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 . + */ + +export interface ViewerRules { + /** + * Checks if user can preview the node. + */ + canPreview?: string; +} diff --git a/src/app/store/effects/viewer.effects.ts b/src/app/store/effects/viewer.effects.ts index 31ccc90cc..2c5f79a30 100644 --- a/src/app/store/effects/viewer.effects.ts +++ b/src/app/store/effects/viewer.effects.ts @@ -37,6 +37,7 @@ import { } from '@alfresco/aca-shared/store'; import { Router } from '@angular/router'; import { Store, createSelector } from '@ngrx/store'; +import { AppExtensionService } from '../../extensions/extension.service'; export const fileToPreview = createSelector( getAppSelection, @@ -54,7 +55,8 @@ export class ViewerEffects { constructor( private store: Store, private actions$: Actions, - private router: Router + private router: Router, + private extensions: AppExtensionService ) {} @Effect({ dispatch: false }) @@ -94,7 +96,10 @@ export class ViewerEffects { if (action.payload && action.payload.entry) { const { id, nodeId, isFile } = action.payload.entry; - if (isFile || nodeId) { + if ( + this.extensions.canPreviewNode(action.payload) && + (isFile || nodeId) + ) { this.displayPreview(nodeId || id, action.parentId); } } else { @@ -105,7 +110,10 @@ export class ViewerEffects { if (result.selection && result.selection.file) { const { id, nodeId, isFile } = result.selection.file.entry; - if (isFile || nodeId) { + if ( + this.extensions.canPreviewNode(action.payload) && + (isFile || nodeId) + ) { const parentId = result.folder ? result.folder.id : null; this.displayPreview(nodeId || id, parentId); }