@yuuvis/client-shell 2.3.9 → 2.3.11

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/README.md CHANGED
@@ -142,3 +142,31 @@ Anywhere within your app you could set components to be shown in one of the app
142
142
  ```
143
143
 
144
144
  Currently there are 3 slots available: `actions`, `search`, `notifications`. Make sure to import `YuvClientShellModule` in the component that sets the slots, because this module exposes the `yuvAppHeaderSlot` directive.
145
+
146
+ ## Inject your own settings
147
+ Apps can register their own settings to be shown in the shells global settings.
148
+
149
+ This should be done in the apps extension, because it's not going to be lazy
150
+ loaded and is therefore available from the beginning.
151
+
152
+ ```ts
153
+ @Injectable()
154
+ export class AppDemoExtension implements ClientShellExtension {
155
+ #shell = inject(ShellService);
156
+
157
+ #registerAppSettings() {
158
+ this.#shell.registerAppSettings({
159
+ appID: 'app-test',
160
+ label: 'App Demo Settings',
161
+ component: AppSettingsComponent
162
+ });
163
+ }
164
+
165
+ init(): Promise<any> {
166
+ this.#registerAppSettings();
167
+ return Promise.resolve();
168
+ }
169
+ }
170
+ ```
171
+
172
+ This `AppSettingsComponent` will then be rendered within the shells settings page. The `label` property will be used fetch a translation. If there is no translation found, the value itself will be used.
@@ -0,0 +1,102 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, signal, effect, Component } from '@angular/core';
3
+ import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
+ import * as i3 from '@yuuvis/client-core';
5
+ import { UserService, ConfigService, TranslateService, TranslateModule } from '@yuuvis/client-core';
6
+ import * as i1 from '@angular/common';
7
+ import { DOCUMENT, CommonModule } from '@angular/common';
8
+ import { HttpClient } from '@angular/common/http';
9
+ import { ReactiveFormsModule } from '@angular/forms';
10
+ import { MatButtonToggleGroup, MatButtonToggle } from '@angular/material/button-toggle';
11
+ import * as i3$1 from '@angular/material/expansion';
12
+ import { MatExpansionModule } from '@angular/material/expansion';
13
+ import { MatSelectModule } from '@angular/material/select';
14
+ import * as i4 from '@angular/material/table';
15
+ import { MatTableModule } from '@angular/material/table';
16
+ import { ShellService } from '@yuuvis/client-shell-core';
17
+ import { map } from 'rxjs';
18
+ import { LayoutSettingsService } from '@yuuvis/client-framework/common';
19
+
20
+ class SettingsPageComponent {
21
+ #layoutSettingsService;
22
+ #http;
23
+ #appSettings;
24
+ #appSettingsEffect;
25
+ constructor() {
26
+ this.userService = inject(UserService);
27
+ this.config = inject(ConfigService);
28
+ this.translate = inject(TranslateService);
29
+ this.shell = inject(ShellService);
30
+ this.document = inject(DOCUMENT);
31
+ this.#layoutSettingsService = inject(LayoutSettingsService);
32
+ this.#http = inject(HttpClient);
33
+ this.clientLocales = signal([]);
34
+ this.clientVersion = signal(undefined);
35
+ this.clientAboutData = signal(undefined);
36
+ this.currentMode = this.#layoutSettingsService.mode;
37
+ this.user = toSignal(this.userService.user$);
38
+ this.appSettings = signal([]);
39
+ this.#appSettings = this.shell.appSettings;
40
+ this.#appSettingsEffect = effect(() => {
41
+ const as = this.#appSettings();
42
+ this.#mapAppSettings(as);
43
+ });
44
+ this.translate.onLangChange.pipe(takeUntilDestroyed()).subscribe(() => {
45
+ this.#mapAppSettings(this.appSettings());
46
+ });
47
+ }
48
+ #mapAppSettings(as) {
49
+ this.appSettings.set(as.map((appSetting) => {
50
+ const translatedLabel = this.translate.instant(appSetting.label);
51
+ const label = translatedLabel && !translatedLabel.startsWith('!missing') ? translatedLabel : appSetting.label;
52
+ return {
53
+ ...appSetting,
54
+ _label: label
55
+ };
56
+ }));
57
+ }
58
+ changeClientLocale(iso) {
59
+ this.userService.changeClientLocale(iso);
60
+ }
61
+ changeMode({ value }) {
62
+ if (value && value !== this.currentMode()) {
63
+ this.#layoutSettingsService.setMode(value);
64
+ this.#layoutSettingsService.applyLayoutMode(value);
65
+ }
66
+ }
67
+ toggleDarkMode() {
68
+ const root = document.getElementsByTagName('body')[0];
69
+ root.classList.toggle('dark');
70
+ }
71
+ ngOnInit() {
72
+ this.clientVersion.set(this.document.body.getAttribute('data-version') ?? 'dev');
73
+ this.clientLocales.set(this.config.getClientLocales());
74
+ this.getAboutData();
75
+ }
76
+ getAboutData() {
77
+ this.#http
78
+ .get('assets/about.data.json')
79
+ .pipe(map((response) => ({
80
+ ...response,
81
+ libraries: response.libraries
82
+ ? response.libraries.map((lib) => ({
83
+ ...lib,
84
+ ...(lib.license !== 'SEE LICENSE IN LICENSE' ? { link: `https://opensource.org/license/${lib.license}` } : {})
85
+ }))
86
+ : undefined
87
+ })))
88
+ .subscribe({
89
+ next: (response) => this.clientAboutData.set(response),
90
+ error: (error) => console.log({ error })
91
+ });
92
+ }
93
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SettingsPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
94
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: SettingsPageComponent, isStandalone: true, selector: "yuv-settings", ngImport: i0, template: "<header>\n <h1>{{ 'yuv.shell.settings.title' | translate }}</h1>\n <span class=\"subhead\">{{ 'yuv.shell.settings.client.version' | translate }}: {{ clientVersion() }}</span>\n</header>\n\n<main>\n <div class=\"content-container\">\n <!-- User Info -->\n @let user = this.user();\n @if (user) {\n <section class=\"section user\">\n <h2 class=\"section__title\">{{ user.title }}</h2>\n <div class=\"section__body user__data grid\">\n <div class=\"user__data-entry grid-row\">\n <span class=\"user__data-entry-key grid-col grid-col-key\"> {{ 'yuv.shell.settings.user.email' | translate }}: </span>\n <span class=\"user__data-entry-value grid-col grid-col-value\">\n {{ user.email }}\n </span>\n </div>\n <div class=\"user__data-entry grid-row\">\n <span class=\"user__data-entry-key grid-col grid-col-key\"> {{ 'yuv.shell.settings.tenant' | translate }}: </span>\n <span class=\"user__data-entry-value grid-col grid-col-value\">\n {{ user.tenant }}\n </span>\n </div>\n\n <!--<div class=\"user__data\">{{ 'yuv.shell.settings.user.name' | translate }}: {{ user.username }}</div>\n <div class=\"user__data-entry\">{{ 'yuv.shell.settings.user.email' | translate }}: {{ user.email }}</div>\n <div class=\"user__data-entry\">{{ 'yuv.shell.settings.tenant' | translate }}: {{ user.tenant }}</div>-->\n </div>\n </section>\n }\n <!-- Language Settings -->\n <section yuvOfflineDisabled class=\"section\">\n <h2 class=\"section__title\">{{ 'yuv.shell.settings.language' | translate }}</h2>\n <div class=\"section__body\">\n <mat-button-toggle-group\n name=\"language\"\n [value]=\"translate.currentLang\"\n (valueChange)=\"changeClientLocale($event)\"\n [attr.aria-label]=\"'yuv.shell.settings.language' | translate\"\n >\n @for (locale of clientLocales(); track locale.iso) {\n <mat-button-toggle value=\"{{ locale.iso }}\">{{ locale.label }}</mat-button-toggle>\n }\n </mat-button-toggle-group>\n </div>\n </section>\n\n <!-- Mode -->\n @let currentThemeMode = currentMode();\n <section class=\"section\">\n <h2 class=\"section__title\">{{ 'yuv.shell.settings.mode' | translate }}</h2>\n <div class=\"section__body\">\n <mat-button-toggle-group name=\"mode\" [value]=\"currentThemeMode\" (change)=\"changeMode($event)\" [attr.aria-label]=\"'yuv.shell.settings.mode' | translate\">\n <mat-button-toggle value=\"light\">{{ 'yuv.shell.settings.mode.light' | translate }}</mat-button-toggle>\n <mat-button-toggle value=\"dark\">{{ 'yuv.shell.settings.mode.dark' | translate }}</mat-button-toggle>\n <mat-button-toggle value=\"system\">{{ 'yuv.shell.settings.mode.system' | translate }}</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n </section>\n\n <!-- app settings -->\n @for (c of appSettings(); track $index) {\n <section class=\"section\">\n <h2 class=\"section__title\">{{ c._label }}</h2>\n <div class=\"section__body\">\n <ng-container *ngComponentOutlet=\"c.component\"></ng-container>\n </div>\n </section>\n }\n\n <!-- About Info -->\n @let libraries = this.clientAboutData()?.libraries;\n @if (libraries) {\n <section class=\"section about\">\n <h2 class=\"section__title\">{{ 'yuv.shell.settings.about.title' | translate }}</h2>\n <mat-expansion-panel class=\"about__panel\">\n <mat-expansion-panel-header>\n <mat-panel-title>{{ 'yuv.shell.settings.dependency-info.title' | translate }}</mat-panel-title>\n <!-- <mat-panel-description>{{ '' | translate }}</mat-panel-description>-->\n </mat-expansion-panel-header>\n\n <ng-template matExpansionPanelContent>\n <div class=\"about__panel-content\">\n <table mat-table [dataSource]=\"libraries\" class=\"mat-elevation-z8\">\n <!-- Name Column -->\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef>{{ 'yuv.shell.settings.dependency-info.package' | translate }}</th>\n <td mat-cell *matCellDef=\"let element\">{{ element.name }}</td>\n </ng-container>\n\n <!-- Version Column -->\n <ng-container matColumnDef=\"version\">\n <th mat-header-cell *matHeaderCellDef>{{ 'yuv.shell.settings.dependency-info.version' | translate }}</th>\n <td mat-cell *matCellDef=\"let element\">{{ element.version }}</td>\n </ng-container>\n\n <!-- License Column -->\n <ng-container matColumnDef=\"license\">\n <th mat-header-cell *matHeaderCellDef>{{ 'yuv.shell.settings.dependency-info.license' | translate }}</th>\n <td mat-cell *matCellDef=\"let element\">\n @if (element.link) {\n <a href=\"{{ element.link }}\" target=\"_blank\">{{ element.license }}</a>\n } @else {\n {{ element.license }}\n }\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"['name', 'version', 'license']\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['name', 'version', 'license']\"></tr>\n </table>\n </div>\n </ng-template>\n </mat-expansion-panel>\n </section>\n }\n </div>\n</main>\n", styles: [":host{display:grid;grid-template-columns:1fr auto;grid-template-rows:auto 1fr;grid-template-areas:\"header\" \"settings\";height:100%;overflow:hidden;overflow-y:auto}:host header{grid-area:header;padding:var(--ymt-spacing-3xl)}:host header h1{margin:0}:host header .subhead{font:var(--ymt-font-subhead);color:var(--ymt-text-color-subtle)}:host main{grid-area:settings;padding:var(--ymt-spacing-m);padding-right:0;overflow-y:auto;scrollbar-gutter:stable}:host main .content-container{max-width:900px}:host main section{display:flex;flex-flow:column;padding:var(--ymt-spacing-m);margin-bottom:var(--ymt-spacing-l)}:host main .about__panel-content{overflow-x:auto}:host main .grid-row{display:grid;grid-template-columns:minmax(10ch,1fr) 11fr;grid-gap:var(--ymt-spacing-s);grid-template-areas:\"key value\";align-items:baseline}:host main .grid-col-key{font-weight:700;grid-area:key}:host main .grid-col-value{grid-area:value;word-break:break-all}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i3$1.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i3$1.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i3$1.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "directive", type: i3$1.MatExpansionPanelContent, selector: "ng-template[matExpansionPanelContent]" }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i4.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i4.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i4.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i4.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i4.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i4.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i4.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i4.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i4.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i4.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }] }); }
95
+ }
96
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SettingsPageComponent, decorators: [{
97
+ type: Component,
98
+ args: [{ selector: 'yuv-settings', standalone: true, imports: [CommonModule, TranslateModule, MatSelectModule, ReactiveFormsModule, MatButtonToggleGroup, MatButtonToggle, MatExpansionModule, MatTableModule], template: "<header>\n <h1>{{ 'yuv.shell.settings.title' | translate }}</h1>\n <span class=\"subhead\">{{ 'yuv.shell.settings.client.version' | translate }}: {{ clientVersion() }}</span>\n</header>\n\n<main>\n <div class=\"content-container\">\n <!-- User Info -->\n @let user = this.user();\n @if (user) {\n <section class=\"section user\">\n <h2 class=\"section__title\">{{ user.title }}</h2>\n <div class=\"section__body user__data grid\">\n <div class=\"user__data-entry grid-row\">\n <span class=\"user__data-entry-key grid-col grid-col-key\"> {{ 'yuv.shell.settings.user.email' | translate }}: </span>\n <span class=\"user__data-entry-value grid-col grid-col-value\">\n {{ user.email }}\n </span>\n </div>\n <div class=\"user__data-entry grid-row\">\n <span class=\"user__data-entry-key grid-col grid-col-key\"> {{ 'yuv.shell.settings.tenant' | translate }}: </span>\n <span class=\"user__data-entry-value grid-col grid-col-value\">\n {{ user.tenant }}\n </span>\n </div>\n\n <!--<div class=\"user__data\">{{ 'yuv.shell.settings.user.name' | translate }}: {{ user.username }}</div>\n <div class=\"user__data-entry\">{{ 'yuv.shell.settings.user.email' | translate }}: {{ user.email }}</div>\n <div class=\"user__data-entry\">{{ 'yuv.shell.settings.tenant' | translate }}: {{ user.tenant }}</div>-->\n </div>\n </section>\n }\n <!-- Language Settings -->\n <section yuvOfflineDisabled class=\"section\">\n <h2 class=\"section__title\">{{ 'yuv.shell.settings.language' | translate }}</h2>\n <div class=\"section__body\">\n <mat-button-toggle-group\n name=\"language\"\n [value]=\"translate.currentLang\"\n (valueChange)=\"changeClientLocale($event)\"\n [attr.aria-label]=\"'yuv.shell.settings.language' | translate\"\n >\n @for (locale of clientLocales(); track locale.iso) {\n <mat-button-toggle value=\"{{ locale.iso }}\">{{ locale.label }}</mat-button-toggle>\n }\n </mat-button-toggle-group>\n </div>\n </section>\n\n <!-- Mode -->\n @let currentThemeMode = currentMode();\n <section class=\"section\">\n <h2 class=\"section__title\">{{ 'yuv.shell.settings.mode' | translate }}</h2>\n <div class=\"section__body\">\n <mat-button-toggle-group name=\"mode\" [value]=\"currentThemeMode\" (change)=\"changeMode($event)\" [attr.aria-label]=\"'yuv.shell.settings.mode' | translate\">\n <mat-button-toggle value=\"light\">{{ 'yuv.shell.settings.mode.light' | translate }}</mat-button-toggle>\n <mat-button-toggle value=\"dark\">{{ 'yuv.shell.settings.mode.dark' | translate }}</mat-button-toggle>\n <mat-button-toggle value=\"system\">{{ 'yuv.shell.settings.mode.system' | translate }}</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n </section>\n\n <!-- app settings -->\n @for (c of appSettings(); track $index) {\n <section class=\"section\">\n <h2 class=\"section__title\">{{ c._label }}</h2>\n <div class=\"section__body\">\n <ng-container *ngComponentOutlet=\"c.component\"></ng-container>\n </div>\n </section>\n }\n\n <!-- About Info -->\n @let libraries = this.clientAboutData()?.libraries;\n @if (libraries) {\n <section class=\"section about\">\n <h2 class=\"section__title\">{{ 'yuv.shell.settings.about.title' | translate }}</h2>\n <mat-expansion-panel class=\"about__panel\">\n <mat-expansion-panel-header>\n <mat-panel-title>{{ 'yuv.shell.settings.dependency-info.title' | translate }}</mat-panel-title>\n <!-- <mat-panel-description>{{ '' | translate }}</mat-panel-description>-->\n </mat-expansion-panel-header>\n\n <ng-template matExpansionPanelContent>\n <div class=\"about__panel-content\">\n <table mat-table [dataSource]=\"libraries\" class=\"mat-elevation-z8\">\n <!-- Name Column -->\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef>{{ 'yuv.shell.settings.dependency-info.package' | translate }}</th>\n <td mat-cell *matCellDef=\"let element\">{{ element.name }}</td>\n </ng-container>\n\n <!-- Version Column -->\n <ng-container matColumnDef=\"version\">\n <th mat-header-cell *matHeaderCellDef>{{ 'yuv.shell.settings.dependency-info.version' | translate }}</th>\n <td mat-cell *matCellDef=\"let element\">{{ element.version }}</td>\n </ng-container>\n\n <!-- License Column -->\n <ng-container matColumnDef=\"license\">\n <th mat-header-cell *matHeaderCellDef>{{ 'yuv.shell.settings.dependency-info.license' | translate }}</th>\n <td mat-cell *matCellDef=\"let element\">\n @if (element.link) {\n <a href=\"{{ element.link }}\" target=\"_blank\">{{ element.license }}</a>\n } @else {\n {{ element.license }}\n }\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"['name', 'version', 'license']\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['name', 'version', 'license']\"></tr>\n </table>\n </div>\n </ng-template>\n </mat-expansion-panel>\n </section>\n }\n </div>\n</main>\n", styles: [":host{display:grid;grid-template-columns:1fr auto;grid-template-rows:auto 1fr;grid-template-areas:\"header\" \"settings\";height:100%;overflow:hidden;overflow-y:auto}:host header{grid-area:header;padding:var(--ymt-spacing-3xl)}:host header h1{margin:0}:host header .subhead{font:var(--ymt-font-subhead);color:var(--ymt-text-color-subtle)}:host main{grid-area:settings;padding:var(--ymt-spacing-m);padding-right:0;overflow-y:auto;scrollbar-gutter:stable}:host main .content-container{max-width:900px}:host main section{display:flex;flex-flow:column;padding:var(--ymt-spacing-m);margin-bottom:var(--ymt-spacing-l)}:host main .about__panel-content{overflow-x:auto}:host main .grid-row{display:grid;grid-template-columns:minmax(10ch,1fr) 11fr;grid-gap:var(--ymt-spacing-s);grid-template-areas:\"key value\";align-items:baseline}:host main .grid-col-key{font-weight:700;grid-area:key}:host main .grid-col-value{grid-area:value;word-break:break-all}\n"] }]
99
+ }], ctorParameters: () => [] });
100
+
101
+ export { SettingsPageComponent };
102
+ //# sourceMappingURL=yuuvis-client-shell-settings.component-B9ZmZGaU.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yuuvis-client-shell-settings.component-B9ZmZGaU.mjs","sources":["../../../../../libs/yuuvis/client-shell/src/lib/pages/settings/settings.component.ts","../../../../../libs/yuuvis/client-shell/src/lib/pages/settings/settings.component.html"],"sourcesContent":["import { Component, computed, effect, inject, OnInit, Signal, signal } from '@angular/core';\nimport { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';\nimport { AppCacheService, ConfigService, TranslateModule, TranslateService, UserService, YuvConfigLanguages, YuvUser } from '@yuuvis/client-core';\n\nimport { CommonModule, DOCUMENT } from '@angular/common';\nimport { HttpClient } from '@angular/common/http';\nimport { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';\nimport { MatButtonToggle, MatButtonToggleChange, MatButtonToggleGroup } from '@angular/material/button-toggle';\nimport { MatExpansionModule } from '@angular/material/expansion';\nimport { MatSelectModule } from '@angular/material/select';\nimport { MatTableModule } from '@angular/material/table';\nimport { ShellAppSettingProperty, ShellAppSettings, ShellService } from '@yuuvis/client-shell-core';\nimport { map, Observable } from 'rxjs';\nimport { AboutData } from './settings.model';\nimport { LayoutMode, LayoutSettingsService } from '@yuuvis/client-framework/common';\n\n@Component({\n selector: 'yuv-settings',\n standalone: true,\n imports: [CommonModule, TranslateModule, MatSelectModule, ReactiveFormsModule, MatButtonToggleGroup, MatButtonToggle, MatExpansionModule, MatTableModule],\n templateUrl: './settings.component.html',\n styleUrls: ['./settings.component.scss']\n})\nexport class SettingsPageComponent implements OnInit {\n private userService = inject(UserService);\n private config = inject(ConfigService);\n public translate = inject(TranslateService);\n private shell = inject(ShellService);\n readonly document = inject(DOCUMENT);\n #layoutSettingsService = inject(LayoutSettingsService);\n #http = inject(HttpClient);\n\n clientLocales = signal<YuvConfigLanguages[]>([]);\n clientVersion = signal<string | undefined>(undefined);\n clientAboutData = signal<AboutData | undefined>(undefined);\n currentMode = this.#layoutSettingsService.mode;\n\n user: Signal<YuvUser | undefined> = toSignal(this.userService.user$);\n appSettings = signal<(ShellAppSettings & { _label: string })[]>([]);\n #appSettings = this.shell.appSettings;\n #appSettingsEffect = effect(() => {\n const as = this.#appSettings();\n this.#mapAppSettings(as);\n });\n\n constructor() {\n this.translate.onLangChange.pipe(takeUntilDestroyed()).subscribe(() => {\n this.#mapAppSettings(this.appSettings());\n });\n }\n\n #mapAppSettings(as: ShellAppSettings[]) {\n this.appSettings.set(\n as.map((appSetting) => {\n const translatedLabel = this.translate.instant(appSetting.label);\n const label = translatedLabel && !translatedLabel.startsWith('!missing') ? translatedLabel : appSetting.label;\n return {\n ...appSetting,\n _label: label\n };\n })\n );\n }\n\n changeClientLocale(iso: string) {\n this.userService.changeClientLocale(iso);\n }\n\n changeMode({ value }: MatButtonToggleChange) {\n if (value && value !== this.currentMode()) {\n this.#layoutSettingsService.setMode(value);\n this.#layoutSettingsService.applyLayoutMode(value);\n }\n }\n\n toggleDarkMode() {\n const root = document.getElementsByTagName('body')[0];\n root.classList.toggle('dark');\n }\n\n ngOnInit(): void {\n this.clientVersion.set(this.document.body.getAttribute('data-version') ?? 'dev');\n this.clientLocales.set(this.config.getClientLocales());\n this.getAboutData();\n }\n\n getAboutData() {\n this.#http\n .get('assets/about.data.json')\n .pipe(\n map((response: AboutData) => ({\n ...response,\n libraries: response.libraries\n ? response.libraries.map((lib) => ({\n ...lib,\n ...(lib.license !== 'SEE LICENSE IN LICENSE' ? { link: `https://opensource.org/license/${lib.license}` } : {})\n }))\n : undefined\n }))\n )\n .subscribe({\n next: (response: AboutData) => this.clientAboutData.set(response),\n error: (error) => console.log({ error })\n });\n }\n}\n","<header>\n <h1>{{ 'yuv.shell.settings.title' | translate }}</h1>\n <span class=\"subhead\">{{ 'yuv.shell.settings.client.version' | translate }}: {{ clientVersion() }}</span>\n</header>\n\n<main>\n <div class=\"content-container\">\n <!-- User Info -->\n @let user = this.user();\n @if (user) {\n <section class=\"section user\">\n <h2 class=\"section__title\">{{ user.title }}</h2>\n <div class=\"section__body user__data grid\">\n <div class=\"user__data-entry grid-row\">\n <span class=\"user__data-entry-key grid-col grid-col-key\"> {{ 'yuv.shell.settings.user.email' | translate }}: </span>\n <span class=\"user__data-entry-value grid-col grid-col-value\">\n {{ user.email }}\n </span>\n </div>\n <div class=\"user__data-entry grid-row\">\n <span class=\"user__data-entry-key grid-col grid-col-key\"> {{ 'yuv.shell.settings.tenant' | translate }}: </span>\n <span class=\"user__data-entry-value grid-col grid-col-value\">\n {{ user.tenant }}\n </span>\n </div>\n\n <!--<div class=\"user__data\">{{ 'yuv.shell.settings.user.name' | translate }}: {{ user.username }}</div>\n <div class=\"user__data-entry\">{{ 'yuv.shell.settings.user.email' | translate }}: {{ user.email }}</div>\n <div class=\"user__data-entry\">{{ 'yuv.shell.settings.tenant' | translate }}: {{ user.tenant }}</div>-->\n </div>\n </section>\n }\n <!-- Language Settings -->\n <section yuvOfflineDisabled class=\"section\">\n <h2 class=\"section__title\">{{ 'yuv.shell.settings.language' | translate }}</h2>\n <div class=\"section__body\">\n <mat-button-toggle-group\n name=\"language\"\n [value]=\"translate.currentLang\"\n (valueChange)=\"changeClientLocale($event)\"\n [attr.aria-label]=\"'yuv.shell.settings.language' | translate\"\n >\n @for (locale of clientLocales(); track locale.iso) {\n <mat-button-toggle value=\"{{ locale.iso }}\">{{ locale.label }}</mat-button-toggle>\n }\n </mat-button-toggle-group>\n </div>\n </section>\n\n <!-- Mode -->\n @let currentThemeMode = currentMode();\n <section class=\"section\">\n <h2 class=\"section__title\">{{ 'yuv.shell.settings.mode' | translate }}</h2>\n <div class=\"section__body\">\n <mat-button-toggle-group name=\"mode\" [value]=\"currentThemeMode\" (change)=\"changeMode($event)\" [attr.aria-label]=\"'yuv.shell.settings.mode' | translate\">\n <mat-button-toggle value=\"light\">{{ 'yuv.shell.settings.mode.light' | translate }}</mat-button-toggle>\n <mat-button-toggle value=\"dark\">{{ 'yuv.shell.settings.mode.dark' | translate }}</mat-button-toggle>\n <mat-button-toggle value=\"system\">{{ 'yuv.shell.settings.mode.system' | translate }}</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n </section>\n\n <!-- app settings -->\n @for (c of appSettings(); track $index) {\n <section class=\"section\">\n <h2 class=\"section__title\">{{ c._label }}</h2>\n <div class=\"section__body\">\n <ng-container *ngComponentOutlet=\"c.component\"></ng-container>\n </div>\n </section>\n }\n\n <!-- About Info -->\n @let libraries = this.clientAboutData()?.libraries;\n @if (libraries) {\n <section class=\"section about\">\n <h2 class=\"section__title\">{{ 'yuv.shell.settings.about.title' | translate }}</h2>\n <mat-expansion-panel class=\"about__panel\">\n <mat-expansion-panel-header>\n <mat-panel-title>{{ 'yuv.shell.settings.dependency-info.title' | translate }}</mat-panel-title>\n <!-- <mat-panel-description>{{ '' | translate }}</mat-panel-description>-->\n </mat-expansion-panel-header>\n\n <ng-template matExpansionPanelContent>\n <div class=\"about__panel-content\">\n <table mat-table [dataSource]=\"libraries\" class=\"mat-elevation-z8\">\n <!-- Name Column -->\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef>{{ 'yuv.shell.settings.dependency-info.package' | translate }}</th>\n <td mat-cell *matCellDef=\"let element\">{{ element.name }}</td>\n </ng-container>\n\n <!-- Version Column -->\n <ng-container matColumnDef=\"version\">\n <th mat-header-cell *matHeaderCellDef>{{ 'yuv.shell.settings.dependency-info.version' | translate }}</th>\n <td mat-cell *matCellDef=\"let element\">{{ element.version }}</td>\n </ng-container>\n\n <!-- License Column -->\n <ng-container matColumnDef=\"license\">\n <th mat-header-cell *matHeaderCellDef>{{ 'yuv.shell.settings.dependency-info.license' | translate }}</th>\n <td mat-cell *matCellDef=\"let element\">\n @if (element.link) {\n <a href=\"{{ element.link }}\" target=\"_blank\">{{ element.license }}</a>\n } @else {\n {{ element.license }}\n }\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"['name', 'version', 'license']\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['name', 'version', 'license']\"></tr>\n </table>\n </div>\n </ng-template>\n </mat-expansion-panel>\n </section>\n }\n </div>\n</main>\n"],"names":["i2"],"mappings":"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"}
@@ -507,7 +507,7 @@ const clientShellRoutes = [
507
507
  { path: 'notifications', component: NotificationsPageComponent, outlet: 'aside' },
508
508
  // tracking outlet for dialogs
509
509
  { path: 'dialogs/:id', component: DialogTrackingComponent, outlet: 'dt', canDeactivate: [closeDialogGuard] },
510
- { path: 'settings', loadComponent: () => import('./yuuvis-client-shell-settings.component-DWoamL5p.mjs').then((comp) => comp.SettingsPageComponent) },
510
+ { path: 'settings', loadComponent: () => import('./yuuvis-client-shell-settings.component-B9ZmZGaU.mjs').then((comp) => comp.SettingsPageComponent) },
511
511
  // default route
512
512
  { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
513
513
  // redirecting route
@@ -1,9 +1,7 @@
1
1
  import { OnInit, Signal } from '@angular/core';
2
2
  import { TranslateService, YuvConfigLanguages, YuvUser } from '@yuuvis/client-core';
3
- import { FormGroup } from '@angular/forms';
4
3
  import { MatButtonToggleChange } from '@angular/material/button-toggle';
5
- import { ShellAppSettingProperty } from '@yuuvis/client-shell-core';
6
- import { Observable } from 'rxjs';
4
+ import { ShellAppSettings } from '@yuuvis/client-shell-core';
7
5
  import { AboutData } from './settings.model';
8
6
  import { LayoutMode } from '@yuuvis/client-framework/common';
9
7
  import * as i0 from "@angular/core";
@@ -19,13 +17,10 @@ export declare class SettingsPageComponent implements OnInit {
19
17
  clientAboutData: import("@angular/core").WritableSignal<AboutData | undefined>;
20
18
  currentMode: Signal<LayoutMode>;
21
19
  user: Signal<YuvUser | undefined>;
22
- appSettingForms$: Observable<{
23
- appID: string;
24
- label: string;
25
- formControls: ShellAppSettingProperty[];
26
- form: FormGroup;
27
- }[]>;
28
- saveAppSettings(appID: string, form: FormGroup): void;
20
+ appSettings: import("@angular/core").WritableSignal<(ShellAppSettings & {
21
+ _label: string;
22
+ })[]>;
23
+ constructor();
29
24
  changeClientLocale(iso: string): void;
30
25
  changeMode({ value }: MatButtonToggleChange): void;
31
26
  toggleDarkMode(): void;
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@yuuvis/client-shell",
3
- "version": "2.3.9",
3
+ "version": "2.3.11",
4
4
  "author": "OPTIMAL SYSTEMS GmbH <npm@optimal-systems.de>",
5
5
  "license": "MIT",
6
6
  "peerDependencies": {
7
7
  "@angular/common": "^19.2.1",
8
8
  "@angular/core": "^19.2.1",
9
9
  "@angular/service-worker": "^19.2.1",
10
- "@yuuvis/client-core": "^2.3.9",
11
- "@yuuvis/client-shell-core": "^2.3.9",
12
- "@yuuvis/client-framework": "^2.3.9"
10
+ "@yuuvis/client-core": "^2.3.11",
11
+ "@yuuvis/client-shell-core": "^2.3.11",
12
+ "@yuuvis/client-framework": "^2.3.11"
13
13
  },
14
14
  "dependencies": {
15
15
  "tslib": "^2.3.0"
@@ -1,115 +0,0 @@
1
- import * as i0 from '@angular/core';
2
- import { inject, signal, Component } from '@angular/core';
3
- import { toSignal } from '@angular/core/rxjs-interop';
4
- import * as i3 from '@yuuvis/client-core';
5
- import { UserService, ConfigService, TranslateService, TranslateModule } from '@yuuvis/client-core';
6
- import { DOCUMENT, CommonModule } from '@angular/common';
7
- import { HttpClient } from '@angular/common/http';
8
- import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
9
- import { MatButtonToggleGroup, MatButtonToggle } from '@angular/material/button-toggle';
10
- import * as i2 from '@angular/material/expansion';
11
- import { MatExpansionModule } from '@angular/material/expansion';
12
- import { MatSelectModule } from '@angular/material/select';
13
- import * as i3$1 from '@angular/material/table';
14
- import { MatTableModule } from '@angular/material/table';
15
- import { ShellService } from '@yuuvis/client-shell-core';
16
- import { map } from 'rxjs';
17
- import { LayoutSettingsService } from '@yuuvis/client-framework/common';
18
-
19
- class SettingsPageComponent {
20
- constructor() {
21
- this.userService = inject(UserService);
22
- this.config = inject(ConfigService);
23
- this.translate = inject(TranslateService);
24
- this.shell = inject(ShellService);
25
- this.document = inject(DOCUMENT);
26
- this.#layoutSettingsService = inject(LayoutSettingsService);
27
- this.#http = inject(HttpClient);
28
- this.#fb = inject(FormBuilder);
29
- this.clientLocales = signal([]);
30
- this.clientVersion = signal(undefined);
31
- this.clientAboutData = signal(undefined);
32
- this.currentMode = this.#layoutSettingsService.mode;
33
- this.user = toSignal(this.userService.user$);
34
- this.appSettingForms$ = this.shell.appSettings$.pipe(map((settings) => settings.map((e) => {
35
- const x = {};
36
- const fcn = e.properties.map((p) => ({
37
- label: this.translate.instant(p.label) || p.label,
38
- name: p.name,
39
- type: p.type
40
- }));
41
- e.properties.forEach((p) => {
42
- x[p.name] = [p.value];
43
- });
44
- return {
45
- appID: e.appID,
46
- label: e.label,
47
- formControls: fcn,
48
- form: this.#fb.group(x)
49
- };
50
- })));
51
- }
52
- #layoutSettingsService;
53
- #http;
54
- #fb;
55
- saveAppSettings(appID, form) {
56
- this.userService
57
- .saveUserSettings({
58
- clientAppSettings: {
59
- [appID]: form.value
60
- }
61
- })
62
- .subscribe({
63
- next: () => {
64
- form.markAsPristine();
65
- },
66
- error: (err) => {
67
- console.error('Error saving app settings', err);
68
- }
69
- });
70
- }
71
- changeClientLocale(iso) {
72
- this.userService.changeClientLocale(iso);
73
- }
74
- changeMode({ value }) {
75
- if (value && value !== this.currentMode()) {
76
- this.#layoutSettingsService.setMode(value);
77
- this.#layoutSettingsService.applyLayoutMode(value);
78
- }
79
- }
80
- toggleDarkMode() {
81
- const root = document.getElementsByTagName('body')[0];
82
- root.classList.toggle('dark');
83
- }
84
- ngOnInit() {
85
- this.clientVersion.set(this.document.body.getAttribute('data-version') ?? 'dev');
86
- this.clientLocales.set(this.config.getClientLocales());
87
- this.getAboutData();
88
- }
89
- getAboutData() {
90
- this.#http
91
- .get('assets/about.data.json')
92
- .pipe(map((response) => ({
93
- ...response,
94
- libraries: response.libraries
95
- ? response.libraries.map((lib) => ({
96
- ...lib,
97
- ...(lib.license !== 'SEE LICENSE IN LICENSE' ? { link: `https://opensource.org/license/${lib.license}` } : {})
98
- }))
99
- : undefined
100
- })))
101
- .subscribe({
102
- next: (response) => this.clientAboutData.set(response),
103
- error: (error) => console.log({ error })
104
- });
105
- }
106
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SettingsPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
107
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: SettingsPageComponent, isStandalone: true, selector: "yuv-settings", ngImport: i0, template: "<header>\n <h1>{{ 'yuv.shell.settings.title' | translate }}</h1>\n <span class=\"subhead\">{{ 'yuv.shell.settings.client.version' | translate }}: {{ clientVersion() }}</span>\n</header>\n\n<main>\n <div class=\"content-container\">\n <!-- User Info -->\n @let user = this.user();\n @if (user) {\n <section class=\"section user\">\n <h2 class=\"section__title\">{{ user.title }}</h2>\n <div class=\"section__body user__data grid\">\n <div class=\"user__data-entry grid-row\">\n <span class=\"user__data-entry-key grid-col grid-col-key\"> {{ 'yuv.shell.settings.user.email' | translate }}: </span>\n <span class=\"user__data-entry-value grid-col grid-col-value\">\n {{ user.email }}\n </span>\n </div>\n <div class=\"user__data-entry grid-row\">\n <span class=\"user__data-entry-key grid-col grid-col-key\"> {{ 'yuv.shell.settings.tenant' | translate }}: </span>\n <span class=\"user__data-entry-value grid-col grid-col-value\">\n {{ user.tenant }}\n </span>\n </div>\n\n <!--<div class=\"user__data\">{{ 'yuv.shell.settings.user.name' | translate }}: {{ user.username }}</div>\n <div class=\"user__data-entry\">{{ 'yuv.shell.settings.user.email' | translate }}: {{ user.email }}</div>\n <div class=\"user__data-entry\">{{ 'yuv.shell.settings.tenant' | translate }}: {{ user.tenant }}</div>-->\n </div>\n </section>\n }\n <!-- Language Settings -->\n <section yuvOfflineDisabled class=\"section\">\n <h2 class=\"section__title\">{{ 'yuv.shell.settings.language' | translate }}</h2>\n <div class=\"section__body\">\n <mat-button-toggle-group\n name=\"language\"\n [value]=\"translate.currentLang\"\n (valueChange)=\"changeClientLocale($event)\"\n [attr.aria-label]=\"'yuv.shell.settings.language' | translate\"\n >\n @for (locale of clientLocales(); track locale.iso) {\n <mat-button-toggle value=\"{{ locale.iso }}\">{{ locale.label }}</mat-button-toggle>\n }\n </mat-button-toggle-group>\n </div>\n </section>\n\n <!-- Mode -->\n @let currentThemeMode = currentMode();\n <section class=\"section\">\n <h2 class=\"section__title\">{{ 'yuv.shell.settings.mode' | translate }}</h2>\n <div class=\"section__body\">\n <mat-button-toggle-group name=\"mode\" [value]=\"currentThemeMode\" (change)=\"changeMode($event)\" [attr.aria-label]=\"'yuv.shell.settings.mode' | translate\">\n <mat-button-toggle value=\"light\">{{ 'yuv.shell.settings.mode.light' | translate }}</mat-button-toggle>\n <mat-button-toggle value=\"dark\">{{ 'yuv.shell.settings.mode.dark' | translate }}</mat-button-toggle>\n <mat-button-toggle value=\"system\">{{ 'yuv.shell.settings.mode.system' | translate }}</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n </section>\n\n <!-- About Info -->\n @let libraries = this.clientAboutData()?.libraries;\n @if (libraries) {\n <section class=\"section about\">\n <h2 class=\"section__title\">{{ 'yuv.shell.settings.about.title' | translate }}</h2>\n <mat-expansion-panel class=\"about__panel\">\n <mat-expansion-panel-header>\n <mat-panel-title>{{ 'yuv.shell.settings.dependency-info.title' | translate }}</mat-panel-title>\n <!-- <mat-panel-description>{{ '' | translate }}</mat-panel-description>-->\n </mat-expansion-panel-header>\n\n <ng-template matExpansionPanelContent>\n <div class=\"about__panel-content\">\n <table mat-table [dataSource]=\"libraries\" class=\"mat-elevation-z8\">\n <!-- Name Column -->\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef>{{ 'yuv.shell.settings.dependency-info.package' | translate }}</th>\n <td mat-cell *matCellDef=\"let element\">{{ element.name }}</td>\n </ng-container>\n\n <!-- Version Column -->\n <ng-container matColumnDef=\"version\">\n <th mat-header-cell *matHeaderCellDef>{{ 'yuv.shell.settings.dependency-info.version' | translate }}</th>\n <td mat-cell *matCellDef=\"let element\">{{ element.version }}</td>\n </ng-container>\n\n <!-- License Column -->\n <ng-container matColumnDef=\"license\">\n <th mat-header-cell *matHeaderCellDef>{{ 'yuv.shell.settings.dependency-info.license' | translate }}</th>\n <td mat-cell *matCellDef=\"let element\">\n @if (element.link) {\n <a href=\"{{ element.link }}\" target=\"_blank\">{{ element.license }}</a>\n } @else {\n {{ element.license }}\n }\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"['name', 'version', 'license']\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['name', 'version', 'license']\"></tr>\n </table>\n </div>\n </ng-template>\n </mat-expansion-panel>\n </section>\n }\n <!-- app settings -->\n <!-- TODO: activate one feature is refined -->\n <!-- @for (c of appSettingForms$ | async; track $index) {\n <section>\n {{ c.label }}\n <form [formGroup]=\"c.form\" (ngSubmit)=\"saveAppSettings(c.appID, c.form)\">\n @for (n of c.formControls; track $index) {\n <label\n >{{ n.label }}\n\n @switch (n.type) {\n @case ('string') {\n <input type=\"text\" [formControlName]=\"n.name\" />\n }\n @case ('number') {\n <input type=\"number\" [formControlName]=\"n.name\" />\n }\n }\n </label>\n }\n <button [ngClass]=\"{ hideen: c.form.untouched }\" [disabled]=\"c.form.invalid\">Save</button>\n </form>\n </section>\n } -->\n </div>\n</main>\n", styles: [":host{display:grid;grid-template-columns:1fr auto;grid-template-rows:auto 1fr;grid-template-areas:\"header\" \"settings\";height:100%;overflow:hidden;overflow-y:auto}:host header{grid-area:header;padding:var(--ymt-spacing-3xl)}:host header h1{margin:0}:host header .subhead{font:var(--ymt-font-subhead);color:var(--ymt-text-color-subtle)}:host main{grid-area:settings;padding:var(--ymt-spacing-m);padding-right:0;overflow-y:auto;scrollbar-gutter:stable}:host main .content-container{max-width:900px}:host main section{display:flex;flex-flow:column;padding:var(--ymt-spacing-m);margin-bottom:var(--ymt-spacing-l)}:host main .about__panel-content{overflow-x:auto}:host main .grid-row{display:grid;grid-template-columns:minmax(10ch,1fr) 11fr;grid-gap:var(--ymt-spacing-s);grid-template-areas:\"key value\";align-items:baseline}:host main .grid-col-key{font-weight:700;grid-area:key}:host main .grid-col-value{grid-area:value;word-break:break-all}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i2.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i2.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i2.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "directive", type: i2.MatExpansionPanelContent, selector: "ng-template[matExpansionPanelContent]" }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i3$1.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i3$1.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i3$1.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i3$1.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i3$1.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i3$1.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i3$1.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i3$1.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i3$1.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i3$1.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }] }); }
108
- }
109
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SettingsPageComponent, decorators: [{
110
- type: Component,
111
- args: [{ selector: 'yuv-settings', standalone: true, imports: [CommonModule, TranslateModule, MatSelectModule, ReactiveFormsModule, MatButtonToggleGroup, MatButtonToggle, MatExpansionModule, MatTableModule], template: "<header>\n <h1>{{ 'yuv.shell.settings.title' | translate }}</h1>\n <span class=\"subhead\">{{ 'yuv.shell.settings.client.version' | translate }}: {{ clientVersion() }}</span>\n</header>\n\n<main>\n <div class=\"content-container\">\n <!-- User Info -->\n @let user = this.user();\n @if (user) {\n <section class=\"section user\">\n <h2 class=\"section__title\">{{ user.title }}</h2>\n <div class=\"section__body user__data grid\">\n <div class=\"user__data-entry grid-row\">\n <span class=\"user__data-entry-key grid-col grid-col-key\"> {{ 'yuv.shell.settings.user.email' | translate }}: </span>\n <span class=\"user__data-entry-value grid-col grid-col-value\">\n {{ user.email }}\n </span>\n </div>\n <div class=\"user__data-entry grid-row\">\n <span class=\"user__data-entry-key grid-col grid-col-key\"> {{ 'yuv.shell.settings.tenant' | translate }}: </span>\n <span class=\"user__data-entry-value grid-col grid-col-value\">\n {{ user.tenant }}\n </span>\n </div>\n\n <!--<div class=\"user__data\">{{ 'yuv.shell.settings.user.name' | translate }}: {{ user.username }}</div>\n <div class=\"user__data-entry\">{{ 'yuv.shell.settings.user.email' | translate }}: {{ user.email }}</div>\n <div class=\"user__data-entry\">{{ 'yuv.shell.settings.tenant' | translate }}: {{ user.tenant }}</div>-->\n </div>\n </section>\n }\n <!-- Language Settings -->\n <section yuvOfflineDisabled class=\"section\">\n <h2 class=\"section__title\">{{ 'yuv.shell.settings.language' | translate }}</h2>\n <div class=\"section__body\">\n <mat-button-toggle-group\n name=\"language\"\n [value]=\"translate.currentLang\"\n (valueChange)=\"changeClientLocale($event)\"\n [attr.aria-label]=\"'yuv.shell.settings.language' | translate\"\n >\n @for (locale of clientLocales(); track locale.iso) {\n <mat-button-toggle value=\"{{ locale.iso }}\">{{ locale.label }}</mat-button-toggle>\n }\n </mat-button-toggle-group>\n </div>\n </section>\n\n <!-- Mode -->\n @let currentThemeMode = currentMode();\n <section class=\"section\">\n <h2 class=\"section__title\">{{ 'yuv.shell.settings.mode' | translate }}</h2>\n <div class=\"section__body\">\n <mat-button-toggle-group name=\"mode\" [value]=\"currentThemeMode\" (change)=\"changeMode($event)\" [attr.aria-label]=\"'yuv.shell.settings.mode' | translate\">\n <mat-button-toggle value=\"light\">{{ 'yuv.shell.settings.mode.light' | translate }}</mat-button-toggle>\n <mat-button-toggle value=\"dark\">{{ 'yuv.shell.settings.mode.dark' | translate }}</mat-button-toggle>\n <mat-button-toggle value=\"system\">{{ 'yuv.shell.settings.mode.system' | translate }}</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n </section>\n\n <!-- About Info -->\n @let libraries = this.clientAboutData()?.libraries;\n @if (libraries) {\n <section class=\"section about\">\n <h2 class=\"section__title\">{{ 'yuv.shell.settings.about.title' | translate }}</h2>\n <mat-expansion-panel class=\"about__panel\">\n <mat-expansion-panel-header>\n <mat-panel-title>{{ 'yuv.shell.settings.dependency-info.title' | translate }}</mat-panel-title>\n <!-- <mat-panel-description>{{ '' | translate }}</mat-panel-description>-->\n </mat-expansion-panel-header>\n\n <ng-template matExpansionPanelContent>\n <div class=\"about__panel-content\">\n <table mat-table [dataSource]=\"libraries\" class=\"mat-elevation-z8\">\n <!-- Name Column -->\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef>{{ 'yuv.shell.settings.dependency-info.package' | translate }}</th>\n <td mat-cell *matCellDef=\"let element\">{{ element.name }}</td>\n </ng-container>\n\n <!-- Version Column -->\n <ng-container matColumnDef=\"version\">\n <th mat-header-cell *matHeaderCellDef>{{ 'yuv.shell.settings.dependency-info.version' | translate }}</th>\n <td mat-cell *matCellDef=\"let element\">{{ element.version }}</td>\n </ng-container>\n\n <!-- License Column -->\n <ng-container matColumnDef=\"license\">\n <th mat-header-cell *matHeaderCellDef>{{ 'yuv.shell.settings.dependency-info.license' | translate }}</th>\n <td mat-cell *matCellDef=\"let element\">\n @if (element.link) {\n <a href=\"{{ element.link }}\" target=\"_blank\">{{ element.license }}</a>\n } @else {\n {{ element.license }}\n }\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"['name', 'version', 'license']\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['name', 'version', 'license']\"></tr>\n </table>\n </div>\n </ng-template>\n </mat-expansion-panel>\n </section>\n }\n <!-- app settings -->\n <!-- TODO: activate one feature is refined -->\n <!-- @for (c of appSettingForms$ | async; track $index) {\n <section>\n {{ c.label }}\n <form [formGroup]=\"c.form\" (ngSubmit)=\"saveAppSettings(c.appID, c.form)\">\n @for (n of c.formControls; track $index) {\n <label\n >{{ n.label }}\n\n @switch (n.type) {\n @case ('string') {\n <input type=\"text\" [formControlName]=\"n.name\" />\n }\n @case ('number') {\n <input type=\"number\" [formControlName]=\"n.name\" />\n }\n }\n </label>\n }\n <button [ngClass]=\"{ hideen: c.form.untouched }\" [disabled]=\"c.form.invalid\">Save</button>\n </form>\n </section>\n } -->\n </div>\n</main>\n", styles: [":host{display:grid;grid-template-columns:1fr auto;grid-template-rows:auto 1fr;grid-template-areas:\"header\" \"settings\";height:100%;overflow:hidden;overflow-y:auto}:host header{grid-area:header;padding:var(--ymt-spacing-3xl)}:host header h1{margin:0}:host header .subhead{font:var(--ymt-font-subhead);color:var(--ymt-text-color-subtle)}:host main{grid-area:settings;padding:var(--ymt-spacing-m);padding-right:0;overflow-y:auto;scrollbar-gutter:stable}:host main .content-container{max-width:900px}:host main section{display:flex;flex-flow:column;padding:var(--ymt-spacing-m);margin-bottom:var(--ymt-spacing-l)}:host main .about__panel-content{overflow-x:auto}:host main .grid-row{display:grid;grid-template-columns:minmax(10ch,1fr) 11fr;grid-gap:var(--ymt-spacing-s);grid-template-areas:\"key value\";align-items:baseline}:host main .grid-col-key{font-weight:700;grid-area:key}:host main .grid-col-value{grid-area:value;word-break:break-all}\n"] }]
112
- }] });
113
-
114
- export { SettingsPageComponent };
115
- //# sourceMappingURL=yuuvis-client-shell-settings.component-DWoamL5p.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"yuuvis-client-shell-settings.component-DWoamL5p.mjs","sources":["../../../../../libs/yuuvis/client-shell/src/lib/pages/settings/settings.component.ts","../../../../../libs/yuuvis/client-shell/src/lib/pages/settings/settings.component.html"],"sourcesContent":["import { Component, inject, OnInit, Signal, signal } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { AppCacheService, ConfigService, TranslateModule, TranslateService, UserService, YuvConfigLanguages, YuvUser } from '@yuuvis/client-core';\n\nimport { CommonModule, DOCUMENT } from '@angular/common';\nimport { HttpClient } from '@angular/common/http';\nimport { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';\nimport { MatButtonToggle, MatButtonToggleChange, MatButtonToggleGroup } from '@angular/material/button-toggle';\nimport { MatExpansionModule } from '@angular/material/expansion';\nimport { MatSelectModule } from '@angular/material/select';\nimport { MatTableModule } from '@angular/material/table';\nimport { ShellAppSettingProperty, ShellAppSettings, ShellService } from '@yuuvis/client-shell-core';\nimport { map, Observable } from 'rxjs';\nimport { AboutData } from './settings.model';\nimport { LayoutMode, LayoutSettingsService } from '@yuuvis/client-framework/common';\n\n@Component({\n selector: 'yuv-settings',\n standalone: true,\n imports: [CommonModule, TranslateModule, MatSelectModule, ReactiveFormsModule, MatButtonToggleGroup, MatButtonToggle, MatExpansionModule, MatTableModule],\n templateUrl: './settings.component.html',\n styleUrls: ['./settings.component.scss']\n})\nexport class SettingsPageComponent implements OnInit {\n private userService = inject(UserService);\n private config = inject(ConfigService);\n public translate = inject(TranslateService);\n private shell = inject(ShellService);\n readonly document = inject(DOCUMENT);\n #layoutSettingsService = inject(LayoutSettingsService);\n #http = inject(HttpClient);\n\n #fb = inject(FormBuilder);\n\n clientLocales = signal<YuvConfigLanguages[]>([]);\n clientVersion = signal<string | undefined>(undefined);\n clientAboutData = signal<AboutData | undefined>(undefined);\n currentMode = this.#layoutSettingsService.mode;\n\n user: Signal<YuvUser | undefined> = toSignal(this.userService.user$);\n appSettingForms$: Observable<\n {\n appID: string;\n label: string;\n formControls: ShellAppSettingProperty[];\n form: FormGroup;\n }[]\n > = this.shell.appSettings$.pipe(\n map((settings: ShellAppSettings[]) =>\n settings.map((e) => {\n const x: any = {};\n const fcn: ShellAppSettingProperty[] = e.properties.map((p) => ({\n label: this.translate.instant(p.label) || p.label,\n name: p.name,\n type: p.type\n }));\n e.properties.forEach((p) => {\n x[p.name] = [p.value];\n });\n return {\n appID: e.appID,\n label: e.label,\n formControls: fcn,\n form: this.#fb.group(x)\n };\n })\n )\n );\n\n saveAppSettings(appID: string, form: FormGroup) {\n this.userService\n .saveUserSettings({\n clientAppSettings: {\n [appID]: form.value\n }\n })\n .subscribe({\n next: () => {\n form.markAsPristine();\n },\n error: (err) => {\n console.error('Error saving app settings', err);\n }\n });\n }\n\n changeClientLocale(iso: string) {\n this.userService.changeClientLocale(iso);\n }\n\n changeMode({ value }: MatButtonToggleChange) {\n if (value && value !== this.currentMode()) {\n this.#layoutSettingsService.setMode(value);\n this.#layoutSettingsService.applyLayoutMode(value);\n }\n }\n\n toggleDarkMode() {\n const root = document.getElementsByTagName('body')[0];\n root.classList.toggle('dark');\n }\n\n ngOnInit(): void {\n this.clientVersion.set(this.document.body.getAttribute('data-version') ?? 'dev');\n this.clientLocales.set(this.config.getClientLocales());\n this.getAboutData();\n }\n\n getAboutData() {\n this.#http\n .get('assets/about.data.json')\n .pipe(\n map((response: AboutData) => ({\n ...response,\n libraries: response.libraries\n ? response.libraries.map((lib) => ({\n ...lib,\n ...(lib.license !== 'SEE LICENSE IN LICENSE' ? { link: `https://opensource.org/license/${lib.license}` } : {})\n }))\n : undefined\n }))\n )\n .subscribe({\n next: (response: AboutData) => this.clientAboutData.set(response),\n error: (error) => console.log({ error })\n });\n }\n}\n","<header>\n <h1>{{ 'yuv.shell.settings.title' | translate }}</h1>\n <span class=\"subhead\">{{ 'yuv.shell.settings.client.version' | translate }}: {{ clientVersion() }}</span>\n</header>\n\n<main>\n <div class=\"content-container\">\n <!-- User Info -->\n @let user = this.user();\n @if (user) {\n <section class=\"section user\">\n <h2 class=\"section__title\">{{ user.title }}</h2>\n <div class=\"section__body user__data grid\">\n <div class=\"user__data-entry grid-row\">\n <span class=\"user__data-entry-key grid-col grid-col-key\"> {{ 'yuv.shell.settings.user.email' | translate }}: </span>\n <span class=\"user__data-entry-value grid-col grid-col-value\">\n {{ user.email }}\n </span>\n </div>\n <div class=\"user__data-entry grid-row\">\n <span class=\"user__data-entry-key grid-col grid-col-key\"> {{ 'yuv.shell.settings.tenant' | translate }}: </span>\n <span class=\"user__data-entry-value grid-col grid-col-value\">\n {{ user.tenant }}\n </span>\n </div>\n\n <!--<div class=\"user__data\">{{ 'yuv.shell.settings.user.name' | translate }}: {{ user.username }}</div>\n <div class=\"user__data-entry\">{{ 'yuv.shell.settings.user.email' | translate }}: {{ user.email }}</div>\n <div class=\"user__data-entry\">{{ 'yuv.shell.settings.tenant' | translate }}: {{ user.tenant }}</div>-->\n </div>\n </section>\n }\n <!-- Language Settings -->\n <section yuvOfflineDisabled class=\"section\">\n <h2 class=\"section__title\">{{ 'yuv.shell.settings.language' | translate }}</h2>\n <div class=\"section__body\">\n <mat-button-toggle-group\n name=\"language\"\n [value]=\"translate.currentLang\"\n (valueChange)=\"changeClientLocale($event)\"\n [attr.aria-label]=\"'yuv.shell.settings.language' | translate\"\n >\n @for (locale of clientLocales(); track locale.iso) {\n <mat-button-toggle value=\"{{ locale.iso }}\">{{ locale.label }}</mat-button-toggle>\n }\n </mat-button-toggle-group>\n </div>\n </section>\n\n <!-- Mode -->\n @let currentThemeMode = currentMode();\n <section class=\"section\">\n <h2 class=\"section__title\">{{ 'yuv.shell.settings.mode' | translate }}</h2>\n <div class=\"section__body\">\n <mat-button-toggle-group name=\"mode\" [value]=\"currentThemeMode\" (change)=\"changeMode($event)\" [attr.aria-label]=\"'yuv.shell.settings.mode' | translate\">\n <mat-button-toggle value=\"light\">{{ 'yuv.shell.settings.mode.light' | translate }}</mat-button-toggle>\n <mat-button-toggle value=\"dark\">{{ 'yuv.shell.settings.mode.dark' | translate }}</mat-button-toggle>\n <mat-button-toggle value=\"system\">{{ 'yuv.shell.settings.mode.system' | translate }}</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n </section>\n\n <!-- About Info -->\n @let libraries = this.clientAboutData()?.libraries;\n @if (libraries) {\n <section class=\"section about\">\n <h2 class=\"section__title\">{{ 'yuv.shell.settings.about.title' | translate }}</h2>\n <mat-expansion-panel class=\"about__panel\">\n <mat-expansion-panel-header>\n <mat-panel-title>{{ 'yuv.shell.settings.dependency-info.title' | translate }}</mat-panel-title>\n <!-- <mat-panel-description>{{ '' | translate }}</mat-panel-description>-->\n </mat-expansion-panel-header>\n\n <ng-template matExpansionPanelContent>\n <div class=\"about__panel-content\">\n <table mat-table [dataSource]=\"libraries\" class=\"mat-elevation-z8\">\n <!-- Name Column -->\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef>{{ 'yuv.shell.settings.dependency-info.package' | translate }}</th>\n <td mat-cell *matCellDef=\"let element\">{{ element.name }}</td>\n </ng-container>\n\n <!-- Version Column -->\n <ng-container matColumnDef=\"version\">\n <th mat-header-cell *matHeaderCellDef>{{ 'yuv.shell.settings.dependency-info.version' | translate }}</th>\n <td mat-cell *matCellDef=\"let element\">{{ element.version }}</td>\n </ng-container>\n\n <!-- License Column -->\n <ng-container matColumnDef=\"license\">\n <th mat-header-cell *matHeaderCellDef>{{ 'yuv.shell.settings.dependency-info.license' | translate }}</th>\n <td mat-cell *matCellDef=\"let element\">\n @if (element.link) {\n <a href=\"{{ element.link }}\" target=\"_blank\">{{ element.license }}</a>\n } @else {\n {{ element.license }}\n }\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"['name', 'version', 'license']\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['name', 'version', 'license']\"></tr>\n </table>\n </div>\n </ng-template>\n </mat-expansion-panel>\n </section>\n }\n <!-- app settings -->\n <!-- TODO: activate one feature is refined -->\n <!-- @for (c of appSettingForms$ | async; track $index) {\n <section>\n {{ c.label }}\n <form [formGroup]=\"c.form\" (ngSubmit)=\"saveAppSettings(c.appID, c.form)\">\n @for (n of c.formControls; track $index) {\n <label\n >{{ n.label }}\n\n @switch (n.type) {\n @case ('string') {\n <input type=\"text\" [formControlName]=\"n.name\" />\n }\n @case ('number') {\n <input type=\"number\" [formControlName]=\"n.name\" />\n }\n }\n </label>\n }\n <button [ngClass]=\"{ hideen: c.form.untouched }\" [disabled]=\"c.form.invalid\">Save</button>\n </form>\n </section>\n } -->\n </div>\n</main>\n"],"names":["i1","i3"],"mappings":"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"}