@yuuvis/client-framework 3.4.2 → 3.6.0
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/fesm2022/yuuvis-client-framework-datepicker.mjs +2 -2
- package/fesm2022/yuuvis-client-framework-datepicker.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework-object-details.mjs +55 -107
- package/fesm2022/yuuvis-client-framework-object-details.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework-object-preview.mjs +2 -1
- package/fesm2022/yuuvis-client-framework-object-preview.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework-renderer.mjs +286 -144
- package/fesm2022/yuuvis-client-framework-renderer.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework.mjs +172 -3
- package/fesm2022/yuuvis-client-framework.mjs.map +1 -1
- package/lib/assets/i18n/de.json +7 -0
- package/lib/assets/i18n/en.json +12 -5
- package/package.json +6 -6
- package/renderer/README.md +212 -2
- package/types/yuuvis-client-framework-object-details.d.ts +3 -19
- package/types/yuuvis-client-framework-renderer.d.ts +71 -5
- package/types/yuuvis-client-framework.d.ts +121 -2
|
@@ -1,13 +1,163 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import {
|
|
3
|
-
import { SystemService, LocaleDatePipe, FileSizePipe, IdmService, AppCacheService,
|
|
2
|
+
import { input, Component, inject, computed, ChangeDetectionStrategy, signal, Injectable, effect, ViewContainerRef, Directive } from '@angular/core';
|
|
3
|
+
import { TranslateService, LocalizationService, SystemService, LocaleDatePipe, FileSizePipe, IdmService, AppCacheService, TranslatePipe, InternalFieldType, ContentStreamField } from '@yuuvis/client-core';
|
|
4
4
|
import { MatIcon, MatIconRegistry } from '@angular/material/icon';
|
|
5
5
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
6
6
|
import { ObjectTypeIconComponent } from '@yuuvis/client-framework/icons';
|
|
7
7
|
import { rxResource } from '@angular/core/rxjs-interop';
|
|
8
|
-
import {
|
|
8
|
+
import { of, switchMap, map, catchError, forkJoin } from 'rxjs';
|
|
9
9
|
import { DecimalPipe, DatePipe } from '@angular/common';
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Abstract class to be extended by audit-entry renderers. The renderer controls the
|
|
13
|
+
* inner content of an audit timeline entry; the surrounding framing (date column,
|
|
14
|
+
* timeline line, version badge, creator) stays with the host component.
|
|
15
|
+
*/
|
|
16
|
+
class AbstractAuditRendererComponent {
|
|
17
|
+
constructor() {
|
|
18
|
+
this.auditEntry = input.required(...(ngDevMode ? [{ debugName: "auditEntry" }] : /* istanbul ignore next */ []));
|
|
19
|
+
}
|
|
20
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AbstractAuditRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
21
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.12", type: AbstractAuditRendererComponent, isStandalone: true, selector: "yuv-abstract-audit-renderer", inputs: { auditEntry: { classPropertyName: "auditEntry", publicName: "auditEntry", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: '', isInline: true }); }
|
|
22
|
+
}
|
|
23
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AbstractAuditRendererComponent, decorators: [{
|
|
24
|
+
type: Component,
|
|
25
|
+
args: [{
|
|
26
|
+
selector: 'yuv-abstract-audit-renderer',
|
|
27
|
+
template: ''
|
|
28
|
+
}]
|
|
29
|
+
}], propDecorators: { auditEntry: [{ type: i0.Input, args: [{ isSignal: true, alias: "auditEntry", required: true }] }] } });
|
|
30
|
+
|
|
31
|
+
class DefaultAuditRendererComponent extends AbstractAuditRendererComponent {
|
|
32
|
+
constructor() {
|
|
33
|
+
super(...arguments);
|
|
34
|
+
this.#translate = inject(TranslateService);
|
|
35
|
+
this.#localization = inject(LocalizationService);
|
|
36
|
+
this.#auditLabels = {
|
|
37
|
+
a100: this.#translate.instant('yuv.audit.label.create.metadata'),
|
|
38
|
+
a101: this.#translate.instant('yuv.audit.label.create.metadata.withcontent'),
|
|
39
|
+
a110: this.#translate.instant('yuv.audit.label.create.tag'),
|
|
40
|
+
a200: this.#translate.instant('yuv.audit.label.delete'),
|
|
41
|
+
a201: this.#translate.instant('yuv.audit.label.delete.content'),
|
|
42
|
+
a202: this.#translate.instant('yuv.audit.label.delete.marked'),
|
|
43
|
+
a210: this.#translate.instant('yuv.audit.label.delete.tag'),
|
|
44
|
+
a220: this.#translate.instant('yuv.audit.label.delete.version'),
|
|
45
|
+
a300: this.#translate.instant('yuv.audit.label.update.metadata'),
|
|
46
|
+
a301: this.#translate.instant('yuv.audit.label.update.content'),
|
|
47
|
+
a302: this.#translate.instant('yuv.audit.label.update.metadata.withcontent'),
|
|
48
|
+
a303: this.#translate.instant('yuv.audit.label.update.move.content'),
|
|
49
|
+
a310: this.#translate.instant('yuv.audit.label.update.tag'),
|
|
50
|
+
a325: this.#translate.instant('yuv.audit.label.update.restore'),
|
|
51
|
+
a340: this.#translate.instant('yuv.audit.label.update.move'),
|
|
52
|
+
a400: this.#translate.instant('yuv.audit.label.get.content'),
|
|
53
|
+
a401: this.#translate.instant('yuv.audit.label.get.metadata'),
|
|
54
|
+
a402: this.#translate.instant('yuv.audit.label.get.rendition.text'),
|
|
55
|
+
a403: this.#translate.instant('yuv.audit.label.get.rendition.pdf'),
|
|
56
|
+
a404: this.#translate.instant('yuv.audit.label.get.rendition.thumbnail'),
|
|
57
|
+
a10000: this.#translate.instant('yuv.audit.label.get.custom')
|
|
58
|
+
};
|
|
59
|
+
this.resolved = computed(() => this.#resolve(this.auditEntry()), ...(ngDevMode ? [{ debugName: "resolved" }] : /* istanbul ignore next */ []));
|
|
60
|
+
}
|
|
61
|
+
#translate;
|
|
62
|
+
#localization;
|
|
63
|
+
#auditLabels;
|
|
64
|
+
#resolve(entry) {
|
|
65
|
+
let label = this.#auditLabels[`a${entry.action}`];
|
|
66
|
+
let more;
|
|
67
|
+
if ([110, 210, 310].includes(entry.action)) {
|
|
68
|
+
const params = this.#getParams(entry);
|
|
69
|
+
if (params.length) {
|
|
70
|
+
const localizedLabel = `${params[0]}:${params[1]}`;
|
|
71
|
+
more = `${this.#localization.getLocalizedLabel(params[0]) ?? params[0]}: ${this.#localization.getLocalizedLabel(localizedLabel) ?? localizedLabel}`;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else if (entry.action === 325) {
|
|
75
|
+
const params = this.#getParams(entry);
|
|
76
|
+
more = this.#translate.instant('yuv.audit.label.update.restore.more', {
|
|
77
|
+
version: params[0] || '[?]'
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
else if (entry.action === 10000) {
|
|
81
|
+
label = this.#localization.getLocalizedLabel(`audit:custom:${entry.subaction}`) || `${entry.subaction}`;
|
|
82
|
+
}
|
|
83
|
+
return { label, more };
|
|
84
|
+
}
|
|
85
|
+
#getParams(entry) {
|
|
86
|
+
const m = entry.detail.match(/\[(.*?)\]/);
|
|
87
|
+
return m?.[1]?.split(',').map((i) => i.trim()) ?? [];
|
|
88
|
+
}
|
|
89
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: DefaultAuditRendererComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
90
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: DefaultAuditRendererComponent, isStandalone: true, selector: "yuv-default-audit-renderer", usesInheritance: true, ngImport: i0, template: `
|
|
91
|
+
@let r = resolved();
|
|
92
|
+
<span class="title">{{ r.label }}</span>
|
|
93
|
+
@if (r.more) {
|
|
94
|
+
<div class="more meta">{{ r.more }}</div>
|
|
95
|
+
}
|
|
96
|
+
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
97
|
+
}
|
|
98
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: DefaultAuditRendererComponent, decorators: [{
|
|
99
|
+
type: Component,
|
|
100
|
+
args: [{
|
|
101
|
+
selector: 'yuv-default-audit-renderer',
|
|
102
|
+
standalone: true,
|
|
103
|
+
template: `
|
|
104
|
+
@let r = resolved();
|
|
105
|
+
<span class="title">{{ r.label }}</span>
|
|
106
|
+
@if (r.more) {
|
|
107
|
+
<div class="more meta">{{ r.more }}</div>
|
|
108
|
+
}
|
|
109
|
+
`,
|
|
110
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
111
|
+
}]
|
|
112
|
+
}] });
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Service for managing audit-entry renderers. Renderers are components that render the
|
|
116
|
+
* inner content of an audit entry in the timeline view of `ObjectAuditComponent`.
|
|
117
|
+
*
|
|
118
|
+
* Register a renderer for an `action` to override the default rendering of all audit
|
|
119
|
+
* entries with that action, or for an `action` + `subaction` pair to override a specific
|
|
120
|
+
* variant. Lookup prefers the subaction-specific renderer over the action-only renderer;
|
|
121
|
+
* if neither is registered, `DefaultAuditRendererComponent` is used.
|
|
122
|
+
*/
|
|
123
|
+
class AuditRendererService {
|
|
124
|
+
#renderers = signal({}, ...(ngDevMode ? [{ debugName: "#renderers" }] : /* istanbul ignore next */ []));
|
|
125
|
+
/**
|
|
126
|
+
* Register a renderer for a specific audit `action`. Pass `subaction` to scope the
|
|
127
|
+
* renderer to a particular (action, subaction) pair.
|
|
128
|
+
*/
|
|
129
|
+
registerAuditRenderer(cmp, action, subaction) {
|
|
130
|
+
this.#renderers.update((curr) => ({ ...curr, [this.#getKey(action, subaction)]: cmp }));
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Resolve the renderer for an audit entry. Tries `(action, subaction)` first, falls
|
|
134
|
+
* back to `(action)`, then to `DefaultAuditRendererComponent`.
|
|
135
|
+
*/
|
|
136
|
+
getAuditRenderer(action, subaction) {
|
|
137
|
+
const r = this.#renderers();
|
|
138
|
+
if (subaction !== undefined) {
|
|
139
|
+
const scoped = r[this.#getKey(action, subaction)];
|
|
140
|
+
if (scoped)
|
|
141
|
+
return scoped;
|
|
142
|
+
}
|
|
143
|
+
return r[this.#getKey(action)] || DefaultAuditRendererComponent;
|
|
144
|
+
}
|
|
145
|
+
#getKey(action, subaction) {
|
|
146
|
+
const k = [String(action)];
|
|
147
|
+
if (subaction !== undefined)
|
|
148
|
+
k.push(String(subaction));
|
|
149
|
+
return k.join('-');
|
|
150
|
+
}
|
|
151
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AuditRendererService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
152
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AuditRendererService, providedIn: 'root' }); }
|
|
153
|
+
}
|
|
154
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AuditRendererService, decorators: [{
|
|
155
|
+
type: Injectable,
|
|
156
|
+
args: [{
|
|
157
|
+
providedIn: 'root'
|
|
158
|
+
}]
|
|
159
|
+
}] });
|
|
160
|
+
|
|
11
161
|
/**
|
|
12
162
|
* Abstract class to be extended by property renderers
|
|
13
163
|
*/
|
|
@@ -92,8 +242,9 @@ class IconRendererComponent extends AbstractRendererComponent {
|
|
|
92
242
|
this.customId = crypto.randomUUID();
|
|
93
243
|
this.#registerIconsEffect = effect(async () => {
|
|
94
244
|
const meta = this.meta();
|
|
245
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
95
246
|
this.propertyName() === 'custom' &&
|
|
96
|
-
!
|
|
247
|
+
!meta?.['isFontIcon'] &&
|
|
97
248
|
this.#iconRegistry.addSvgIconLiteral(this.customId, this.#sanitizer.bypassSecurityTrustHtml(this.value()));
|
|
98
249
|
}, ...(ngDevMode ? [{ debugName: "#registerIconsEffect" }] : /* istanbul ignore next */ []));
|
|
99
250
|
}
|
|
@@ -101,31 +252,11 @@ class IconRendererComponent extends AbstractRendererComponent {
|
|
|
101
252
|
#sanitizer;
|
|
102
253
|
#registerIconsEffect;
|
|
103
254
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: IconRendererComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
104
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: IconRendererComponent, isStandalone: true, selector: "yuv-icon-renderer", usesInheritance: true, ngImport: i0, template:
|
|
105
|
-
@if (propertyName() !== 'custom') {
|
|
106
|
-
<yuv-object-type-icon [objectTypeId]="icon || ''"></yuv-object-type-icon>
|
|
107
|
-
} @else if (icon !== null) {
|
|
108
|
-
@let metaData = meta();
|
|
109
|
-
@if (metaData && metaData['isFontIcon']) {
|
|
110
|
-
<mat-icon>{{ icon }}</mat-icon>
|
|
111
|
-
} @else {
|
|
112
|
-
<mat-icon [svgIcon]="customId"></mat-icon>
|
|
113
|
-
}
|
|
114
|
-
}`, isInline: true, styles: [":host{display:flex;align-items:center;justify-content:center;padding:var(--tile-slot-padding)}:host yuv-icon,:host yuv-object-type-icon{--icon-size: var(--icon-renderer-icon-size);width:var(--icon-size);height:var(--icon-size)}\n"], dependencies: [{ kind: "component", type: ObjectTypeIconComponent, selector: "yuv-object-type-icon", inputs: ["objectTypeId"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] }); }
|
|
255
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: IconRendererComponent, isStandalone: true, selector: "yuv-icon-renderer", usesInheritance: true, ngImport: i0, template: "@let icon = value();\n@if (propertyName() !== 'custom') {\n <yuv-object-type-icon [objectTypeId]=\"icon || ''\"></yuv-object-type-icon>\n} @else if (icon !== null) {\n @let metaData = meta();\n @if (metaData && metaData['isFontIcon']) {\n <mat-icon>{{ icon }}</mat-icon>\n } @else {\n <mat-icon [svgIcon]=\"customId\"></mat-icon>\n }\n}\n", styles: [":host{display:flex;align-items:center;justify-content:center;padding:var(--tile-slot-padding)}:host yuv-icon,:host yuv-object-type-icon{--icon-size: var(--icon-renderer-icon-size);width:var(--icon-size);height:var(--icon-size)}\n"], dependencies: [{ kind: "component", type: ObjectTypeIconComponent, selector: "yuv-object-type-icon", inputs: ["objectTypeId"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] }); }
|
|
115
256
|
}
|
|
116
257
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: IconRendererComponent, decorators: [{
|
|
117
258
|
type: Component,
|
|
118
|
-
args: [{ selector: 'yuv-icon-renderer', imports: [ObjectTypeIconComponent, MatIcon], template:
|
|
119
|
-
@if (propertyName() !== 'custom') {
|
|
120
|
-
<yuv-object-type-icon [objectTypeId]="icon || ''"></yuv-object-type-icon>
|
|
121
|
-
} @else if (icon !== null) {
|
|
122
|
-
@let metaData = meta();
|
|
123
|
-
@if (metaData && metaData['isFontIcon']) {
|
|
124
|
-
<mat-icon>{{ icon }}</mat-icon>
|
|
125
|
-
} @else {
|
|
126
|
-
<mat-icon [svgIcon]="customId"></mat-icon>
|
|
127
|
-
}
|
|
128
|
-
}`, styles: [":host{display:flex;align-items:center;justify-content:center;padding:var(--tile-slot-padding)}:host yuv-icon,:host yuv-object-type-icon{--icon-size: var(--icon-renderer-icon-size);width:var(--icon-size);height:var(--icon-size)}\n"] }]
|
|
259
|
+
args: [{ selector: 'yuv-icon-renderer', imports: [ObjectTypeIconComponent, MatIcon], template: "@let icon = value();\n@if (propertyName() !== 'custom') {\n <yuv-object-type-icon [objectTypeId]=\"icon || ''\"></yuv-object-type-icon>\n} @else if (icon !== null) {\n @let metaData = meta();\n @if (metaData && metaData['isFontIcon']) {\n <mat-icon>{{ icon }}</mat-icon>\n } @else {\n <mat-icon [svgIcon]=\"customId\"></mat-icon>\n }\n}\n", styles: [":host{display:flex;align-items:center;justify-content:center;padding:var(--tile-slot-padding)}:host yuv-icon,:host yuv-object-type-icon{--icon-size: var(--icon-renderer-icon-size);width:var(--icon-size);height:var(--icon-size)}\n"] }]
|
|
129
260
|
}] });
|
|
130
261
|
|
|
131
262
|
class IntegerRendererComponent extends AbstractRendererComponent {
|
|
@@ -144,55 +275,91 @@ class OrganizationRendererComponent extends AbstractRendererComponent {
|
|
|
144
275
|
this.#appCache = inject(AppCacheService);
|
|
145
276
|
this.#STORAGE_USER_KEY = 'yuv.core.users.storage';
|
|
146
277
|
this.#STORAGE_ROLES_KEY = 'yuv.core.roles.storage';
|
|
278
|
+
// Input may be a single id/role-name or an array of them; normalize to string[] so the resolver
|
|
279
|
+
// pipeline always works on a uniform shape.
|
|
147
280
|
this.resolvedValue = computed(() => {
|
|
148
|
-
const
|
|
149
|
-
return
|
|
281
|
+
const value = this.value();
|
|
282
|
+
return value === null ? [] : Array.isArray(value) ? value : [value];
|
|
150
283
|
}, ...(ngDevMode ? [{ debugName: "resolvedValue" }] : /* istanbul ignore next */ []));
|
|
151
284
|
this.#userRoleResolver = rxResource({
|
|
152
285
|
params: this.resolvedValue,
|
|
153
|
-
stream: ({ params }) =>
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
.getRoles()
|
|
159
|
-
.pipe(switchMap((roles) => roles.length
|
|
160
|
-
? this.#appCache.setItem(this.#STORAGE_ROLES_KEY, roles).pipe(map(() => roles))
|
|
161
|
-
: of([])))).pipe(map((roles) => params.reduce((acc, value) => {
|
|
162
|
-
const matchingRole = roles.find((r) => r.name === value);
|
|
163
|
-
matchingRole ? acc.roles.push(matchingRole.name) : acc.users.push(value);
|
|
164
|
-
return acc;
|
|
165
|
-
}, { roles: [], users: [] })))), switchMap(({ roles, users }) => this.#appCache
|
|
166
|
-
.getItem(this.#STORAGE_USER_KEY)
|
|
167
|
-
.pipe(map((cache) => cache ? { roles, users, cache: cache.filter((c) => c !== null) } : { roles, users, cache: null }))), switchMap(({ roles, users, cache }) => {
|
|
168
|
-
let missingUsers = users;
|
|
169
|
-
let filteredUsers = [];
|
|
170
|
-
if (cache) {
|
|
171
|
-
filteredUsers = cache.filter((u) => u && users.includes(u.id));
|
|
172
|
-
missingUsers = users.filter((uid) => !filteredUsers.some((u) => u.id === uid));
|
|
286
|
+
stream: ({ params }) => {
|
|
287
|
+
// Nothing to resolve — short-circuit so we don't show the loading indicator or hit the
|
|
288
|
+
// backend for an empty input.
|
|
289
|
+
if (params.length === 0) {
|
|
290
|
+
return of([]);
|
|
173
291
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
292
|
+
// Step 1 — load the role catalog (cached) and use it to partition the input into role
|
|
293
|
+
// names vs. user IDs. Roles are a closed set; anything that doesn't match is treated as
|
|
294
|
+
// a user ID and resolved in step 2.
|
|
295
|
+
// TODO: Move get Roles to App init or somewhere else to avoid multiple calls
|
|
296
|
+
return this.#appCache.getItem(this.#STORAGE_ROLES_KEY).pipe(switchMap((cachedRoles) => (cachedRoles
|
|
297
|
+
? of(cachedRoles)
|
|
298
|
+
: this.#idmService.getRoles().pipe(
|
|
299
|
+
// Only persist the role list when the backend actually returned something —
|
|
300
|
+
// caching an empty array would mask later successful fetches.
|
|
301
|
+
switchMap((roles) => roles.length ? this.#appCache.setItem(this.#STORAGE_ROLES_KEY, roles).pipe(map(() => roles)) : of([])))).pipe(map((roles) => params.reduce((acc, value) => {
|
|
302
|
+
const matchingRole = roles.find((role) => role.name === value);
|
|
303
|
+
// Role-name match → roles bucket; everything else is assumed to be a user ID.
|
|
304
|
+
if (matchingRole) {
|
|
305
|
+
acc.roles.push(matchingRole.name);
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
acc.users.push(value);
|
|
309
|
+
}
|
|
310
|
+
return acc;
|
|
311
|
+
}, { roles: [], users: [] })))),
|
|
312
|
+
// Step 2a — pull the persisted user cache. Defensive filter against null entries that
|
|
313
|
+
// may linger from earlier buggy writes (see commit 2f3ff694f).
|
|
314
|
+
switchMap(({ roles, users }) => this.#appCache
|
|
315
|
+
.getItem(this.#STORAGE_USER_KEY)
|
|
316
|
+
.pipe(map((cache) => cache ? { roles, users, cache: cache.filter((entry) => entry !== null) } : { roles, users, cache: null }))),
|
|
317
|
+
// Step 2b — resolve users: serve from cache where possible, fetch the rest from IDM.
|
|
318
|
+
switchMap(({ roles, users, cache }) => {
|
|
319
|
+
let missingUsers = users;
|
|
320
|
+
let filteredUsers = [];
|
|
321
|
+
if (cache) {
|
|
322
|
+
filteredUsers = cache.filter((entry) => entry && users.includes(entry.id));
|
|
323
|
+
missingUsers = users.filter((uid) => !filteredUsers.some((user) => user.id === uid));
|
|
324
|
+
}
|
|
325
|
+
// Pair every request with its uid so we can tell which IDs came back unresolved.
|
|
326
|
+
// catchError keeps a single failing lookup from killing the whole forkJoin.
|
|
327
|
+
const userRequests = missingUsers.map((uid) => this.#idmService.getUserById(uid).pipe(catchError(() => of(null)), map((user) => ({ uid, user }))));
|
|
328
|
+
if (userRequests.length > 0) {
|
|
329
|
+
return forkJoin(userRequests).pipe(switchMap((results) => {
|
|
330
|
+
// Resolved users are real YuvUsers — safe to cache and render.
|
|
331
|
+
// Unresolved IDs render as a synthetic { id, title: id } so the user still
|
|
332
|
+
// sees the raw ID, but they are NOT written to the cache (a 404 today might
|
|
333
|
+
// resolve tomorrow, and caching it would block that).
|
|
334
|
+
const resolved = results.filter((res) => res.user != null).map((res) => res.user);
|
|
335
|
+
const unresolved = results
|
|
336
|
+
.filter((res) => res.user == null)
|
|
337
|
+
.map((res) => ({ id: res.uid, title: res.uid }));
|
|
338
|
+
return this.#appCache
|
|
339
|
+
.setItem(this.#STORAGE_USER_KEY, [...(cache || []), ...resolved, ...filteredUsers])
|
|
340
|
+
.pipe(map(() => [...resolved, ...unresolved]));
|
|
341
|
+
}), map((users) => ({ roles, users: [...users, ...filteredUsers] })));
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
// Every requested user was already in the cache — no network needed.
|
|
345
|
+
return of({ roles, users: [...filteredUsers] });
|
|
346
|
+
}
|
|
347
|
+
}),
|
|
348
|
+
// Step 3 — project to the flat render-model the template iterates over. data-type
|
|
349
|
+
// drives the chip styling (user vs role).
|
|
350
|
+
map(({ roles, users }) => {
|
|
351
|
+
const userNodes = users.map((user) => ({
|
|
352
|
+
type: 'user',
|
|
353
|
+
label: user.title || user.displayName
|
|
354
|
+
}));
|
|
355
|
+
const roleNodes = roles.map((role) => ({
|
|
356
|
+
type: 'role',
|
|
357
|
+
label: role
|
|
358
|
+
}));
|
|
359
|
+
return [...userNodes, ...roleNodes];
|
|
193
360
|
}));
|
|
194
|
-
|
|
195
|
-
|
|
361
|
+
},
|
|
362
|
+
defaultValue: []
|
|
196
363
|
});
|
|
197
364
|
this.userAndRole = this.#userRoleResolver.value;
|
|
198
365
|
this.userAndRoleLoading = this.#userRoleResolver.isLoading;
|
|
@@ -203,27 +370,11 @@ class OrganizationRendererComponent extends AbstractRendererComponent {
|
|
|
203
370
|
#STORAGE_ROLES_KEY;
|
|
204
371
|
#userRoleResolver;
|
|
205
372
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: OrganizationRendererComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
206
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: OrganizationRendererComponent, isStandalone: true, selector: "yuv-organization-renderer", usesInheritance: true, ngImport: i0, template:
|
|
207
|
-
@if (userAndRoleLoading()) {
|
|
208
|
-
<span class="loading"><i>.</i><i>.</i><i>.</i></span>
|
|
209
|
-
} @else {
|
|
210
|
-
@for (node of userAndRole(); track $index) {
|
|
211
|
-
<span class="node" [attr.data-type]="node.type">{{ node.label }}</span>
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
`, isInline: true, styles: [":host{padding:var(--tile-slot-padding);display:var(--yuv-renderer-display, flex);gap:var(--ymt-spacing-xs);align-items:center;@keyframes pulse{0%,80%,to{opacity:.3;transform:scale(1)}40%{opacity:1;transform:scale(1.2)}}}:host .node{display:flex;flex-flow:row nowrap;align-items:center;border:1px solid var(--ymt-outline);border-radius:var(--ymt-corner-xs);padding:0 var(--ymt-spacing-xs);font:var(--ymt-font-body-subtle);white-space:nowrap}:host .loading i{animation:pulse 1.4s ease-in-out infinite both}:host .loading i:nth-child(1){animation-delay:-.32s}:host .loading i:nth-child(2){animation-delay:-.16s}:host .loading i:nth-child(3){animation-delay:0s}\n"] }); }
|
|
373
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: OrganizationRendererComponent, isStandalone: true, selector: "yuv-organization-renderer", usesInheritance: true, ngImport: i0, template: "@if (userAndRoleLoading()) {\n <span class=\"loading\"><i>.</i><i>.</i><i>.</i></span>\n} @else {\n @for (node of userAndRole(); track $index) {\n <span class=\"node\" [attr.data-type]=\"node.type\">{{ node.label }}</span>\n }\n}\n", styles: [":host{padding:var(--tile-slot-padding);display:var(--yuv-renderer-display, flex);gap:var(--ymt-spacing-xs);align-items:center}:host .node{display:flex;flex-flow:row nowrap;align-items:center;border:1px solid var(--ymt-outline);border-radius:var(--ymt-corner-xs);padding:0 var(--ymt-spacing-xs);font:var(--ymt-font-body-subtle);white-space:nowrap}:host .loading i{animation:pulse 1.4s ease-in-out infinite both}:host .loading i:nth-child(1){animation-delay:-.32s}:host .loading i:nth-child(2){animation-delay:-.16s}:host .loading i:nth-child(3){animation-delay:0s}@keyframes pulse{0%,80%,to{opacity:.3;transform:scale(1)}40%{opacity:1;transform:scale(1.2)}}\n"] }); }
|
|
215
374
|
}
|
|
216
375
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: OrganizationRendererComponent, decorators: [{
|
|
217
376
|
type: Component,
|
|
218
|
-
args: [{ selector: 'yuv-organization-renderer', template:
|
|
219
|
-
@if (userAndRoleLoading()) {
|
|
220
|
-
<span class="loading"><i>.</i><i>.</i><i>.</i></span>
|
|
221
|
-
} @else {
|
|
222
|
-
@for (node of userAndRole(); track $index) {
|
|
223
|
-
<span class="node" [attr.data-type]="node.type">{{ node.label }}</span>
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
`, styles: [":host{padding:var(--tile-slot-padding);display:var(--yuv-renderer-display, flex);gap:var(--ymt-spacing-xs);align-items:center;@keyframes pulse{0%,80%,to{opacity:.3;transform:scale(1)}40%{opacity:1;transform:scale(1.2)}}}:host .node{display:flex;flex-flow:row nowrap;align-items:center;border:1px solid var(--ymt-outline);border-radius:var(--ymt-corner-xs);padding:0 var(--ymt-spacing-xs);font:var(--ymt-font-body-subtle);white-space:nowrap}:host .loading i{animation:pulse 1.4s ease-in-out infinite both}:host .loading i:nth-child(1){animation-delay:-.32s}:host .loading i:nth-child(2){animation-delay:-.16s}:host .loading i:nth-child(3){animation-delay:0s}\n"] }]
|
|
377
|
+
args: [{ selector: 'yuv-organization-renderer', template: "@if (userAndRoleLoading()) {\n <span class=\"loading\"><i>.</i><i>.</i><i>.</i></span>\n} @else {\n @for (node of userAndRole(); track $index) {\n <span class=\"node\" [attr.data-type]=\"node.type\">{{ node.label }}</span>\n }\n}\n", styles: [":host{padding:var(--tile-slot-padding);display:var(--yuv-renderer-display, flex);gap:var(--ymt-spacing-xs);align-items:center}:host .node{display:flex;flex-flow:row nowrap;align-items:center;border:1px solid var(--ymt-outline);border-radius:var(--ymt-corner-xs);padding:0 var(--ymt-spacing-xs);font:var(--ymt-font-body-subtle);white-space:nowrap}:host .loading i{animation:pulse 1.4s ease-in-out infinite both}:host .loading i:nth-child(1){animation-delay:-.32s}:host .loading i:nth-child(2){animation-delay:-.16s}:host .loading i:nth-child(3){animation-delay:0s}@keyframes pulse{0%,80%,to{opacity:.3;transform:scale(1)}40%{opacity:1;transform:scale(1.2)}}\n"] }]
|
|
227
378
|
}] });
|
|
228
379
|
|
|
229
380
|
class StringRendererComponent extends AbstractRendererComponent {
|
|
@@ -243,7 +394,7 @@ class TableRendererComponent extends AbstractRendererComponent {
|
|
|
243
394
|
this.#decimalPipe = inject(DecimalPipe);
|
|
244
395
|
this.#datePipe = inject(DatePipe);
|
|
245
396
|
this.tableHeaders = computed(() => [
|
|
246
|
-
...new Set((this.value() || []).flat().map((item
|
|
397
|
+
...new Set((this.value() || []).flat().map((item) => ({
|
|
247
398
|
id: `header-${crypto.randomUUID()}`,
|
|
248
399
|
key: item.propertyName,
|
|
249
400
|
label: this.#system.getLocalizedLabel(`${item.propertyName}`) || item.propertyName
|
|
@@ -251,7 +402,7 @@ class TableRendererComponent extends AbstractRendererComponent {
|
|
|
251
402
|
], ...(ngDevMode ? [{ debugName: "tableHeaders" }] : /* istanbul ignore next */ []));
|
|
252
403
|
this.tableData = computed(() => {
|
|
253
404
|
const data = this.value() || [];
|
|
254
|
-
return (data.length > 10 ? data.slice(0, 10) : data).map((row, rowIndex) => row.map((item
|
|
405
|
+
return (data.length > 10 ? data.slice(0, 10) : data).map((row, rowIndex) => row.map((item) => ({
|
|
255
406
|
id: `row-${rowIndex}-cell-${crypto.randomUUID()}`,
|
|
256
407
|
...item,
|
|
257
408
|
value: this.#cellValue(item)
|
|
@@ -265,6 +416,10 @@ class TableRendererComponent extends AbstractRendererComponent {
|
|
|
265
416
|
#system;
|
|
266
417
|
#decimalPipe;
|
|
267
418
|
#datePipe;
|
|
419
|
+
getCellValue(row, key) {
|
|
420
|
+
const item = (row || []).find((i) => i.propertyName === key);
|
|
421
|
+
return item ? item.value : '';
|
|
422
|
+
}
|
|
268
423
|
#cellValue(element) {
|
|
269
424
|
switch (element.propertyType) {
|
|
270
425
|
case 'datetime':
|
|
@@ -277,64 +432,12 @@ class TableRendererComponent extends AbstractRendererComponent {
|
|
|
277
432
|
return element.value;
|
|
278
433
|
}
|
|
279
434
|
}
|
|
280
|
-
getCellValue(row, key) {
|
|
281
|
-
const item = (row || []).find((i) => i.propertyName === key);
|
|
282
|
-
return item ? item.value : '';
|
|
283
|
-
}
|
|
284
435
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TableRendererComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
285
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: TableRendererComponent, isStandalone: true, selector: "yuv-table-renderer", providers: [DecimalPipe, DatePipe], usesInheritance: true, ngImport: i0, template:
|
|
286
|
-
<div class="table-container">
|
|
287
|
-
<table>
|
|
288
|
-
<thead>
|
|
289
|
-
<tr>
|
|
290
|
-
@for (header of tableHeaders(); track header.id) {
|
|
291
|
-
<th>{{ header.label }}</th>
|
|
292
|
-
}
|
|
293
|
-
</tr>
|
|
294
|
-
</thead>
|
|
295
|
-
<tbody>
|
|
296
|
-
@for (row of tableData(); track $index) {
|
|
297
|
-
<tr>
|
|
298
|
-
@for (header of tableHeaders(); track header.id) {
|
|
299
|
-
<td>{{ getCellValue(row, header.key) }}</td>
|
|
300
|
-
}
|
|
301
|
-
</tr>
|
|
302
|
-
}
|
|
303
|
-
</tbody>
|
|
304
|
-
</table>
|
|
305
|
-
@if (reducedData()) {
|
|
306
|
-
<p>{{ 'yuv.table.renderer.moreEntries' | translate: { count: value()?.length } }}</p>
|
|
307
|
-
}
|
|
308
|
-
</div>
|
|
309
|
-
`, isInline: true, styles: [":host{display:flex;padding:var(--tile-slot-padding);width:100%}.table-container{width:100%;overflow-x:auto;max-width:100%}table{width:100%;border-collapse:collapse;min-width:400px}th,td{padding:8px;text-align:left;border-bottom:1px solid var(--ymt-outline-variant);word-break:normal}th{background-color:var(--object-summary-section-background, var(--ymt-surface));font-weight:700}tr:hover{background-color:var(--ymt-hover-background)}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
436
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: TableRendererComponent, isStandalone: true, selector: "yuv-table-renderer", providers: [DecimalPipe, DatePipe], usesInheritance: true, ngImport: i0, template: "<div class=\"table-container\">\n <table>\n <thead>\n <tr>\n @for (header of tableHeaders(); track header.id) {\n <th>{{ header.label }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of tableData(); track $index) {\n <tr>\n @for (header of tableHeaders(); track header.id) {\n <td>{{ getCellValue(row, header.key) }}</td>\n }\n </tr>\n }\n </tbody>\n </table>\n @if (reducedData()) {\n <p>{{ 'yuv.table.renderer.moreEntries' | translate: { count: value()?.length } }}</p>\n }\n</div>\n", styles: [":host{display:flex;padding:var(--tile-slot-padding);width:100%}.table-container{width:100%;overflow-x:auto;max-width:100%}table{width:100%;border-collapse:collapse;min-width:400px}th,td{padding:8px;text-align:left;border-bottom:1px solid var(--ymt-outline-variant);word-break:normal}th{background-color:var(--object-summary-section-background, var(--ymt-surface));font-weight:700}tr:hover{background-color:var(--ymt-hover-background)}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
310
437
|
}
|
|
311
438
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TableRendererComponent, decorators: [{
|
|
312
439
|
type: Component,
|
|
313
|
-
args: [{ selector: 'yuv-table-renderer', standalone: true, imports: [TranslatePipe], template:
|
|
314
|
-
<div class="table-container">
|
|
315
|
-
<table>
|
|
316
|
-
<thead>
|
|
317
|
-
<tr>
|
|
318
|
-
@for (header of tableHeaders(); track header.id) {
|
|
319
|
-
<th>{{ header.label }}</th>
|
|
320
|
-
}
|
|
321
|
-
</tr>
|
|
322
|
-
</thead>
|
|
323
|
-
<tbody>
|
|
324
|
-
@for (row of tableData(); track $index) {
|
|
325
|
-
<tr>
|
|
326
|
-
@for (header of tableHeaders(); track header.id) {
|
|
327
|
-
<td>{{ getCellValue(row, header.key) }}</td>
|
|
328
|
-
}
|
|
329
|
-
</tr>
|
|
330
|
-
}
|
|
331
|
-
</tbody>
|
|
332
|
-
</table>
|
|
333
|
-
@if (reducedData()) {
|
|
334
|
-
<p>{{ 'yuv.table.renderer.moreEntries' | translate: { count: value()?.length } }}</p>
|
|
335
|
-
}
|
|
336
|
-
</div>
|
|
337
|
-
`, providers: [DecimalPipe, DatePipe], styles: [":host{display:flex;padding:var(--tile-slot-padding);width:100%}.table-container{width:100%;overflow-x:auto;max-width:100%}table{width:100%;border-collapse:collapse;min-width:400px}th,td{padding:8px;text-align:left;border-bottom:1px solid var(--ymt-outline-variant);word-break:normal}th{background-color:var(--object-summary-section-background, var(--ymt-surface));font-weight:700}tr:hover{background-color:var(--ymt-hover-background)}\n"] }]
|
|
440
|
+
args: [{ selector: 'yuv-table-renderer', standalone: true, imports: [TranslatePipe], providers: [DecimalPipe, DatePipe], template: "<div class=\"table-container\">\n <table>\n <thead>\n <tr>\n @for (header of tableHeaders(); track header.id) {\n <th>{{ header.label }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of tableData(); track $index) {\n <tr>\n @for (header of tableHeaders(); track header.id) {\n <td>{{ getCellValue(row, header.key) }}</td>\n }\n </tr>\n }\n </tbody>\n </table>\n @if (reducedData()) {\n <p>{{ 'yuv.table.renderer.moreEntries' | translate: { count: value()?.length } }}</p>\n }\n</div>\n", styles: [":host{display:flex;padding:var(--tile-slot-padding);width:100%}.table-container{width:100%;overflow-x:auto;max-width:100%}table{width:100%;border-collapse:collapse;min-width:400px}th,td{padding:8px;text-align:left;border-bottom:1px solid var(--ymt-outline-variant);word-break:normal}th{background-color:var(--object-summary-section-background, var(--ymt-surface));font-weight:700}tr:hover{background-color:var(--ymt-hover-background)}\n"] }]
|
|
338
441
|
}] });
|
|
339
442
|
|
|
340
443
|
class UnknownRendererComponent extends AbstractRendererComponent {
|
|
@@ -422,6 +525,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
422
525
|
}]
|
|
423
526
|
}], ctorParameters: () => [] });
|
|
424
527
|
|
|
528
|
+
/**
|
|
529
|
+
* Attribute directive that renders an `AuditEntry` using the component registered with
|
|
530
|
+
* `AuditRendererService` for the entry's `action` (and optionally `subaction`). Falls
|
|
531
|
+
* back to `DefaultAuditRendererComponent` when no override is registered.
|
|
532
|
+
*/
|
|
533
|
+
class AuditRendererDirective {
|
|
534
|
+
constructor() {
|
|
535
|
+
this.#service = inject(AuditRendererService);
|
|
536
|
+
this.#containerRef = inject(ViewContainerRef);
|
|
537
|
+
this.yuvAuditRenderer = input.required(...(ngDevMode ? [{ debugName: "yuvAuditRenderer" }] : /* istanbul ignore next */ []));
|
|
538
|
+
this.#renderEffect = effect(() => {
|
|
539
|
+
const entry = this.yuvAuditRenderer();
|
|
540
|
+
if (this.#alreadyRendered(entry))
|
|
541
|
+
return;
|
|
542
|
+
this.#current = entry;
|
|
543
|
+
this.#containerRef.clear();
|
|
544
|
+
const cmp = this.#service.getAuditRenderer(entry.action, entry.subaction);
|
|
545
|
+
this.component = this.#containerRef.createComponent(cmp);
|
|
546
|
+
this.component.setInput('auditEntry', entry);
|
|
547
|
+
}, ...(ngDevMode ? [{ debugName: "#renderEffect" }] : /* istanbul ignore next */ []));
|
|
548
|
+
}
|
|
549
|
+
#service;
|
|
550
|
+
#containerRef;
|
|
551
|
+
#current;
|
|
552
|
+
#renderEffect;
|
|
553
|
+
#alreadyRendered(entry) {
|
|
554
|
+
return !!this.#current && JSON.stringify(this.#current) === JSON.stringify(entry);
|
|
555
|
+
}
|
|
556
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AuditRendererDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
557
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.12", type: AuditRendererDirective, isStandalone: true, selector: "[yuvAuditRenderer]", inputs: { yuvAuditRenderer: { classPropertyName: "yuvAuditRenderer", publicName: "yuvAuditRenderer", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
|
|
558
|
+
}
|
|
559
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AuditRendererDirective, decorators: [{
|
|
560
|
+
type: Directive,
|
|
561
|
+
args: [{
|
|
562
|
+
selector: '[yuvAuditRenderer]',
|
|
563
|
+
standalone: true
|
|
564
|
+
}]
|
|
565
|
+
}], propDecorators: { yuvAuditRenderer: [{ type: i0.Input, args: [{ isSignal: true, alias: "yuvAuditRenderer", required: true }] }] } });
|
|
566
|
+
|
|
425
567
|
/**
|
|
426
568
|
* Structural directive for rendering an obect type property
|
|
427
569
|
*/
|
|
@@ -473,5 +615,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
473
615
|
* Generated bundle index. Do not edit.
|
|
474
616
|
*/
|
|
475
617
|
|
|
476
|
-
export { AbstractRendererComponent, DateTimeRendererComponent, DecimalRendererComponent, IconRendererComponent, IntegerRendererComponent, OrganizationRendererComponent, RendererDirective, RendererService, StringRendererComponent, UnknownRendererComponent };
|
|
618
|
+
export { AbstractAuditRendererComponent, AbstractRendererComponent, AuditRendererDirective, AuditRendererService, BooleanRendererComponent, DateTimeRendererComponent, DecimalRendererComponent, DefaultAuditRendererComponent, FileSizeRendererComponent, IconRendererComponent, IntegerRendererComponent, OrganizationRendererComponent, RendererDirective, RendererService, StringRendererComponent, TableRendererComponent, UnknownRendererComponent };
|
|
477
619
|
//# sourceMappingURL=yuuvis-client-framework-renderer.mjs.map
|