@yuuvis/client-shell-core 2.20.1 → 3.0.0-beta.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/index.js +15 -0
- package/esm2022/index.js.map +1 -0
- package/esm2022/lib/client-shell.assets.js +12 -0
- package/esm2022/lib/client-shell.assets.js.map +1 -0
- package/esm2022/lib/models/client-shell.interface.js +5 -0
- package/esm2022/lib/models/client-shell.interface.js.map +1 -0
- package/esm2022/lib/services/command-palette/command-palette/command-palette.component.js +94 -0
- package/esm2022/lib/services/command-palette/command-palette/command-palette.component.js.map +1 -0
- package/esm2022/lib/services/command-palette/command-palette.interface.js +2 -0
- package/esm2022/lib/services/command-palette/command-palette.interface.js.map +1 -0
- package/esm2022/lib/services/command-palette/command-palette.service.js +120 -0
- package/esm2022/lib/services/command-palette/command-palette.service.js.map +1 -0
- package/esm2022/lib/services/feature/feature.guard.js +9 -0
- package/esm2022/lib/services/feature/feature.guard.js.map +1 -0
- package/esm2022/lib/services/feature/feature.interface.js +2 -0
- package/esm2022/lib/services/feature/feature.interface.js.map +1 -0
- package/esm2022/lib/services/feature/feature.providers.js +14 -0
- package/esm2022/lib/services/feature/feature.providers.js.map +1 -0
- package/esm2022/lib/services/feature/feature.service.js +141 -0
- package/esm2022/lib/services/feature/feature.service.js.map +1 -0
- package/esm2022/lib/services/feature/index.js +5 -0
- package/esm2022/lib/services/feature/index.js.map +1 -0
- package/esm2022/lib/services/shell/noop.extension.js +13 -0
- package/esm2022/lib/services/shell/noop.extension.js.map +1 -0
- package/esm2022/lib/services/shell/requirements.parser.js +7 -0
- package/esm2022/lib/services/shell/requirements.parser.js.map +1 -0
- package/esm2022/lib/services/shell/shell.bootstrap.js +84 -0
- package/esm2022/lib/services/shell/shell.bootstrap.js.map +1 -0
- package/esm2022/lib/services/shell/shell.providers.js +20 -0
- package/esm2022/lib/services/shell/shell.providers.js.map +1 -0
- package/esm2022/lib/services/shell/shell.service.js +455 -0
- package/esm2022/lib/services/shell/shell.service.js.map +1 -0
- package/esm2022/lib/services/shell-config/shell-config.const.js +17 -0
- package/esm2022/lib/services/shell-config/shell-config.const.js.map +1 -0
- package/esm2022/lib/services/shell-config/shell-config.interface.js +2 -0
- package/esm2022/lib/services/shell-config/shell-config.interface.js.map +1 -0
- package/esm2022/lib/services/shell-config/shell-config.service.js +100 -0
- package/esm2022/lib/services/shell-config/shell-config.service.js.map +1 -0
- package/esm2022/lib/services/shell-notifications/shell-notifications.interface.js +2 -0
- package/esm2022/lib/services/shell-notifications/shell-notifications.interface.js.map +1 -0
- package/esm2022/lib/services/shell-notifications/shell-notifications.service.js +84 -0
- package/esm2022/lib/services/shell-notifications/shell-notifications.service.js.map +1 -0
- package/esm2022/lib/tile-extension.interface.js +2 -0
- package/esm2022/lib/tile-extension.interface.js.map +1 -0
- package/esm2022/yuuvis-client-shell-core.js +5 -0
- package/esm2022/yuuvis-client-shell-core.js.map +1 -0
- package/lib/services/command-palette/command-palette/command-palette.component.d.ts +2 -2
- package/package.json +10 -10
- package/yuuvis-client-shell-core.d.ts +5 -0
- package/esm2022/index.mjs +0 -15
- package/esm2022/lib/client-shell.assets.mjs +0 -12
- package/esm2022/lib/models/client-shell.interface.mjs +0 -5
- package/esm2022/lib/services/command-palette/command-palette/command-palette.component.mjs +0 -101
- package/esm2022/lib/services/command-palette/command-palette.interface.mjs +0 -2
- package/esm2022/lib/services/command-palette/command-palette.service.mjs +0 -120
- package/esm2022/lib/services/feature/feature.guard.mjs +0 -9
- package/esm2022/lib/services/feature/feature.interface.mjs +0 -2
- package/esm2022/lib/services/feature/feature.providers.mjs +0 -14
- package/esm2022/lib/services/feature/feature.service.mjs +0 -141
- package/esm2022/lib/services/feature/index.mjs +0 -5
- package/esm2022/lib/services/shell/noop.extension.mjs +0 -13
- package/esm2022/lib/services/shell/requirements.parser.mjs +0 -7
- package/esm2022/lib/services/shell/shell.bootstrap.mjs +0 -84
- package/esm2022/lib/services/shell/shell.providers.mjs +0 -20
- package/esm2022/lib/services/shell/shell.service.mjs +0 -456
- package/esm2022/lib/services/shell-config/shell-config.const.mjs +0 -17
- package/esm2022/lib/services/shell-config/shell-config.interface.mjs +0 -2
- package/esm2022/lib/services/shell-config/shell-config.service.mjs +0 -100
- package/esm2022/lib/services/shell-notifications/shell-notifications.interface.mjs +0 -2
- package/esm2022/lib/services/shell-notifications/shell-notifications.service.mjs +0 -84
- package/esm2022/lib/tile-extension.interface.mjs +0 -2
- package/esm2022/yuuvis-client-shell-core.mjs +0 -5
package/esm2022/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from './lib/models/client-shell.interface';
|
|
2
|
+
export * from './lib/services/command-palette/command-palette.interface';
|
|
3
|
+
export * from './lib/services/command-palette/command-palette.service';
|
|
4
|
+
export * from './lib/services/command-palette/command-palette/command-palette.component';
|
|
5
|
+
export * from './lib/services/shell-notifications/shell-notifications.interface';
|
|
6
|
+
export * from './lib/services/shell-notifications/shell-notifications.service';
|
|
7
|
+
export * from './lib/services/shell/shell.service';
|
|
8
|
+
export * from './lib/tile-extension.interface';
|
|
9
|
+
export * from './lib/services/shell/shell.bootstrap';
|
|
10
|
+
export * from './lib/services/shell/shell.providers';
|
|
11
|
+
export * from './lib/services/feature';
|
|
12
|
+
export * from './lib/services/shell-config/shell-config.service';
|
|
13
|
+
export * from './lib/services/shell-config/shell-config.interface';
|
|
14
|
+
export * from './lib/services/shell-config/shell-config.const';
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../libs/yuuvis/client-shell-core/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qCAAqC,CAAC;AACpD,cAAc,0DAA0D,CAAC;AACzE,cAAc,wDAAwD,CAAC;AACvE,cAAc,0EAA0E,CAAC;AACzF,cAAc,kEAAkE,CAAC;AACjF,cAAc,gEAAgE,CAAC;AAC/E,cAAc,oCAAoC,CAAC;AACnD,cAAc,gCAAgC,CAAC;AAE/C,cAAc,sCAAsC,CAAC;AACrD,cAAc,sCAAsC,CAAC;AACrD,cAAc,wBAAwB,CAAC;AACvC,cAAc,kDAAkD,CAAC;AACjE,cAAc,oDAAoD,CAAC;AACnE,cAAc,gDAAgD,CAAC","sourcesContent":["export * from './lib/models/client-shell.interface';\nexport * from './lib/services/command-palette/command-palette.interface';\nexport * from './lib/services/command-palette/command-palette.service';\nexport * from './lib/services/command-palette/command-palette/command-palette.component';\nexport * from './lib/services/shell-notifications/shell-notifications.interface';\nexport * from './lib/services/shell-notifications/shell-notifications.service';\nexport * from './lib/services/shell/shell.service';\nexport * from './lib/tile-extension.interface';\n\nexport * from './lib/services/shell/shell.bootstrap';\nexport * from './lib/services/shell/shell.providers';\nexport * from './lib/services/feature';\nexport * from './lib/services/shell-config/shell-config.service';\nexport * from './lib/services/shell-config/shell-config.interface';\nexport * from './lib/services/shell-config/shell-config.const';\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// default assets for the client shell
|
|
2
|
+
export const CLIENT_SHELL_ASSETS = {
|
|
3
|
+
appIcon: {
|
|
4
|
+
svgIcon: '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 64 64">' +
|
|
5
|
+
' <path fill="var(--ymt-brand, #181C21)" d="M12 0h40v44a8 8 0 0 1-8 8H20a8 8 0 0 1-8-8V0Z"/>' +
|
|
6
|
+
' <path fill="var(--ymt-on-brand, #E0E2EA)" d="m40 24-4.534 6.931a51.188 51.188 0 0 0-1.523 2.462s-.583-1.07-1.425-2.332L27.79 24H24l8.324 12.567V40h3.66v-3.757L40 29.7V24Z"/>' +
|
|
7
|
+
'</svg>',
|
|
8
|
+
iconName: 'app_logo'
|
|
9
|
+
},
|
|
10
|
+
shellIconNamespace: 'shellIcons'
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=client-shell.assets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-shell.assets.js","sourceRoot":"","sources":["../../../../../../libs/yuuvis/client-shell-core/src/lib/client-shell.assets.ts"],"names":[],"mappings":"AAEA,sCAAsC;AACtC,MAAM,CAAC,MAAM,mBAAmB,GAAsB;IACpD,OAAO,EAAE;QACP,OAAO,EACL,0EAA0E;YAC1E,8FAA8F;YAC9F,iLAAiL;YACjL,QAAQ;QACV,QAAQ,EAAE,UAAU;KACrB;IACD,kBAAkB,EAAE,YAAY;CACjC,CAAC","sourcesContent":["import { ClientShellConfig } from './models/client-shell.interface';\n\n// default assets for the client shell\nexport const CLIENT_SHELL_ASSETS: ClientShellConfig = {\n appIcon: {\n svgIcon:\n '<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 64 64\">' +\n ' <path fill=\"var(--ymt-brand, #181C21)\" d=\"M12 0h40v44a8 8 0 0 1-8 8H20a8 8 0 0 1-8-8V0Z\"/>' +\n ' <path fill=\"var(--ymt-on-brand, #E0E2EA)\" d=\"m40 24-4.534 6.931a51.188 51.188 0 0 0-1.523 2.462s-.583-1.07-1.425-2.332L27.79 24H24l8.324 12.567V40h3.66v-3.757L40 29.7V24Z\"/>' +\n '</svg>',\n iconName: 'app_logo'\n },\n shellIconNamespace: 'shellIcons'\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-shell.interface.js","sourceRoot":"","sources":["../../../../../../../libs/yuuvis/client-shell-core/src/lib/models/client-shell.interface.ts"],"names":[],"mappings":"AA+FA,MAAM,CAAN,IAAY,cAEX;AAFD,WAAY,cAAc;IACxB,mCAAiB,CAAA;AACnB,CAAC,EAFW,cAAc,KAAd,cAAc,QAEzB","sourcesContent":["import { Type } from '@angular/core';\nimport { Route } from '@angular/router';\nimport { ObjectTypeFlavor } from '@yuuvis/client-core';\nimport { Observable } from 'rxjs';\n\nexport interface ClientShellExtension {\n init: () => Promise<any> | Observable<any>;\n}\n\nexport interface ClientShellConfig {\n appIcon?: {\n svgIcon?: string;\n iconName: string;\n };\n shellIconNamespace?: string;\n}\n\n// Todo: write documentation\nexport interface App extends Route {\n id: string;\n svgIcon?: string;\n iconName: string;\n title: string;\n // user roles/groups that are allowed/denied to use the app\n permissions?: AppPermission;\n options?: AppOptions;\n}\n\nexport interface AppOptions {\n // whether or not to use shells app header layout\n appHeader?: boolean;\n // using app header layout this claim will be placed next to (below) the apps name\n // key to be used for translation. If a key is provided the appClaim will\n // be set to the translated value of the key\n appClaimKey?: string;\n // claim to show as is\n appClaim?: string;\n // whether or not to list the app in the shells sidenav\n hideFromNav?: boolean;\n}\n\nexport interface AppPermission {\n allow: string[];\n deny: string[];\n}\n\nexport interface AccentColor {\n label: string;\n name: string;\n tone: string;\n}\n\n// Interface for apps to expose own settings to be hooked into\n// shell settings page\nexport interface ShellAppSettings {\n appID: string;\n // label for the settings group (e.g. the apps name)\n label: string;\n // component responsible for rendering the settings\n component: Type<any>;\n}\nexport interface ShellAppSettingProperty {\n label: string;\n name: string;\n // 'string' | 'number' | 'boolean' | 'catalog' | 'url' | 'email';\n type: string;\n value?: string | boolean | number;\n}\n\n// Public interface for apps\n\n/**\n * @deprecated\n */\nexport type AppSchemaFlavorOrigin = AppFlavorOrigin;\n/**\n * @deprecated\n */\nexport type AppSchemaFlavor = AppFlavor;\n\nexport type AppFlavorOrigin = 'app' | 'config';\n\n// FLAVORS\nexport type ObjectFlavor = AppFlavor & { app: string; origin: AppFlavorOrigin; name?: string; description?: string };\n\n// Definition of an object flavor.\nexport interface AppFlavor extends ObjectTypeFlavor {\n objectTypeID: string;\n descriptionKey?: string;\n // use the default apply component (preview and metadata overlay)\n useDefaultApplyComponent?: boolean;\n // set a custom apply component\n applyComponent?: Type<any>;\n}\n\nexport enum GlobalShortcut {\n search = 'search'\n}\n\nexport interface ShellBootstrapOptions {\n /**\n * Enables capabilities of conditionally load features like apps and\n * extensions based on a configuration file mapping features to user\n * authorities.\n */\n enableFeatureConfig?: boolean;\n /**\n * Enables capabilities of adding custom object types by configuration.\n * Any schema type or SOT can then be configured to serve as a custom\n * object type (flavor).\n */\n enableObjectTypeConfig?: boolean;\n /**\n * Always show the notification icon in the sidebar navigation.\n */\n alwaysShowNotifications?: boolean;\n}\n\nexport interface ShellExtensionImport {\n id: string;\n extension: Type<ClientShellExtension>;\n}\n"]}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { Component, ElementRef, output } from '@angular/core';
|
|
3
|
+
import { FormsModule } from '@angular/forms';
|
|
4
|
+
import { CommandPaletteService } from '../command-palette.service';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
import * as i1 from "../command-palette.service";
|
|
7
|
+
import * as i2 from "@angular/common";
|
|
8
|
+
import * as i3 from "@angular/forms";
|
|
9
|
+
export class CommandPaletteComponent {
|
|
10
|
+
set currentCommandIndex(i) {
|
|
11
|
+
if (i > this.commands.length - 1) {
|
|
12
|
+
i = 0;
|
|
13
|
+
}
|
|
14
|
+
else if (i < 0) {
|
|
15
|
+
i = this.commands.length - 1;
|
|
16
|
+
}
|
|
17
|
+
this._cci = i;
|
|
18
|
+
setTimeout(() => {
|
|
19
|
+
const el = this.elRef.nativeElement.querySelector('.current');
|
|
20
|
+
if (el)
|
|
21
|
+
el.scrollIntoView(false);
|
|
22
|
+
}, 0);
|
|
23
|
+
}
|
|
24
|
+
get currentCommandIndex() {
|
|
25
|
+
return this._cci;
|
|
26
|
+
}
|
|
27
|
+
onArrowDown(e) {
|
|
28
|
+
e.preventDefault();
|
|
29
|
+
e.stopPropagation();
|
|
30
|
+
this.currentCommandIndex++;
|
|
31
|
+
}
|
|
32
|
+
onArrowUp(e) {
|
|
33
|
+
e.preventDefault();
|
|
34
|
+
e.stopPropagation();
|
|
35
|
+
this.currentCommandIndex--;
|
|
36
|
+
}
|
|
37
|
+
onEnter() {
|
|
38
|
+
this.triggerCommand();
|
|
39
|
+
}
|
|
40
|
+
constructor(cmdService, elRef) {
|
|
41
|
+
this.cmdService = cmdService;
|
|
42
|
+
this.elRef = elRef;
|
|
43
|
+
this._commands = [];
|
|
44
|
+
this._cci = -1;
|
|
45
|
+
this.commands = [];
|
|
46
|
+
this.searchTerm = '';
|
|
47
|
+
this.keepFocus = true;
|
|
48
|
+
this.disabledCauses = this.cmdService.disabledCauses;
|
|
49
|
+
this.searchTermChange = output();
|
|
50
|
+
this.placeholder = this.cmdService.placeholder;
|
|
51
|
+
}
|
|
52
|
+
onTermChange(term) {
|
|
53
|
+
const regExp = new RegExp(term.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi');
|
|
54
|
+
this.commands = [...this._commands.filter((c) => c.label.match(regExp))];
|
|
55
|
+
this.currentCommandIndex = 0;
|
|
56
|
+
}
|
|
57
|
+
onInputBlur() {
|
|
58
|
+
if (this.keepFocus && !this.disabledCauses.length) {
|
|
59
|
+
this.elRef.nativeElement.querySelector('input').focus();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
triggerCommand(command) {
|
|
63
|
+
if (command || this.commands[this.currentCommandIndex]) {
|
|
64
|
+
this.cmdService.triggerCommand(command || this.commands[this.currentCommandIndex]);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
highlight(txt) {
|
|
68
|
+
if (txt) {
|
|
69
|
+
const re = new RegExp(this.searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi');
|
|
70
|
+
return txt.replace(re, '<mark>$&</mark>');
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
return txt;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
ngOnInit() {
|
|
77
|
+
this._commands = this.cmdService.getCommands();
|
|
78
|
+
this.commands = [...this._commands];
|
|
79
|
+
}
|
|
80
|
+
ngAfterViewInit() {
|
|
81
|
+
this.onInputBlur();
|
|
82
|
+
}
|
|
83
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CommandPaletteComponent, deps: [{ token: i1.CommandPaletteService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
84
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: CommandPaletteComponent, isStandalone: true, selector: "yuv-command-palette", outputs: { searchTermChange: "searchTermChange" }, host: { listeners: { "keydown.arrowDown": "onArrowDown($event)", "keydown.arrowUp": "onArrowUp($event)", "keydown.enter": "onEnter()" } }, ngImport: i0, template: "@if (!disabledCauses.length) {\n <div class=\"search\">\n <input type=\"text\" autofocus [placeholder]=\"placeholder\" [(ngModel)]=\"searchTerm\" (blur)=\"onInputBlur()\" (ngModelChange)=\"onTermChange($event)\" />\n @if (message) {\n <div class=\"message\">{{ message }}</div>\n }\n </div>\n\n <div class=\"commands\">\n @for (c of commands; track c.id; let i = $index) {\n <div class=\"command\" [ngStyle]=\"{ '--i': i }\" [ngClass]=\"{ current: i === currentCommandIndex }\" (click)=\"triggerCommand(c)\">\n <div class=\"label\" [innerHTML]=\"highlight(c.label)\"></div>\n <div class=\"desc\" [innerHTML]=\"highlight(c?.description)\"></div>\n </div>\n }\n </div>\n} @else {\n <div class=\"disabled\">\n @for (c of disabledCauses; track c.id) {\n <div class=\"disabled-cause\">{{ c.message }}</div>\n }\n </div>\n}\n", styles: [":host{display:grid;grid-template-rows:auto 2fr;grid-template-columns:1fr;grid-template-areas:\"search\" \"commands\";overflow:hidden}:host .search{display:flex;flex-flow:column;align-items:center;justify-content:flex-end;grid-area:search}:host .search input{background-color:transparent;border:0;outline:0;font-size:2em;padding:var(--ymt-spacing-m);color:var(--ymt-text-color);border-bottom:1px solid var(--ymt-outline-variant)}:host .search input::placeholder{font-size:.6em;opacity:.4}:host .search .message{background:var(--ymt-primary);margin:2px;padding:.2em .5em;border-radius:2px;box-sizing:border-box}:host .commands{box-sizing:border-box;grid-area:commands;overflow-y:auto;display:flex;flex-flow:column;-ms-overflow-style:none;scrollbar-width:none}:host .commands::-webkit-scrollbar{display:none}:host .commands .command{opacity:0;animation:commandEnter .15s ease-in-out .2s forwards;animation-delay:calc(var(--i) * 50ms);width:var(--cmp-width);min-width:var(--cmp-min-width);box-sizing:border-box;padding:var(--ymt-spacing-m);transition:background-color .2s ease-in-out;cursor:pointer;border-radius:2px}:host .commands .command.current{background-color:var(--ymt-focus-background)}:host .commands .command:not(.current):hover{background-color:var(--ymt-hover-background)}:host .commands .command ::ng-deep mark{position:relative;display:inline-block;background-color:transparent;color:var(--ymt-text-color)}:host .commands .command ::ng-deep mark:after{content:\"\";position:absolute;bottom:-3px;height:2px;border-radius:1px;background-color:var(--ymt-text-color-subtle);left:0;right:0}:host .commands .command .desc{font:var(--ymt-font-body-subtle);color:var(--ymt-text-color-subtle);margin-top:.5em}:host .disabled{grid-row:1/span 2;display:flex;flex-flow:column;align-items:center;justify-content:center}@keyframes commandEnter{0%{opacity:0}to{opacity:1}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
|
|
85
|
+
}
|
|
86
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CommandPaletteComponent, decorators: [{
|
|
87
|
+
type: Component,
|
|
88
|
+
args: [{ selector: 'yuv-command-palette', imports: [CommonModule, FormsModule], host: {
|
|
89
|
+
'(keydown.arrowDown)': 'onArrowDown($event)',
|
|
90
|
+
'(keydown.arrowUp)': 'onArrowUp($event)',
|
|
91
|
+
'(keydown.enter)': 'onEnter()'
|
|
92
|
+
}, template: "@if (!disabledCauses.length) {\n <div class=\"search\">\n <input type=\"text\" autofocus [placeholder]=\"placeholder\" [(ngModel)]=\"searchTerm\" (blur)=\"onInputBlur()\" (ngModelChange)=\"onTermChange($event)\" />\n @if (message) {\n <div class=\"message\">{{ message }}</div>\n }\n </div>\n\n <div class=\"commands\">\n @for (c of commands; track c.id; let i = $index) {\n <div class=\"command\" [ngStyle]=\"{ '--i': i }\" [ngClass]=\"{ current: i === currentCommandIndex }\" (click)=\"triggerCommand(c)\">\n <div class=\"label\" [innerHTML]=\"highlight(c.label)\"></div>\n <div class=\"desc\" [innerHTML]=\"highlight(c?.description)\"></div>\n </div>\n }\n </div>\n} @else {\n <div class=\"disabled\">\n @for (c of disabledCauses; track c.id) {\n <div class=\"disabled-cause\">{{ c.message }}</div>\n }\n </div>\n}\n", styles: [":host{display:grid;grid-template-rows:auto 2fr;grid-template-columns:1fr;grid-template-areas:\"search\" \"commands\";overflow:hidden}:host .search{display:flex;flex-flow:column;align-items:center;justify-content:flex-end;grid-area:search}:host .search input{background-color:transparent;border:0;outline:0;font-size:2em;padding:var(--ymt-spacing-m);color:var(--ymt-text-color);border-bottom:1px solid var(--ymt-outline-variant)}:host .search input::placeholder{font-size:.6em;opacity:.4}:host .search .message{background:var(--ymt-primary);margin:2px;padding:.2em .5em;border-radius:2px;box-sizing:border-box}:host .commands{box-sizing:border-box;grid-area:commands;overflow-y:auto;display:flex;flex-flow:column;-ms-overflow-style:none;scrollbar-width:none}:host .commands::-webkit-scrollbar{display:none}:host .commands .command{opacity:0;animation:commandEnter .15s ease-in-out .2s forwards;animation-delay:calc(var(--i) * 50ms);width:var(--cmp-width);min-width:var(--cmp-min-width);box-sizing:border-box;padding:var(--ymt-spacing-m);transition:background-color .2s ease-in-out;cursor:pointer;border-radius:2px}:host .commands .command.current{background-color:var(--ymt-focus-background)}:host .commands .command:not(.current):hover{background-color:var(--ymt-hover-background)}:host .commands .command ::ng-deep mark{position:relative;display:inline-block;background-color:transparent;color:var(--ymt-text-color)}:host .commands .command ::ng-deep mark:after{content:\"\";position:absolute;bottom:-3px;height:2px;border-radius:1px;background-color:var(--ymt-text-color-subtle);left:0;right:0}:host .commands .command .desc{font:var(--ymt-font-body-subtle);color:var(--ymt-text-color-subtle);margin-top:.5em}:host .disabled{grid-row:1/span 2;display:flex;flex-flow:column;align-items:center;justify-content:center}@keyframes commandEnter{0%{opacity:0}to{opacity:1}}\n"] }]
|
|
93
|
+
}], ctorParameters: () => [{ type: i1.CommandPaletteService }, { type: i0.ElementRef }], propDecorators: { searchTermChange: [{ type: i0.Output, args: ["searchTermChange"] }] } });
|
|
94
|
+
//# sourceMappingURL=command-palette.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-palette.component.js","sourceRoot":"","sources":["../../../../../../../../../libs/yuuvis/client-shell-core/src/lib/services/command-palette/command-palette/command-palette.component.ts","../../../../../../../../../libs/yuuvis/client-shell-core/src/lib/services/command-palette/command-palette/command-palette.component.html"],"names":[],"mappings":"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","sourcesContent":["import { CommonModule } from '@angular/common';\nimport { AfterViewInit, Component, ElementRef, OnInit, output } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { CommandPaletteCommand, DisabledCause } from '../command-palette.interface';\nimport { CommandPaletteService } from '../command-palette.service';\n\n@Component({\n selector: 'yuv-command-palette',\n imports: [CommonModule, FormsModule],\n templateUrl: './command-palette.component.html',\n styleUrl: './command-palette.component.scss',\n host: {\n '(keydown.arrowDown)': 'onArrowDown($event)',\n '(keydown.arrowUp)': 'onArrowUp($event)',\n '(keydown.enter)': 'onEnter()'\n }\n})\nexport class CommandPaletteComponent implements OnInit, AfterViewInit {\n private _commands: CommandPaletteCommand[] = [];\n private _cci = -1;\n set currentCommandIndex(i: number) {\n if (i > this.commands.length - 1) {\n i = 0;\n } else if (i < 0) {\n i = this.commands.length - 1;\n }\n this._cci = i;\n\n setTimeout(() => {\n const el = this.elRef.nativeElement.querySelector('.current');\n if (el) el.scrollIntoView(false);\n }, 0);\n }\n get currentCommandIndex() {\n return this._cci;\n }\n commands: CommandPaletteCommand[] = [];\n searchTerm = '';\n keepFocus = true;\n message: string | undefined;\n disabledCauses: DisabledCause[] = this.cmdService.disabledCauses;\n placeholder: string | undefined;\n\n readonly searchTermChange = output<string>();\n\n onArrowDown(e: KeyboardEvent) {\n e.preventDefault();\n e.stopPropagation();\n this.currentCommandIndex++;\n }\n\n onArrowUp(e: KeyboardEvent) {\n e.preventDefault();\n e.stopPropagation();\n this.currentCommandIndex--;\n }\n\n onEnter() {\n this.triggerCommand();\n }\n\n constructor(\n private cmdService: CommandPaletteService,\n private elRef: ElementRef\n ) {\n this.placeholder = this.cmdService.placeholder;\n }\n\n onTermChange(term: string) {\n const regExp = new RegExp(term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'gi');\n this.commands = [...this._commands.filter((c) => c.label.match(regExp))];\n this.currentCommandIndex = 0;\n }\n\n onInputBlur() {\n if (this.keepFocus && !this.disabledCauses.length) {\n this.elRef.nativeElement.querySelector('input').focus();\n }\n }\n\n triggerCommand(command?: CommandPaletteCommand) {\n if (command || this.commands[this.currentCommandIndex]) {\n this.cmdService.triggerCommand(command || this.commands[this.currentCommandIndex]);\n }\n }\n\n highlight(txt: string | undefined): string | undefined {\n if (txt) {\n const re = new RegExp(this.searchTerm.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'gi');\n return txt.replace(re, '<mark>$&</mark>');\n } else {\n return txt;\n }\n }\n\n ngOnInit(): void {\n this._commands = this.cmdService.getCommands();\n this.commands = [...this._commands];\n }\n\n ngAfterViewInit() {\n this.onInputBlur();\n }\n}\n","@if (!disabledCauses.length) {\n <div class=\"search\">\n <input type=\"text\" autofocus [placeholder]=\"placeholder\" [(ngModel)]=\"searchTerm\" (blur)=\"onInputBlur()\" (ngModelChange)=\"onTermChange($event)\" />\n @if (message) {\n <div class=\"message\">{{ message }}</div>\n }\n </div>\n\n <div class=\"commands\">\n @for (c of commands; track c.id; let i = $index) {\n <div class=\"command\" [ngStyle]=\"{ '--i': i }\" [ngClass]=\"{ current: i === currentCommandIndex }\" (click)=\"triggerCommand(c)\">\n <div class=\"label\" [innerHTML]=\"highlight(c.label)\"></div>\n <div class=\"desc\" [innerHTML]=\"highlight(c?.description)\"></div>\n </div>\n }\n </div>\n} @else {\n <div class=\"disabled\">\n @for (c of disabledCauses; track c.id) {\n <div class=\"disabled-cause\">{{ c.message }}</div>\n }\n </div>\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-palette.interface.js","sourceRoot":"","sources":["../../../../../../../../libs/yuuvis/client-shell-core/src/lib/services/command-palette/command-palette.interface.ts"],"names":[],"mappings":"","sourcesContent":["export interface CommandPaletteModuleConfig {\n // Key that should trigger the commander.\n // Hitting this key twice will open the commander overlay\n triggerKey?: string;\n accentColor?: string;\n // choose a character that enters search mode\n // Setting this value wil set the component to search mode. This will the emit the\n // entered term instead of filtering the list of commands so you can e.g. trigger a\n // fulltext search and display the results.\n searchModeIndicator?: string;\n // Placeholder for command paletts input field\n placeholder?: string;\n}\n\nexport interface CommandPaletteCommand {\n id: string;\n label: string;\n description?: string;\n callback?: () => void;\n}\n\nexport interface DisabledCause {\n id: string;\n message: string;\n}\n"]}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { Injectable, inject } from '@angular/core';
|
|
2
|
+
import { MatDialog } from '@angular/material/dialog';
|
|
3
|
+
import { ReplaySubject, Subject, debounceTime, fromEvent } from 'rxjs';
|
|
4
|
+
import { filter, map, tap } from 'rxjs/operators';
|
|
5
|
+
import { CommandPaletteComponent } from './command-palette/command-palette.component';
|
|
6
|
+
import * as i0 from "@angular/core";
|
|
7
|
+
export class CommandPaletteService {
|
|
8
|
+
#dialog;
|
|
9
|
+
#dialogRef;
|
|
10
|
+
constructor() {
|
|
11
|
+
this.#dialog = inject(MatDialog);
|
|
12
|
+
this.actionKey = 'Control';
|
|
13
|
+
this._ac = 0;
|
|
14
|
+
this.overlayVisible = false;
|
|
15
|
+
this.disabledCauses = [];
|
|
16
|
+
this.placeholder = '';
|
|
17
|
+
this.overlayVisibleSource = new ReplaySubject();
|
|
18
|
+
this.overlayVisible$ = this.overlayVisibleSource.asObservable();
|
|
19
|
+
this.commands = [];
|
|
20
|
+
this.commandSource = new Subject();
|
|
21
|
+
this.command$ = this.commandSource.asObservable();
|
|
22
|
+
fromEvent(document, 'keyup')
|
|
23
|
+
.pipe(debounceTime(100), map((e) => e), tap((e) => {
|
|
24
|
+
if (e.key === this.actionKey)
|
|
25
|
+
this._actionKeyClick();
|
|
26
|
+
}))
|
|
27
|
+
.subscribe();
|
|
28
|
+
}
|
|
29
|
+
getCommands() {
|
|
30
|
+
const commands = Object.values(this.commands);
|
|
31
|
+
return commands;
|
|
32
|
+
}
|
|
33
|
+
registerCommand(command) {
|
|
34
|
+
this.commands.push(command);
|
|
35
|
+
this._processCommands();
|
|
36
|
+
return this.command$.pipe(filter((c) => c.id === command.id));
|
|
37
|
+
}
|
|
38
|
+
registerCommands(commands) {
|
|
39
|
+
this.commands = [...this.commands, ...commands];
|
|
40
|
+
this._processCommands();
|
|
41
|
+
return this.command$.pipe(filter((cmd) => commands.map((c) => c.id).includes(cmd.id)));
|
|
42
|
+
}
|
|
43
|
+
unregisterCommand(id) {
|
|
44
|
+
this.unregisterCommands([id]);
|
|
45
|
+
}
|
|
46
|
+
unregisterCommands(ids) {
|
|
47
|
+
this.commands = this.commands.filter((c) => !ids.includes(c.id));
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Updates the properties of the registered commands. This is usefull when
|
|
51
|
+
* the language of the app changes and you want to update the commands labels.
|
|
52
|
+
* Based on the IDs propeties of the registered commands will be updated.
|
|
53
|
+
* @param cmds Commands containing the updated properties
|
|
54
|
+
*/
|
|
55
|
+
updateCommands(cmds) {
|
|
56
|
+
const exCmdQA = {};
|
|
57
|
+
cmds.forEach((c) => (exCmdQA[c.id] = c));
|
|
58
|
+
const updatedCommands = this.commands.map((c) => (exCmdQA[c.id] ? exCmdQA[c.id] : c));
|
|
59
|
+
this.commands = updatedCommands;
|
|
60
|
+
}
|
|
61
|
+
triggerCommand(cmd) {
|
|
62
|
+
this.commandSource.next(cmd);
|
|
63
|
+
if (cmd.callback)
|
|
64
|
+
cmd.callback();
|
|
65
|
+
this.#dialogRef?.close();
|
|
66
|
+
}
|
|
67
|
+
addDisabledCause(cause) {
|
|
68
|
+
const existingCauseIndex = this.disabledCauses.findIndex((c) => c.id === cause.id);
|
|
69
|
+
if (existingCauseIndex === -1) {
|
|
70
|
+
this.disabledCauses.push(cause);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
this.disabledCauses[existingCauseIndex].message = cause.message;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
removeDisabledCause(id) {
|
|
77
|
+
this.disabledCauses = this.disabledCauses.filter((c) => c.id !== id);
|
|
78
|
+
}
|
|
79
|
+
removeAllDisabledCauses() {
|
|
80
|
+
this.disabledCauses = [];
|
|
81
|
+
}
|
|
82
|
+
_processCommands() {
|
|
83
|
+
// sort the commands
|
|
84
|
+
this.commands.sort((a, b) => (a.label > b.label ? 1 : a.label === b.label ? 0 : -1));
|
|
85
|
+
}
|
|
86
|
+
_actionKeyClick() {
|
|
87
|
+
this._ac++;
|
|
88
|
+
if (this._ac === 2) {
|
|
89
|
+
this.appendComponentToBody();
|
|
90
|
+
this._ac = 0;
|
|
91
|
+
}
|
|
92
|
+
else if (this._ac === 1) {
|
|
93
|
+
setTimeout(() => {
|
|
94
|
+
this._ac = 0;
|
|
95
|
+
}, 300);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
appendComponentToBody() {
|
|
99
|
+
if (!this.overlayVisible) {
|
|
100
|
+
this.#dialogRef = this.#dialog.open(CommandPaletteComponent);
|
|
101
|
+
this.#dialogRef
|
|
102
|
+
.afterClosed()
|
|
103
|
+
.subscribe(() => {
|
|
104
|
+
this.overlayVisible = false;
|
|
105
|
+
this.overlayVisibleSource.next(this.overlayVisible);
|
|
106
|
+
});
|
|
107
|
+
this.overlayVisible = true;
|
|
108
|
+
this.overlayVisibleSource.next(this.overlayVisible);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CommandPaletteService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
112
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CommandPaletteService, providedIn: 'root' }); }
|
|
113
|
+
}
|
|
114
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CommandPaletteService, decorators: [{
|
|
115
|
+
type: Injectable,
|
|
116
|
+
args: [{
|
|
117
|
+
providedIn: 'root'
|
|
118
|
+
}]
|
|
119
|
+
}], ctorParameters: () => [] });
|
|
120
|
+
//# sourceMappingURL=command-palette.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-palette.service.js","sourceRoot":"","sources":["../../../../../../../../libs/yuuvis/client-shell-core/src/lib/services/command-palette/command-palette.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, inject } from '@angular/core';\nimport { MatDialog, MatDialogRef } from '@angular/material/dialog';\nimport { Observable, ReplaySubject, Subject, debounceTime, fromEvent } from 'rxjs';\nimport { filter, map, tap } from 'rxjs/operators';\nimport { CommandPaletteCommand, DisabledCause } from './command-palette.interface';\nimport { CommandPaletteComponent } from './command-palette/command-palette.component';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class CommandPaletteService {\n #dialog = inject(MatDialog);\n\n readonly actionKey: string = 'Control';\n private _ac = 0;\n #dialogRef: MatDialogRef<CommandPaletteComponent> | undefined;\n\n private overlayVisible = false;\n disabledCauses: DisabledCause[] = [];\n placeholder = '';\n private overlayVisibleSource = new ReplaySubject<boolean>();\n public overlayVisible$: Observable<boolean> = this.overlayVisibleSource.asObservable();\n\n private commands: CommandPaletteCommand[] = [];\n private commandSource = new Subject<CommandPaletteCommand>();\n public command$: Observable<CommandPaletteCommand> = this.commandSource.asObservable();\n\n onSearchTerm!: (term: string, cb: (res: CommandPaletteCommand[]) => void) => void;\n constructor() {\n fromEvent(document, 'keyup')\n .pipe(\n debounceTime(100),\n map((e: Event) => e as KeyboardEvent),\n tap((e) => {\n if (e.key === this.actionKey) this._actionKeyClick();\n })\n )\n .subscribe();\n }\n\n getCommands(): CommandPaletteCommand[] {\n const commands: CommandPaletteCommand[] = Object.values(this.commands);\n return commands;\n }\n\n registerCommand(command: CommandPaletteCommand): Observable<CommandPaletteCommand> {\n this.commands.push(command);\n this._processCommands();\n return this.command$.pipe(filter((c) => c.id === command.id));\n }\n\n registerCommands(commands: CommandPaletteCommand[]): Observable<CommandPaletteCommand> {\n this.commands = [...this.commands, ...commands];\n this._processCommands();\n return this.command$.pipe(filter((cmd) => commands.map((c) => c.id).includes(cmd.id)));\n }\n\n unregisterCommand(id: string) {\n this.unregisterCommands([id]);\n }\n\n unregisterCommands(ids: string[]) {\n this.commands = this.commands.filter((c) => !ids.includes(c.id));\n }\n\n /**\n * Updates the properties of the registered commands. This is usefull when\n * the language of the app changes and you want to update the commands labels.\n * Based on the IDs propeties of the registered commands will be updated.\n * @param cmds Commands containing the updated properties\n */\n updateCommands(cmds: CommandPaletteCommand[]) {\n const exCmdQA: Record<string, any> = {};\n cmds.forEach((c) => (exCmdQA[c.id] = c));\n\n const updatedCommands = this.commands.map((c) => (exCmdQA[c.id] ? exCmdQA[c.id] : c));\n this.commands = updatedCommands;\n }\n\n triggerCommand(cmd: CommandPaletteCommand) {\n this.commandSource.next(cmd);\n if (cmd.callback) cmd.callback();\n this.#dialogRef?.close();\n }\n\n addDisabledCause(cause: DisabledCause) {\n const existingCauseIndex = this.disabledCauses.findIndex((c) => c.id === cause.id);\n if (existingCauseIndex === -1) {\n this.disabledCauses.push(cause);\n } else {\n this.disabledCauses[existingCauseIndex].message = cause.message;\n }\n }\n\n removeDisabledCause(id: string) {\n this.disabledCauses = this.disabledCauses.filter((c) => c.id !== id);\n }\n\n removeAllDisabledCauses() {\n this.disabledCauses = [];\n }\n\n private _processCommands() {\n // sort the commands\n this.commands.sort((a, b) => (a.label > b.label ? 1 : a.label === b.label ? 0 : -1));\n }\n private _actionKeyClick() {\n this._ac++;\n if (this._ac === 2) {\n this.appendComponentToBody();\n this._ac = 0;\n } else if (this._ac === 1) {\n setTimeout(() => {\n this._ac = 0;\n }, 300);\n }\n }\n\n private appendComponentToBody() {\n if (!this.overlayVisible) {\n this.#dialogRef = this.#dialog.open(CommandPaletteComponent);\n this.#dialogRef\n .afterClosed()\n .subscribe(() => {\n this.overlayVisible = false;\n this.overlayVisibleSource.next(this.overlayVisible);\n });\n this.overlayVisible = true;\n this.overlayVisibleSource.next(this.overlayVisible);\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { inject } from '@angular/core';
|
|
2
|
+
import { FeatureService } from './feature.service';
|
|
3
|
+
export const canMatchFeature = (route) => {
|
|
4
|
+
const featureService = inject(FeatureService);
|
|
5
|
+
return (featureService.canMatchRequirements(route) &&
|
|
6
|
+
featureService.canUseApp(route) &&
|
|
7
|
+
featureService.canUseFeatureById(route.id));
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=feature.guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature.guard.js","sourceRoot":"","sources":["../../../../../../../../libs/yuuvis/client-shell-core/src/lib/services/feature/feature.guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAGvC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAY,EAAE,EAAE;IAC9C,MAAM,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;IAC9C,OAAO,CACL,cAAc,CAAC,oBAAoB,CAAC,KAAuB,CAAC;QAC5D,cAAc,CAAC,SAAS,CAAC,KAAY,CAAC;QACtC,cAAc,CAAC,iBAAiB,CAAE,KAAa,CAAC,EAAE,CAAC,CACpD,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { inject } from '@angular/core';\nimport { Route } from '@angular/router';\nimport { App } from '../../models/client-shell.interface';\nimport { FeatureService } from './feature.service';\n\nexport const canMatchFeature = (route: Route) => {\n const featureService = inject(FeatureService);\n return (\n featureService.canMatchRequirements(route as { id: string }) &&\n featureService.canUseApp(route as App) &&\n featureService.canUseFeatureById((route as App).id)\n );\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature.interface.js","sourceRoot":"","sources":["../../../../../../../../libs/yuuvis/client-shell-core/src/lib/services/feature/feature.interface.ts"],"names":[],"mappings":"","sourcesContent":["export interface ClientShellFeatureConfig {\n objectID: string;\n features: ClientShellFeature[];\n}\nexport interface ClientShellFeature {\n id: string;\n // label for the feature\n label?: string;\n extension?: boolean;\n // list of allowed authorities (roles) for this feature\n allowed?: string[];\n // list of denied authorities (roles) for this feature\n // denied will overrule allowed\n denied?: string[]; \n}"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { InjectionToken } from '@angular/core';
|
|
2
|
+
export const CLIENT_SHELL_FEATURE_CONFIG = new InjectionToken('Feature configurations for client shell', {
|
|
3
|
+
factory: () => undefined
|
|
4
|
+
});
|
|
5
|
+
export const provideClientShellFeatures = (featureConfig) => {
|
|
6
|
+
return { provide: CLIENT_SHELL_FEATURE_CONFIG, useValue: featureConfig };
|
|
7
|
+
};
|
|
8
|
+
export const CLIENT_SHELL_FEATURE_CONFIG_ALWAYS_SHOW_NOTOFICATION = new InjectionToken('Always show notifications in client shell', {
|
|
9
|
+
factory: () => false
|
|
10
|
+
});
|
|
11
|
+
export const provideClientShellAlwaysShowNotifications = (alwaysShow) => {
|
|
12
|
+
return { provide: CLIENT_SHELL_FEATURE_CONFIG_ALWAYS_SHOW_NOTOFICATION, useValue: alwaysShow };
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=feature.providers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature.providers.js","sourceRoot":"","sources":["../../../../../../../../libs/yuuvis/client-shell-core/src/lib/services/feature/feature.providers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAY,MAAM,eAAe,CAAC;AAGzD,MAAM,CAAC,MAAM,2BAA2B,GAAG,IAAI,cAAc,CAAuC,yCAAyC,EAAE;IAC7I,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS;CACzB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,aAAuC,EAAY,EAAE;IAC9F,OAAO,EAAE,OAAO,EAAE,2BAA2B,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC;AAC3E,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oDAAoD,GAAG,IAAI,cAAc,CAAU,2CAA2C,EAAE;IAC3I,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK;CACrB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,yCAAyC,GAAG,CAAC,UAAmB,EAAY,EAAE;IACzF,OAAO,EAAE,OAAO,EAAE,oDAAoD,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;AACjG,CAAC,CAAC","sourcesContent":["import { InjectionToken, Provider } from '@angular/core';\nimport { ClientShellFeatureConfig } from './feature.interface';\n\nexport const CLIENT_SHELL_FEATURE_CONFIG = new InjectionToken<ClientShellFeatureConfig | undefined>('Feature configurations for client shell', {\n factory: () => undefined\n});\n\nexport const provideClientShellFeatures = (featureConfig: ClientShellFeatureConfig): Provider => {\n return { provide: CLIENT_SHELL_FEATURE_CONFIG, useValue: featureConfig };\n};\n\nexport const CLIENT_SHELL_FEATURE_CONFIG_ALWAYS_SHOW_NOTOFICATION = new InjectionToken<boolean>('Always show notifications in client shell', {\n factory: () => false\n});\n\nexport const provideClientShellAlwaysShowNotifications = (alwaysShow: boolean): Provider => {\n return { provide: CLIENT_SHELL_FEATURE_CONFIG_ALWAYS_SHOW_NOTOFICATION, useValue: alwaysShow };\n};\n"]}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { inject, Injectable } from '@angular/core';
|
|
2
|
+
import { AVAILABLE_BACKEND_APPS, BackendService, CLIENT_APP_REQUIREMENTS } from '@yuuvis/client-core';
|
|
3
|
+
import { YUV_USER } from '@yuuvis/client-core';
|
|
4
|
+
import { of, switchMap, tap } from 'rxjs';
|
|
5
|
+
import { SHELL_CONFIG_FEATURES } from '../shell-config/shell-config.const';
|
|
6
|
+
import { ShellConfigService } from '../shell-config/shell-config.service';
|
|
7
|
+
import { ShellService } from '../shell/shell.service';
|
|
8
|
+
import { CLIENT_SHELL_FEATURE_CONFIG } from './feature.providers';
|
|
9
|
+
import * as i0 from "@angular/core";
|
|
10
|
+
export class FeatureService {
|
|
11
|
+
#featureManagement = inject(AVAILABLE_BACKEND_APPS);
|
|
12
|
+
#featureRequirements = inject(CLIENT_APP_REQUIREMENTS);
|
|
13
|
+
#featureConfig = inject(CLIENT_SHELL_FEATURE_CONFIG);
|
|
14
|
+
#userToken = inject(YUV_USER);
|
|
15
|
+
#shell = inject(ShellService);
|
|
16
|
+
#shellConfig = inject(ShellConfigService);
|
|
17
|
+
#featureObjectId = this.#featureConfig?.objectID;
|
|
18
|
+
#features = this.#featureConfig?.features || [];
|
|
19
|
+
#backend = inject(BackendService);
|
|
20
|
+
/**
|
|
21
|
+
* Checks if a feature meets all its requirements.
|
|
22
|
+
*
|
|
23
|
+
* This method validates whether a feature (identified by its ID) can be enabled based on:
|
|
24
|
+
* 1. Whether it has any defined requirements in the feature requirements configuration
|
|
25
|
+
* 2. Whether all its requirements are present and enabled in the feature availability list
|
|
26
|
+
*
|
|
27
|
+
* @param fet - An object containing the feature ID to check
|
|
28
|
+
* @param fet.id - The unique identifier of the feature (may include '.extension' suffix)
|
|
29
|
+
* @returns `true` if the feature has no requirements or all requirements are enabled; `false` otherwise
|
|
30
|
+
*
|
|
31
|
+
* @remarks
|
|
32
|
+
* - The method matches feature IDs exactly or with an optional '.extension' suffix
|
|
33
|
+
* - Requirement names ending with '+' have the suffix removed before validation
|
|
34
|
+
* - If no matching requirements are found, the feature is considered valid (returns `true`)
|
|
35
|
+
* - All requirements must have a state of 'enabled' for the feature to pass validation
|
|
36
|
+
*/
|
|
37
|
+
#matchesRequirements(feat) {
|
|
38
|
+
const featureRequirements = this.#featureRequirements;
|
|
39
|
+
const featureAvailability = this.#featureManagement;
|
|
40
|
+
if (!featureRequirements)
|
|
41
|
+
return true;
|
|
42
|
+
// Check if fet.id matches exactly 'key' or 'key.extension'
|
|
43
|
+
const matchingKey = Object.keys(featureRequirements).find((key) => new RegExp(`^${key}(\\.extension)?$`).test(feat.id));
|
|
44
|
+
// If no matching key, return true
|
|
45
|
+
if (!matchingKey) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
// Get the requirements for the matching key
|
|
49
|
+
const requirements = featureRequirements[matchingKey];
|
|
50
|
+
// Check if all requirements are in avv with state 'enabled'
|
|
51
|
+
return requirements.every((reqName) => {
|
|
52
|
+
// Remove the '+' suffix if present
|
|
53
|
+
const cleanReqName = reqName.replace(/\+$/, '');
|
|
54
|
+
// Find the requirement in avv and check if it's enabled
|
|
55
|
+
const found = featureAvailability.find((item) => item.name === cleanReqName);
|
|
56
|
+
return found && found.state === 'enabled';
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
hasFeatureConfig() {
|
|
60
|
+
return !!this.#featureObjectId;
|
|
61
|
+
}
|
|
62
|
+
getFeatures() {
|
|
63
|
+
return this.#features;
|
|
64
|
+
}
|
|
65
|
+
getAvailableApps(allApps) {
|
|
66
|
+
return allApps.filter((app) => this.#matchesRequirements(app) && this.canUseApp(app) && this.canUseFeatureById(app.id));
|
|
67
|
+
}
|
|
68
|
+
canUseApp(app) {
|
|
69
|
+
const authorities = this.#userToken?.authorities || [];
|
|
70
|
+
const allowed = app.permissions?.allow || [];
|
|
71
|
+
const denied = app.permissions?.deny || [];
|
|
72
|
+
const isAllowed = allowed.length === 0 || authorities.some((authority) => allowed.includes(authority));
|
|
73
|
+
const isDenied = denied.some((deniedAuthority) => authorities.includes(deniedAuthority));
|
|
74
|
+
return isAllowed && !isDenied;
|
|
75
|
+
}
|
|
76
|
+
canMatchRequirements(app) {
|
|
77
|
+
return this.#matchesRequirements({ id: app.id });
|
|
78
|
+
}
|
|
79
|
+
canUseFeatureById(featureId, authorities) {
|
|
80
|
+
// check requirement
|
|
81
|
+
if (!this.#matchesRequirements({ id: featureId }))
|
|
82
|
+
return false;
|
|
83
|
+
// check configuration from the backend (item filed in shell config)
|
|
84
|
+
const feature = this.#features.find((f) => f.id === featureId);
|
|
85
|
+
return !feature || this.canUseFeature(feature, authorities);
|
|
86
|
+
}
|
|
87
|
+
canUseFeature(feature, authorities) {
|
|
88
|
+
const authoritiesToCheck = authorities || this.#userToken?.authorities || [];
|
|
89
|
+
const allowed = feature.allowed || [];
|
|
90
|
+
const denied = feature.denied || [];
|
|
91
|
+
const isAllowed = allowed.length === 0 || authoritiesToCheck.some((authority) => allowed.includes(authority));
|
|
92
|
+
const isDenied = denied.some((deniedAuthority) => authoritiesToCheck.includes(deniedAuthority));
|
|
93
|
+
return isAllowed && !isDenied;
|
|
94
|
+
}
|
|
95
|
+
saveFeatureSettings(features) {
|
|
96
|
+
if (!this.#featureObjectId) {
|
|
97
|
+
throw new Error('No feature configuration object ID provided');
|
|
98
|
+
}
|
|
99
|
+
return this.#shellConfig.update(this.#featureObjectId, features).pipe(tap(() => (this.#features = features)));
|
|
100
|
+
}
|
|
101
|
+
deleteFeatureSettings() {
|
|
102
|
+
if (!this.#featureObjectId) {
|
|
103
|
+
throw new Error('No feature configuration object ID provided');
|
|
104
|
+
}
|
|
105
|
+
return this.#shellConfig.delete(this.#featureObjectId);
|
|
106
|
+
}
|
|
107
|
+
createSettingsObject() {
|
|
108
|
+
return this.#shellConfig.create(SHELL_CONFIG_FEATURES, []).pipe(tap((res) => {
|
|
109
|
+
this.#featureObjectId = res.id;
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
export() {
|
|
113
|
+
if (this.#featureObjectId) {
|
|
114
|
+
this.#shellConfig.download(this.#featureObjectId, `${SHELL_CONFIG_FEATURES}.json`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
import() {
|
|
118
|
+
// read files contents
|
|
119
|
+
return this.#featureObjectId
|
|
120
|
+
? this.#shell.pickFile().pipe(switchMap((file) => file
|
|
121
|
+
? this.#shellConfig.upload(this.#featureObjectId, file).pipe(switchMap((res) => {
|
|
122
|
+
// read uploaded file
|
|
123
|
+
return this.#backend.get(`/dms/objects/${res.id}/contents/file`).pipe(tap((data) => {
|
|
124
|
+
// update features
|
|
125
|
+
//console.log('data', data);
|
|
126
|
+
this.#features = data;
|
|
127
|
+
}));
|
|
128
|
+
}))
|
|
129
|
+
: of(null)))
|
|
130
|
+
: of(null);
|
|
131
|
+
}
|
|
132
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
133
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureService, providedIn: 'root' }); }
|
|
134
|
+
}
|
|
135
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureService, decorators: [{
|
|
136
|
+
type: Injectable,
|
|
137
|
+
args: [{
|
|
138
|
+
providedIn: 'root'
|
|
139
|
+
}]
|
|
140
|
+
}] });
|
|
141
|
+
//# sourceMappingURL=feature.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature.service.js","sourceRoot":"","sources":["../../../../../../../../libs/yuuvis/client-shell-core/src/lib/services/feature/feature.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { inject, Injectable } from '@angular/core';\nimport {\n AVAILABLE_BACKEND_APPS,\n BackendService,\n CLIENT_APP_REQUIREMENTS,\n Requirements,\n YuvAvailableBackendApps,\n YuvUser\n} from '@yuuvis/client-core';\n\nimport { YUV_USER } from '@yuuvis/client-core';\nimport { Observable, of, switchMap, tap } from 'rxjs';\nimport { App } from '../../models/client-shell.interface';\nimport { SHELL_CONFIG_FEATURES } from '../shell-config/shell-config.const';\nimport { ShellConfigService } from '../shell-config/shell-config.service';\nimport { ShellService } from '../shell/shell.service';\nimport { ClientShellFeature, ClientShellFeatureConfig } from './feature.interface';\nimport { CLIENT_SHELL_FEATURE_CONFIG } from './feature.providers';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class FeatureService {\n #featureManagement = inject<YuvAvailableBackendApps[]>(AVAILABLE_BACKEND_APPS);\n #featureRequirements = inject<Requirements>(CLIENT_APP_REQUIREMENTS);\n\n #featureConfig = inject<ClientShellFeatureConfig>(CLIENT_SHELL_FEATURE_CONFIG);\n #userToken = inject<YuvUser>(YUV_USER);\n #shell = inject(ShellService);\n #shellConfig = inject(ShellConfigService);\n #featureObjectId? = this.#featureConfig?.objectID;\n #features = this.#featureConfig?.features || [];\n #backend = inject(BackendService);\n\n /**\n * Checks if a feature meets all its requirements.\n *\n * This method validates whether a feature (identified by its ID) can be enabled based on:\n * 1. Whether it has any defined requirements in the feature requirements configuration\n * 2. Whether all its requirements are present and enabled in the feature availability list\n *\n * @param fet - An object containing the feature ID to check\n * @param fet.id - The unique identifier of the feature (may include '.extension' suffix)\n * @returns `true` if the feature has no requirements or all requirements are enabled; `false` otherwise\n *\n * @remarks\n * - The method matches feature IDs exactly or with an optional '.extension' suffix\n * - Requirement names ending with '+' have the suffix removed before validation\n * - If no matching requirements are found, the feature is considered valid (returns `true`)\n * - All requirements must have a state of 'enabled' for the feature to pass validation\n */\n #matchesRequirements(feat: { id: string }): boolean {\n const featureRequirements = this.#featureRequirements;\n const featureAvailability = this.#featureManagement;\n if (!featureRequirements) return true;\n // Check if fet.id matches exactly 'key' or 'key.extension'\n const matchingKey = Object.keys(featureRequirements).find((key) =>\n new RegExp(`^${key}(\\\\.extension)?$`).test(feat.id)\n );\n\n // If no matching key, return true\n if (!matchingKey) {\n return true;\n }\n\n // Get the requirements for the matching key\n const requirements = featureRequirements[matchingKey];\n\n // Check if all requirements are in avv with state 'enabled'\n return requirements.every((reqName) => {\n // Remove the '+' suffix if present\n const cleanReqName = reqName.replace(/\\+$/, '');\n // Find the requirement in avv and check if it's enabled\n const found = featureAvailability.find((item) => item.name === cleanReqName);\n return found && found.state === 'enabled';\n });\n }\n\n hasFeatureConfig(): boolean {\n return !!this.#featureObjectId;\n }\n\n getFeatures(): ClientShellFeature[] {\n return this.#features;\n }\n\n getAvailableApps(allApps: App[]): App[] {\n return allApps.filter(\n (app) => this.#matchesRequirements(app) && this.canUseApp(app) && this.canUseFeatureById(app.id)\n );\n }\n\n canUseApp(app: App) {\n const authorities = this.#userToken?.authorities || [];\n const allowed = app.permissions?.allow || [];\n const denied = app.permissions?.deny || [];\n\n const isAllowed = allowed.length === 0 || authorities.some((authority) => allowed.includes(authority));\n const isDenied = denied.some((deniedAuthority) => authorities.includes(deniedAuthority));\n\n return isAllowed && !isDenied;\n }\n\n canMatchRequirements(app: { id: string }): boolean {\n return this.#matchesRequirements({ id: app.id });\n }\n\n canUseFeatureById(featureId: string, authorities?: string[]): boolean {\n // check requirement\n if (!this.#matchesRequirements({ id: featureId })) return false;\n // check configuration from the backend (item filed in shell config)\n const feature = this.#features.find((f) => f.id === featureId);\n return !feature || this.canUseFeature(feature, authorities);\n }\n\n canUseFeature(feature: ClientShellFeature, authorities?: string[]): boolean {\n const authoritiesToCheck = authorities || this.#userToken?.authorities || [];\n const allowed = feature.allowed || [];\n const denied = feature.denied || [];\n\n const isAllowed = allowed.length === 0 || authoritiesToCheck.some((authority) => allowed.includes(authority));\n const isDenied = denied.some((deniedAuthority) => authoritiesToCheck.includes(deniedAuthority));\n\n return isAllowed && !isDenied;\n }\n\n saveFeatureSettings(features: ClientShellFeature[]): Observable<any> {\n if (!this.#featureObjectId) {\n throw new Error('No feature configuration object ID provided');\n }\n return this.#shellConfig.update(this.#featureObjectId, features).pipe(tap(() => (this.#features = features)));\n }\n\n deleteFeatureSettings(): Observable<any> {\n if (!this.#featureObjectId) {\n throw new Error('No feature configuration object ID provided');\n }\n return this.#shellConfig.delete(this.#featureObjectId);\n }\n\n createSettingsObject(): Observable<any> {\n return this.#shellConfig.create(SHELL_CONFIG_FEATURES, []).pipe(\n tap((res) => {\n this.#featureObjectId = res.id;\n })\n );\n }\n\n export() {\n if (this.#featureObjectId) {\n this.#shellConfig.download(this.#featureObjectId, `${SHELL_CONFIG_FEATURES}.json`);\n }\n }\n\n import() {\n // read files contents\n\n return this.#featureObjectId\n ? this.#shell.pickFile().pipe(\n switchMap((file) =>\n file\n ? this.#shellConfig.upload(this.#featureObjectId!, file).pipe(\n switchMap((res) => {\n // read uploaded file\n return this.#backend.get(`/dms/objects/${res.id}/contents/file`).pipe(\n tap((data) => {\n // update features\n //console.log('data', data);\n\n this.#features = data;\n })\n );\n })\n )\n : of(null)\n )\n )\n : of(null);\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../../libs/yuuvis/client-shell-core/src/lib/services/feature/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC","sourcesContent":["export * from './feature.interface';\nexport * from './feature.guard';\nexport * from './feature.providers';\nexport * from './feature.service';"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export class NoopExtension {
|
|
4
|
+
init() {
|
|
5
|
+
return Promise.resolve();
|
|
6
|
+
}
|
|
7
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NoopExtension, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
8
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NoopExtension }); }
|
|
9
|
+
}
|
|
10
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NoopExtension, decorators: [{
|
|
11
|
+
type: Injectable
|
|
12
|
+
}] });
|
|
13
|
+
//# sourceMappingURL=noop.extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noop.extension.js","sourceRoot":"","sources":["../../../../../../../../libs/yuuvis/client-shell-core/src/lib/services/shell/noop.extension.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;;AAI3C,MAAM,OAAO,aAAa;IACxB,IAAI;QACF,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;+GAHU,aAAa;mHAAb,aAAa;;4FAAb,aAAa;kBADzB,UAAU","sourcesContent":["import { Injectable } from '@angular/core';\nimport { ClientShellExtension } from '../../models/client-shell.interface';\n\n@Injectable()\nexport class NoopExtension implements ClientShellExtension {\n init(): Promise<any> {\n return Promise.resolve();\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requirements.parser.js","sourceRoot":"","sources":["../../../../../../../../libs/yuuvis/client-shell-core/src/lib/services/shell/requirements.parser.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,oBAAgD,EAA6B,EAAE;IACjH,OAAO,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACrD,IAAI,EAAE,GAAG;QACT,KAAK,EAAE,SAA8B;KACtC,CAAC,CAAC,CAAC;AACN,CAAC,CAAC","sourcesContent":["import { AvailabilityState, YuvAvailableBackendApps } from '@yuuvis/client-core';\n\nexport const requirementsMapping = (requirementsResponse: { [key: string]: unknown }): YuvAvailableBackendApps[] => {\n return Object.keys(requirementsResponse).map((key) => ({\n name: key,\n state: 'enabled' as AvailabilityState\n }));\n};\n"]}
|