@yuuvis/client-core 3.2.0 → 3.2.2
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-core.mjs +1325 -1299
- package/fesm2022/yuuvis-client-core.mjs.map +1 -1
- package/package.json +1 -1
- package/types/yuuvis-client-core.d.ts +338 -312
|
@@ -5,11 +5,12 @@ import * as i1 from '@angular/common/http';
|
|
|
5
5
|
import { HttpErrorResponse, HttpClient, HttpHeaders, HttpRequest, HttpParams, HttpResponse, HttpEventType, provideHttpClient, withInterceptors } from '@angular/common/http';
|
|
6
6
|
import * as i0 from '@angular/core';
|
|
7
7
|
import { inject, Injectable, InjectionToken, NgZone, DOCUMENT, Inject, signal, Directive, Pipe, provideEnvironmentInitializer, makeEnvironmentProviders, provideAppInitializer } from '@angular/core';
|
|
8
|
-
import { tap, finalize, shareReplay, catchError,
|
|
9
|
-
import { EMPTY, Subject, of, forkJoin, tap as tap$1, catchError as catchError$1,
|
|
8
|
+
import { tap, finalize, shareReplay, catchError, map, switchMap, first, filter, scan, delay } from 'rxjs/operators';
|
|
9
|
+
import { EMPTY, Subject, of, forkJoin, Observable, tap as tap$1, catchError as catchError$1, ReplaySubject, BehaviorSubject, map as map$1, throwError, switchMap as switchMap$1, merge, fromEvent, filter as filter$1, debounceTime, isObservable } from 'rxjs';
|
|
10
10
|
import { StorageMap } from '@ngx-pwa/local-storage';
|
|
11
11
|
import { __decorate, __param, __metadata } from 'tslib';
|
|
12
12
|
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
|
13
|
+
import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
13
14
|
import { registerLocaleData, DecimalPipe, PercentPipe, CurrencyPipe } from '@angular/common';
|
|
14
15
|
import localeAr from '@angular/common/locales/ar';
|
|
15
16
|
import localeBn from '@angular/common/locales/bn';
|
|
@@ -59,7 +60,6 @@ import localeTr from '@angular/common/locales/tr';
|
|
|
59
60
|
import localeUk from '@angular/common/locales/uk';
|
|
60
61
|
import localeVi from '@angular/common/locales/vi';
|
|
61
62
|
import localeZh from '@angular/common/locales/zh';
|
|
62
|
-
import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
63
63
|
import { DeviceDetectorService } from 'ngx-device-detector';
|
|
64
64
|
import { FormGroup, FormControl } from '@angular/forms';
|
|
65
65
|
import { MatTabGroup } from '@angular/material/tabs';
|
|
@@ -404,6 +404,28 @@ class YuvUser {
|
|
|
404
404
|
}
|
|
405
405
|
}
|
|
406
406
|
|
|
407
|
+
var AuditAction;
|
|
408
|
+
(function (AuditAction) {
|
|
409
|
+
AuditAction["CREATE_METADATA"] = "100";
|
|
410
|
+
AuditAction["CREATE_METADATA_WITH_CONTENT"] = "101";
|
|
411
|
+
AuditAction["CREATE_TAG"] = "110";
|
|
412
|
+
AuditAction["DELETE"] = "200";
|
|
413
|
+
AuditAction["DELETE_CONTENT"] = "201";
|
|
414
|
+
AuditAction["DELETE_MARKED"] = "202";
|
|
415
|
+
AuditAction["DELETE_TAG"] = "210";
|
|
416
|
+
AuditAction["UPDATE_METADATA"] = "300";
|
|
417
|
+
AuditAction["UPDATE_CONTENT"] = "301";
|
|
418
|
+
AuditAction["UPDATE_METADATA_WITH_CONTENT"] = "302";
|
|
419
|
+
AuditAction["UPDATE_MOVE_CONTENT"] = "303";
|
|
420
|
+
AuditAction["UPDATE_TAG"] = "310";
|
|
421
|
+
AuditAction["OBJECT_RESTORED_FROM_VERSION"] = "325";
|
|
422
|
+
AuditAction["GET_CONTENT"] = "400";
|
|
423
|
+
AuditAction["GET_METADATA"] = "401";
|
|
424
|
+
AuditAction["GET_RENDITION_TEXT"] = "402";
|
|
425
|
+
AuditAction["GET_RENDITION_PDF"] = "403";
|
|
426
|
+
AuditAction["GET_RENDITION_THUMBNAIL"] = "404";
|
|
427
|
+
})(AuditAction || (AuditAction = {}));
|
|
428
|
+
|
|
407
429
|
var Sort;
|
|
408
430
|
(function (Sort) {
|
|
409
431
|
Sort["ASC"] = "asc";
|
|
@@ -1262,111 +1284,115 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
1262
1284
|
args: [{ providedIn: 'root' }]
|
|
1263
1285
|
}] });
|
|
1264
1286
|
|
|
1265
|
-
var
|
|
1266
|
-
(function (
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1287
|
+
var Operator;
|
|
1288
|
+
(function (Operator) {
|
|
1289
|
+
Operator["EQUAL"] = "eq";
|
|
1290
|
+
Operator["EEQUAL"] = "eeq";
|
|
1291
|
+
Operator["IN"] = "in";
|
|
1292
|
+
Operator["GREATER_THAN"] = "gt";
|
|
1293
|
+
Operator["GREATER_OR_EQUAL"] = "gte";
|
|
1294
|
+
Operator["LESS_THAN"] = "lt";
|
|
1295
|
+
Operator["LESS_OR_EQUAL"] = "lte";
|
|
1296
|
+
Operator["INTERVAL"] = "gtlt";
|
|
1297
|
+
Operator["INTERVAL_INCLUDE_BOTH"] = "gtelte";
|
|
1298
|
+
Operator["INTERVAL_INCLUDE_TO"] = "gtlte";
|
|
1299
|
+
Operator["INTERVAL_INCLUDE_FROM"] = "gtelt";
|
|
1300
|
+
Operator["RANGE"] = "rg";
|
|
1301
|
+
Operator["LIKE"] = "like";
|
|
1302
|
+
Operator["CONTAINS"] = "contains"; // contains
|
|
1303
|
+
})(Operator || (Operator = {}));
|
|
1304
|
+
const OperatorLabel = {
|
|
1305
|
+
/** equal */
|
|
1306
|
+
EQUAL: '=',
|
|
1307
|
+
/** exact equal */
|
|
1308
|
+
EEQUAL: '==',
|
|
1309
|
+
/** match at least one of the provided values (value has to be an array) */
|
|
1310
|
+
IN: '~',
|
|
1311
|
+
/** greater than */
|
|
1312
|
+
GREATER_THAN: '>',
|
|
1313
|
+
/** greater than or equal */
|
|
1314
|
+
GREATER_OR_EQUAL: '≽', //
|
|
1315
|
+
LESS_THAN: '<', // less than
|
|
1316
|
+
LESS_OR_EQUAL: '≼', // less than or equal
|
|
1317
|
+
INTERVAL: '<>', // interval
|
|
1318
|
+
INTERVAL_INCLUDE_BOTH: '-', // interval include left and right
|
|
1319
|
+
INTERVAL_INCLUDE_TO: '>-', // interval include right
|
|
1320
|
+
INTERVAL_INCLUDE_FROM: '-<', // interval include left
|
|
1321
|
+
RANGE: '=', // aggegation ranges
|
|
1322
|
+
LIKE: '~', // like
|
|
1323
|
+
CONTAINS: '~' // contains
|
|
1324
|
+
};
|
|
1278
1325
|
|
|
1279
1326
|
/**
|
|
1280
|
-
* Service for
|
|
1327
|
+
* Service for saving or caching data on the users device. It uses the most efficient storage
|
|
1328
|
+
* available (IndexDB, localstorage, ...) on the device. Depending on the type of storage used,
|
|
1329
|
+
* its limitations apply.
|
|
1281
1330
|
*/
|
|
1282
|
-
class
|
|
1283
|
-
#
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
this.#
|
|
1292
|
-
this.event$ = this.#eventSource.asObservable();
|
|
1293
|
-
this.#listenToWindowEvents();
|
|
1294
|
-
}
|
|
1295
|
-
#startsWithAllowed(value) {
|
|
1296
|
-
return typeof value === 'string' && this.#customEvents.some((prefix) => value.startsWith(prefix));
|
|
1297
|
-
}
|
|
1298
|
-
#isValidExternalMessage(event) {
|
|
1299
|
-
this.#customEvents.push(CUSTOM_YUV_EVENT_PREFIX);
|
|
1300
|
-
if (!event.data || typeof event.data !== 'object')
|
|
1301
|
-
return false;
|
|
1302
|
-
if (!(this.#startsWithAllowed(event.data.source) || this.#startsWithAllowed(event.data.type)))
|
|
1303
|
-
return false;
|
|
1304
|
-
// Accept messages from trusted origins
|
|
1305
|
-
this.#customEventsTrustedOrigins.push(window.location.origin);
|
|
1306
|
-
const isFromTrustedOrigin = this.#customEventsTrustedOrigins.includes(event.origin);
|
|
1307
|
-
const hasValidStructure = event.data && (event.data.type || event.data.eventType) && typeof event.data === 'object';
|
|
1308
|
-
return isFromTrustedOrigin && hasValidStructure;
|
|
1331
|
+
class AppCacheService {
|
|
1332
|
+
#storage = inject(StorageMap);
|
|
1333
|
+
/**
|
|
1334
|
+
* Set item in storage.
|
|
1335
|
+
* @param key The key under which the value is stored.
|
|
1336
|
+
* @param value The value to store.
|
|
1337
|
+
* @returns An Observable that emits true when the operation is successful.
|
|
1338
|
+
*/
|
|
1339
|
+
setItem(key, value) {
|
|
1340
|
+
return this.#storage.set(key, value).pipe(map(() => true));
|
|
1309
1341
|
}
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1342
|
+
/**
|
|
1343
|
+
* Get item from storage.
|
|
1344
|
+
* @param key The key of the item to retrieve.
|
|
1345
|
+
* @returns An Observable that emits the retrieved value.
|
|
1346
|
+
*/
|
|
1347
|
+
getItem(key) {
|
|
1348
|
+
return this.#storage.get(key);
|
|
1314
1349
|
}
|
|
1315
1350
|
/**
|
|
1316
|
-
*
|
|
1317
|
-
* @param
|
|
1318
|
-
* @
|
|
1351
|
+
* Remove item from storage.
|
|
1352
|
+
* @param key The key of the item to remove.
|
|
1353
|
+
* @returns An Observable that emits true when the operation is successful.
|
|
1319
1354
|
*/
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
const payload = {
|
|
1323
|
-
type,
|
|
1324
|
-
data,
|
|
1325
|
-
timestamp: Date.now()
|
|
1326
|
-
};
|
|
1327
|
-
window.postMessage(payload, targetOrigin);
|
|
1355
|
+
removeItem(key) {
|
|
1356
|
+
return this.#storage.delete(key).pipe(map(() => true));
|
|
1328
1357
|
}
|
|
1329
1358
|
/**
|
|
1330
|
-
*
|
|
1331
|
-
* @param
|
|
1332
|
-
* @
|
|
1359
|
+
* Clear storage, optionally filtered by a function.
|
|
1360
|
+
* @param filter A function to filter which keys to clear.
|
|
1361
|
+
* @returns An Observable that emits true when the operation is successful.
|
|
1333
1362
|
*/
|
|
1334
|
-
|
|
1335
|
-
|
|
1363
|
+
clear(filter) {
|
|
1364
|
+
return filter
|
|
1365
|
+
? this.getStorageKeys().pipe(switchMap((keys) => {
|
|
1366
|
+
const list = keys.filter((k) => filter(k)).map((k) => this.removeItem(k));
|
|
1367
|
+
return list.length ? forkJoin(list).pipe(map(() => true)) : of(true);
|
|
1368
|
+
}))
|
|
1369
|
+
: this.#storage.clear().pipe(map(() => true));
|
|
1336
1370
|
}
|
|
1337
1371
|
/**
|
|
1338
|
-
*
|
|
1339
|
-
* @
|
|
1372
|
+
* Get all storage keys.
|
|
1373
|
+
* @returns An Observable that emits an array of all storage keys.
|
|
1340
1374
|
*/
|
|
1341
|
-
|
|
1342
|
-
return
|
|
1375
|
+
getStorageKeys() {
|
|
1376
|
+
return new Observable((observer) => {
|
|
1377
|
+
const keys = [];
|
|
1378
|
+
this.#storage.keys().subscribe({
|
|
1379
|
+
next: (key) => keys.push(key),
|
|
1380
|
+
complete: () => observer.next(keys)
|
|
1381
|
+
});
|
|
1382
|
+
}).pipe(first());
|
|
1343
1383
|
}
|
|
1344
|
-
|
|
1345
|
-
|
|
1384
|
+
setStorage(options) {
|
|
1385
|
+
return forkJoin(Object.keys(options || {}).map((k) => this.setItem(k, options[k])));
|
|
1386
|
+
}
|
|
1387
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AppCacheService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1388
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AppCacheService, providedIn: 'root' }); }
|
|
1346
1389
|
}
|
|
1347
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type:
|
|
1390
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AppCacheService, decorators: [{
|
|
1348
1391
|
type: Injectable,
|
|
1349
1392
|
args: [{
|
|
1350
1393
|
providedIn: 'root'
|
|
1351
1394
|
}]
|
|
1352
|
-
}]
|
|
1353
|
-
|
|
1354
|
-
/**
|
|
1355
|
-
* Events emitted by parts of the application
|
|
1356
|
-
*/
|
|
1357
|
-
var YuvEventType;
|
|
1358
|
-
(function (YuvEventType) {
|
|
1359
|
-
YuvEventType["LOGOUT"] = "yuv.user.logout";
|
|
1360
|
-
YuvEventType["CLIENT_LOCALE_CHANGED"] = "yuv.user.locale.client.changed";
|
|
1361
|
-
YuvEventType["DMS_OBJECT_LOADED"] = "yuv.dms.object.loaded";
|
|
1362
|
-
YuvEventType["DMS_OBJECT_CREATED"] = "yuv.dms.object.created";
|
|
1363
|
-
YuvEventType["DMS_OBJECT_DELETED"] = "yuv.dms.object.deleted";
|
|
1364
|
-
YuvEventType["DMS_OBJECT_UPDATED"] = "yuv.dms.object.updated";
|
|
1365
|
-
YuvEventType["DMS_OBJECT_CONTENT_UPDATED"] = "yuv.dms.object.content.updated";
|
|
1366
|
-
YuvEventType["DMS_OBJECTS_MOVED"] = "yuv.dms.objects.moved";
|
|
1367
|
-
YuvEventType["RELATIONSHIP_CREATED"] = "yuv.dms.relationship.created";
|
|
1368
|
-
YuvEventType["RELATIONSHIP_DELETED"] = "yuv.dms.relationship.deleted";
|
|
1369
|
-
})(YuvEventType || (YuvEventType = {}));
|
|
1395
|
+
}] });
|
|
1370
1396
|
|
|
1371
1397
|
/**
|
|
1372
1398
|
* Service managing localizations. The localizations are fetched
|
|
@@ -1432,77 +1458,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
1432
1458
|
}]
|
|
1433
1459
|
}] });
|
|
1434
1460
|
|
|
1435
|
-
/**
|
|
1436
|
-
* Service for saving or caching data on the users device. It uses the most efficient storage
|
|
1437
|
-
* available (IndexDB, localstorage, ...) on the device. Depending on the type of storage used,
|
|
1438
|
-
* its limitations apply.
|
|
1439
|
-
*/
|
|
1440
|
-
class AppCacheService {
|
|
1441
|
-
#storage = inject(StorageMap);
|
|
1442
|
-
/**
|
|
1443
|
-
* Set item in storage.
|
|
1444
|
-
* @param key The key under which the value is stored.
|
|
1445
|
-
* @param value The value to store.
|
|
1446
|
-
* @returns An Observable that emits true when the operation is successful.
|
|
1447
|
-
*/
|
|
1448
|
-
setItem(key, value) {
|
|
1449
|
-
return this.#storage.set(key, value).pipe(map(() => true));
|
|
1450
|
-
}
|
|
1451
|
-
/**
|
|
1452
|
-
* Get item from storage.
|
|
1453
|
-
* @param key The key of the item to retrieve.
|
|
1454
|
-
* @returns An Observable that emits the retrieved value.
|
|
1455
|
-
*/
|
|
1456
|
-
getItem(key) {
|
|
1457
|
-
return this.#storage.get(key);
|
|
1458
|
-
}
|
|
1459
|
-
/**
|
|
1460
|
-
* Remove item from storage.
|
|
1461
|
-
* @param key The key of the item to remove.
|
|
1462
|
-
* @returns An Observable that emits true when the operation is successful.
|
|
1463
|
-
*/
|
|
1464
|
-
removeItem(key) {
|
|
1465
|
-
return this.#storage.delete(key).pipe(map(() => true));
|
|
1466
|
-
}
|
|
1467
|
-
/**
|
|
1468
|
-
* Clear storage, optionally filtered by a function.
|
|
1469
|
-
* @param filter A function to filter which keys to clear.
|
|
1470
|
-
* @returns An Observable that emits true when the operation is successful.
|
|
1471
|
-
*/
|
|
1472
|
-
clear(filter) {
|
|
1473
|
-
return filter
|
|
1474
|
-
? this.getStorageKeys().pipe(switchMap((keys) => {
|
|
1475
|
-
const list = keys.filter((k) => filter(k)).map((k) => this.removeItem(k));
|
|
1476
|
-
return list.length ? forkJoin(list).pipe(map(() => true)) : of(true);
|
|
1477
|
-
}))
|
|
1478
|
-
: this.#storage.clear().pipe(map(() => true));
|
|
1479
|
-
}
|
|
1480
|
-
/**
|
|
1481
|
-
* Get all storage keys.
|
|
1482
|
-
* @returns An Observable that emits an array of all storage keys.
|
|
1483
|
-
*/
|
|
1484
|
-
getStorageKeys() {
|
|
1485
|
-
return new Observable((observer) => {
|
|
1486
|
-
const keys = [];
|
|
1487
|
-
this.#storage.keys().subscribe({
|
|
1488
|
-
next: (key) => keys.push(key),
|
|
1489
|
-
complete: () => observer.next(keys)
|
|
1490
|
-
});
|
|
1491
|
-
}).pipe(first());
|
|
1492
|
-
}
|
|
1493
|
-
setStorage(options) {
|
|
1494
|
-
return forkJoin(Object.keys(options || {}).map((k) => this.setItem(k, options[k])));
|
|
1495
|
-
}
|
|
1496
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AppCacheService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1497
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AppCacheService, providedIn: 'root' }); }
|
|
1498
|
-
}
|
|
1499
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AppCacheService, decorators: [{
|
|
1500
|
-
type: Injectable,
|
|
1501
|
-
args: [{
|
|
1502
|
-
providedIn: 'root'
|
|
1503
|
-
}]
|
|
1504
|
-
}] });
|
|
1505
|
-
|
|
1506
1461
|
/**
|
|
1507
1462
|
* Providing system definitions.
|
|
1508
1463
|
*/
|
|
@@ -2139,1268 +2094,1182 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
2139
2094
|
}]
|
|
2140
2095
|
}] });
|
|
2141
2096
|
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
constructor() {
|
|
2147
|
-
this.#backend = inject(BackendService);
|
|
2148
|
-
this.#translate = inject(TranslateService);
|
|
2149
|
-
this.#logger = inject(Logger);
|
|
2150
|
-
this.#system = inject(SystemService);
|
|
2151
|
-
this.#localization = inject(LocalizationService);
|
|
2152
|
-
this.#eventService = inject(EventService);
|
|
2153
|
-
this.#config = inject(ConfigService);
|
|
2154
|
-
this.#document = inject(DOCUMENT);
|
|
2155
|
-
this.#USERS_SETTINGS = '/users/settings/';
|
|
2156
|
-
this.#DEFAULT_SETTINGS = '/users/settings';
|
|
2157
|
-
this.#SETTINGS_SECTION_OBJECTCONFIG = 'object-config';
|
|
2158
|
-
this.#userSource = new BehaviorSubject(this.#user);
|
|
2159
|
-
this.user$ = this.#userSource.asObservable();
|
|
2160
|
-
this.globalSettings = new Map();
|
|
2161
|
-
this.canCreateObjects = false;
|
|
2162
|
-
}
|
|
2163
|
-
#backend;
|
|
2164
|
-
#translate;
|
|
2165
|
-
#logger;
|
|
2166
|
-
#system;
|
|
2167
|
-
#localization;
|
|
2168
|
-
#eventService;
|
|
2169
|
-
#config;
|
|
2170
|
-
#document;
|
|
2171
|
-
#USERS_SETTINGS;
|
|
2172
|
-
#DEFAULT_SETTINGS;
|
|
2173
|
-
#SETTINGS_SECTION_OBJECTCONFIG;
|
|
2174
|
-
#user;
|
|
2175
|
-
#userSource;
|
|
2097
|
+
class SearchService {
|
|
2098
|
+
#backend = inject(BackendService);
|
|
2099
|
+
#system = inject(SystemService);
|
|
2100
|
+
static { this.DEFAULT_QUERY_SIZE = 50; }
|
|
2176
2101
|
/**
|
|
2177
|
-
*
|
|
2178
|
-
* @param
|
|
2102
|
+
* Execute a search query ans transform the result to a SearchResult object
|
|
2103
|
+
* @param query The search query
|
|
2104
|
+
* @returns Observable of a SearchResult
|
|
2179
2105
|
*/
|
|
2180
|
-
|
|
2181
|
-
this
|
|
2182
|
-
this.changeClientLocale('', false);
|
|
2183
|
-
this.#userSource.next(this.#user);
|
|
2184
|
-
}
|
|
2185
|
-
getCurrentUser() {
|
|
2186
|
-
return this.#user;
|
|
2187
|
-
}
|
|
2188
|
-
get hasAdminRole() {
|
|
2189
|
-
return this.#user?.authorities?.includes(AdministrationRoles.ADMIN) || false;
|
|
2190
|
-
}
|
|
2191
|
-
get hasSystemRole() {
|
|
2192
|
-
return this.#user?.authorities?.includes(AdministrationRoles.SYSTEM) || false;
|
|
2193
|
-
}
|
|
2194
|
-
get hasAdministrationRoles() {
|
|
2195
|
-
return this.hasAdminRole || this.hasSystemRole;
|
|
2196
|
-
}
|
|
2197
|
-
get hasManageSettingsRole() {
|
|
2198
|
-
const customRole = this.#config.get('core.permissions.manageSettingsRole');
|
|
2199
|
-
const manageSettingsRole = customRole || AdministrationRoles.MANAGE_SETTINGS;
|
|
2200
|
-
return this.#user?.authorities?.includes(manageSettingsRole) || false;
|
|
2201
|
-
}
|
|
2202
|
-
get isAdvancedUser() {
|
|
2203
|
-
const customRole = this.#config.get('core.permissions.advancedUserRole');
|
|
2204
|
-
const advancedUserRole = customRole || AdministrationRoles.MANAGE_SETTINGS;
|
|
2205
|
-
return this.#user?.authorities?.includes(advancedUserRole) || false;
|
|
2106
|
+
search(query) {
|
|
2107
|
+
return this.searchRaw(query).pipe(map((res) => this.toSearchResult(res, query.size || SearchService.DEFAULT_QUERY_SIZE, query.from || 0)));
|
|
2206
2108
|
}
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2109
|
+
/**
|
|
2110
|
+
* Execute a raw search query and return the result as is.
|
|
2111
|
+
* @param query The search query
|
|
2112
|
+
* @returns Observable of the raw search result
|
|
2113
|
+
*/
|
|
2114
|
+
searchRaw(query) {
|
|
2115
|
+
if (!query.size)
|
|
2116
|
+
query.size = SearchService.DEFAULT_QUERY_SIZE;
|
|
2117
|
+
return this.#backend.post(`/dms/objects/search`, query);
|
|
2211
2118
|
}
|
|
2212
2119
|
/**
|
|
2213
|
-
*
|
|
2214
|
-
* @param
|
|
2120
|
+
* Search for objects in the dms using CMIS like SQL syntax.
|
|
2121
|
+
* @param statement The query statement
|
|
2122
|
+
* @param size The number of items to return
|
|
2123
|
+
* @returns Observable of a SearchResult
|
|
2215
2124
|
*/
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
const languages = this.#config.getClientLocales().map((lang) => lang.iso);
|
|
2219
|
-
iso = iso || this.#user.getClientLocale(this.#config.getDefaultClientLocale());
|
|
2220
|
-
if (!languages.includes(iso)) {
|
|
2221
|
-
iso = this.#config.getDefaultClientLocale();
|
|
2222
|
-
}
|
|
2223
|
-
this.#logger.debug("Changed client locale to '" + iso + "'");
|
|
2224
|
-
this.#backend.setHeader('Accept-Language', iso);
|
|
2225
|
-
this.#user.uiDirection = this.#getUiDirection(iso);
|
|
2226
|
-
this.#document.body.dir = this.#user.uiDirection;
|
|
2227
|
-
this.#document.documentElement.lang = iso;
|
|
2228
|
-
this.#user.userSettings.locale = iso;
|
|
2229
|
-
if (this.#translate.getCurrentLang() !== iso || this.#system.authData?.language !== iso) {
|
|
2230
|
-
const obs = persist
|
|
2231
|
-
? forkJoin([
|
|
2232
|
-
this.#translate.use(iso),
|
|
2233
|
-
this.#system
|
|
2234
|
-
.updateAuthData({ language: iso })
|
|
2235
|
-
.pipe(switchMap(() => this.#localization.fetchLocalizations())),
|
|
2236
|
-
this.saveUserSettings(this.#user.userSettings).pipe(tap(() => {
|
|
2237
|
-
this.#logger.debug('Loading system definitions i18n resources for new locale.');
|
|
2238
|
-
}))
|
|
2239
|
-
])
|
|
2240
|
-
: this.#translate.use(iso);
|
|
2241
|
-
obs.subscribe(() => this.#eventService.trigger(YuvEventType.CLIENT_LOCALE_CHANGED, iso));
|
|
2242
|
-
}
|
|
2243
|
-
}
|
|
2125
|
+
searchCmis(statement, size = SearchService.DEFAULT_QUERY_SIZE, includePermissions = false) {
|
|
2126
|
+
return this.#executeCmisSearch(statement, size, 0, includePermissions);
|
|
2244
2127
|
}
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2128
|
+
#executeCmisSearch(statement, maxItems, skipCount = 0, includePermissions = false) {
|
|
2129
|
+
const payload = {
|
|
2130
|
+
query: {
|
|
2131
|
+
statement,
|
|
2132
|
+
skipCount,
|
|
2133
|
+
maxItems,
|
|
2134
|
+
handleDeletedDocuments: 'DELETED_DOCUMENTS_EXCLUDE'
|
|
2135
|
+
}
|
|
2136
|
+
};
|
|
2137
|
+
if (includePermissions) {
|
|
2138
|
+
payload.query.includePermissions = true;
|
|
2252
2139
|
}
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
this
|
|
2259
|
-
return this.#backend.get(this.#DEFAULT_SETTINGS);
|
|
2260
|
-
}));
|
|
2140
|
+
return this.#backend
|
|
2141
|
+
.post('/dms/objects/cmisSearch', payload
|
|
2142
|
+
// Using API-WEB because it enriches the response with additional information (resolved user names, etc.)
|
|
2143
|
+
// ApiBase.core
|
|
2144
|
+
)
|
|
2145
|
+
.pipe(map((res) => this.toSearchResult(res, maxItems, skipCount)));
|
|
2261
2146
|
}
|
|
2262
2147
|
/**
|
|
2263
|
-
*
|
|
2264
|
-
* @param
|
|
2265
|
-
* @param
|
|
2266
|
-
*
|
|
2148
|
+
* Fetch aggragations for a given query.
|
|
2149
|
+
* @param q The query
|
|
2150
|
+
* @param aggregations List of aggregations to be fetched (e.g. `enaio:objectTypeId`
|
|
2151
|
+
* to get an aggregation of object types)
|
|
2267
2152
|
*/
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
return this.#backend
|
|
2272
|
-
.get(`/idm/users?${params}`)
|
|
2273
|
-
.pipe(map((users) => (!users ? [] : users.map((u) => new YuvUser(u)))));
|
|
2274
|
-
}
|
|
2275
|
-
getUserById(id) {
|
|
2276
|
-
return this.#backend.get(`/idm/users/${id}`).pipe(map((user) => new YuvUser(user, this.#user.userSettings)));
|
|
2277
|
-
}
|
|
2278
|
-
logout(redirRoute) {
|
|
2279
|
-
const redir = redirRoute ? `?redir=${redirRoute}` : '';
|
|
2280
|
-
window.location.href = `${this.#backend.getApiBase('logout')}${redir}`;
|
|
2281
|
-
}
|
|
2282
|
-
getSettings(section) {
|
|
2283
|
-
return this.#user ? this.#backend.get(this.#USERS_SETTINGS + encodeURIComponent(section)) : of(null);
|
|
2284
|
-
}
|
|
2285
|
-
saveObjectConfig(objectConfigs) {
|
|
2286
|
-
return this.#backend.post(this.#USERS_SETTINGS + encodeURIComponent(this.#SETTINGS_SECTION_OBJECTCONFIG), objectConfigs);
|
|
2287
|
-
}
|
|
2288
|
-
loadObjectConfig() {
|
|
2289
|
-
return this.getSettings(this.#SETTINGS_SECTION_OBJECTCONFIG).pipe(catchError(() => of(undefined)));
|
|
2290
|
-
}
|
|
2291
|
-
#getUiDirection(iso) {
|
|
2292
|
-
// languages that are read right to left
|
|
2293
|
-
const rtlLanguages = ['ar', 'arc', 'dv', 'fa', 'ha', 'he', 'khw', 'ks', 'ku', 'ps', 'ur', 'yi'];
|
|
2294
|
-
return !rtlLanguages.includes(iso) ? Direction.LTR : Direction.RTL;
|
|
2295
|
-
}
|
|
2296
|
-
#setUserPermissions(res) {
|
|
2297
|
-
this.userPermissions = {
|
|
2298
|
-
create: this.#mapPermissions('CREATE', res),
|
|
2299
|
-
write: this.#mapPermissions('WRITE', res),
|
|
2300
|
-
read: this.#mapPermissions('READ', res),
|
|
2301
|
-
delete: this.#mapPermissions('DELETE', res)
|
|
2302
|
-
};
|
|
2303
|
-
const permissions = {
|
|
2304
|
-
createableObjectTypes: [
|
|
2305
|
-
...this.userPermissions.create.folderTypes,
|
|
2306
|
-
...this.userPermissions.create.objectTypes,
|
|
2307
|
-
...this.userPermissions.create.secondaryObjectTypes
|
|
2308
|
-
],
|
|
2309
|
-
searchableObjectTypes: [
|
|
2310
|
-
...this.userPermissions.read.folderTypes,
|
|
2311
|
-
...this.userPermissions.read.objectTypes,
|
|
2312
|
-
...this.userPermissions.read.secondaryObjectTypes
|
|
2313
|
-
]
|
|
2314
|
-
};
|
|
2315
|
-
this.#system.setPermissions(permissions);
|
|
2316
|
-
this.canCreateObjects = permissions.createableObjectTypes.length > 0;
|
|
2153
|
+
aggregate(q, aggregations) {
|
|
2154
|
+
q.aggs = aggregations;
|
|
2155
|
+
return this.searchRaw(q).pipe(map((res) => this.#toAggregateResult(res, aggregations)));
|
|
2317
2156
|
}
|
|
2318
|
-
|
|
2319
|
-
|
|
2157
|
+
/**
|
|
2158
|
+
* Map search result from the backend to applications AggregateResult object
|
|
2159
|
+
* @param searchResponse The backend response
|
|
2160
|
+
* @param aggregations The aggregations to be fetched
|
|
2161
|
+
*/
|
|
2162
|
+
#toAggregateResult(searchResponse, aggregations) {
|
|
2163
|
+
const agg = [];
|
|
2164
|
+
if (aggregations) {
|
|
2165
|
+
aggregations.forEach((a) => {
|
|
2166
|
+
const ag = {
|
|
2167
|
+
aggKey: a,
|
|
2168
|
+
entries: searchResponse.objects.map((o) => ({
|
|
2169
|
+
key: o.properties[a].value,
|
|
2170
|
+
count: o.properties['OBJECT_COUNT'].value
|
|
2171
|
+
}))
|
|
2172
|
+
};
|
|
2173
|
+
agg.push(ag);
|
|
2174
|
+
});
|
|
2175
|
+
}
|
|
2320
2176
|
return {
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
secondaryObjectTypes: res['secondaryObjectTypeIds'] || []
|
|
2177
|
+
totalNumItems: searchResponse.totalNumItems,
|
|
2178
|
+
aggregations: agg
|
|
2324
2179
|
};
|
|
2325
2180
|
}
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
*
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
factory: () => ({ main: ['assets/_yuuvis/config/main.json'], translations: ['assets/_yuuvis/i18n/'] })
|
|
2341
|
-
});
|
|
2342
|
-
const CORE_CONFIG = new InjectionToken('CORE_CONFIG');
|
|
2343
|
-
|
|
2344
|
-
/**
|
|
2345
|
-
* @ignore
|
|
2346
|
-
*/
|
|
2347
|
-
let CoreConfig = class CoreConfig {
|
|
2348
|
-
constructor(__config) {
|
|
2349
|
-
this.main = ['assets/_yuuvis/config/main.json'];
|
|
2350
|
-
this.translations = ['assets/_yuuvis/i18n/'];
|
|
2351
|
-
this.environment = { production: true };
|
|
2352
|
-
Object.assign(this, __config);
|
|
2353
|
-
}
|
|
2354
|
-
};
|
|
2355
|
-
CoreConfig = __decorate([
|
|
2356
|
-
__param(0, Inject(CUSTOM_CONFIG)),
|
|
2357
|
-
__metadata("design:paramtypes", [CoreConfig])
|
|
2358
|
-
], CoreConfig);
|
|
2359
|
-
|
|
2360
|
-
/**
|
|
2361
|
-
* Service managing the configuarions for object types.
|
|
2362
|
-
* Configuration means that you can pick certain fields
|
|
2363
|
-
* of an object type and assign them to a config object.
|
|
2364
|
-
*/
|
|
2365
|
-
class ObjectConfigService {
|
|
2366
|
-
constructor() {
|
|
2367
|
-
this.#system = inject(SystemService);
|
|
2368
|
-
this.#user = inject(UserService);
|
|
2369
|
-
this.OBJECT_CONFIG_STORAGE_KEY = 'yuv.framework.object-config';
|
|
2370
|
-
this.#objectConfigsSource = new ReplaySubject();
|
|
2371
|
-
this.#objectConfigs$ = this.#objectConfigsSource.asObservable();
|
|
2372
|
-
this.#defaultObjectConfigs = {};
|
|
2373
|
-
this.#registeredDefaultObjectConfigs = {
|
|
2374
|
-
main: {},
|
|
2375
|
-
buckets: []
|
|
2376
|
-
};
|
|
2377
|
-
this.#objectConfigs = {
|
|
2378
|
-
main: {},
|
|
2379
|
-
buckets: []
|
|
2380
|
-
};
|
|
2381
|
-
}
|
|
2382
|
-
#system;
|
|
2383
|
-
#user;
|
|
2384
|
-
#objectConfigsSource;
|
|
2385
|
-
#objectConfigs$;
|
|
2386
|
-
#defaultObjectConfigs;
|
|
2387
|
-
#registeredDefaultObjectConfigs;
|
|
2388
|
-
#objectConfigs;
|
|
2389
|
-
#isValidObjectConfig(soc) {
|
|
2390
|
-
return coerceBooleanProperty(soc && Object.hasOwn(soc, 'main') && Object.hasOwn(soc, 'buckets'));
|
|
2391
|
-
}
|
|
2392
|
-
// called on core init (auth.service -> initApp)
|
|
2393
|
-
init() {
|
|
2394
|
-
return this.#user.loadObjectConfig().pipe(tap$1((res) => {
|
|
2395
|
-
this.#getDefaultObjectConfig();
|
|
2396
|
-
this.#objectConfigs = (this.#isValidObjectConfig(res) && res) || {
|
|
2397
|
-
main: {},
|
|
2398
|
-
buckets: []
|
|
2399
|
-
};
|
|
2400
|
-
this.#objectConfigsSource.next(this.#objectConfigs);
|
|
2401
|
-
}));
|
|
2181
|
+
/**
|
|
2182
|
+
* Go to a page of a search result.
|
|
2183
|
+
* @param query SearchQuery or CMIS query statement
|
|
2184
|
+
* @param page The number of the page to go to
|
|
2185
|
+
*/
|
|
2186
|
+
getPage(query, page, pageSize = SearchService.DEFAULT_QUERY_SIZE, includePermissions = false) {
|
|
2187
|
+
const isCmis = typeof query === 'string';
|
|
2188
|
+
if (isCmis) {
|
|
2189
|
+
return this.#executeCmisSearch(query, pageSize, (page - 1) * pageSize, includePermissions);
|
|
2190
|
+
}
|
|
2191
|
+
else {
|
|
2192
|
+
query.from = (page - 1) * (query.size || pageSize);
|
|
2193
|
+
return this.search(query);
|
|
2194
|
+
}
|
|
2402
2195
|
}
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2196
|
+
/**
|
|
2197
|
+
* Map search result from the backend to applications SearchResult object
|
|
2198
|
+
* @param searchResponse The backend response
|
|
2199
|
+
*/
|
|
2200
|
+
toSearchResult(searchResponse, pageSize = SearchService.DEFAULT_QUERY_SIZE, skipCount = 0) {
|
|
2201
|
+
const resultListItems = [];
|
|
2202
|
+
const objectTypes = [];
|
|
2203
|
+
searchResponse.objects.forEach((o) => {
|
|
2204
|
+
const fields = new Map();
|
|
2205
|
+
// process properties section of result
|
|
2206
|
+
Object.keys(o.properties).forEach((key) => {
|
|
2207
|
+
let value = o.properties[key].value;
|
|
2208
|
+
if (o.properties[key].clvalue) {
|
|
2209
|
+
// table fields will have a clientValue too ...
|
|
2210
|
+
value = o.properties[key].clvalue;
|
|
2211
|
+
// ... and also may contain values that need to be resolved
|
|
2212
|
+
if (o.properties[key].resolvedValues) {
|
|
2213
|
+
value.forEach((v) => {
|
|
2214
|
+
Object.keys(v).forEach((k) => {
|
|
2215
|
+
const resValue = Array.isArray(v[k]) ? v[k].map((i) => o.properties[key].resolvedValues[i]) : o.properties[key].resolvedValues[v[k]];
|
|
2216
|
+
if (resValue) {
|
|
2217
|
+
v[`${k}_title`] = resValue;
|
|
2218
|
+
}
|
|
2219
|
+
});
|
|
2414
2220
|
});
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
fields.set(key, value);
|
|
2224
|
+
if (o.properties[key].title) {
|
|
2225
|
+
fields.set(key + '_title', o.properties[key].title);
|
|
2415
2226
|
}
|
|
2227
|
+
});
|
|
2228
|
+
// process contentStreams section of result if available.
|
|
2229
|
+
// Objects that don't have files attached won't have this section
|
|
2230
|
+
let content;
|
|
2231
|
+
if (o.contentStreams && o.contentStreams.length > 0) {
|
|
2232
|
+
// we assume that each result object only has ONE file attached, altough
|
|
2233
|
+
// this is an array and there may be more
|
|
2234
|
+
const contentStream = o.contentStreams[0];
|
|
2235
|
+
// also add contentstream related fields to the result fields
|
|
2236
|
+
fields.set(ContentStreamField.LENGTH, contentStream.length);
|
|
2237
|
+
fields.set(ContentStreamField.MIME_TYPE, contentStream.mimeType);
|
|
2238
|
+
fields.set(ContentStreamField.FILENAME, contentStream.fileName);
|
|
2239
|
+
fields.set(ContentStreamField.ID, contentStream.contentStreamId);
|
|
2240
|
+
fields.set(ContentStreamField.RANGE, contentStream.contentStreamRange);
|
|
2241
|
+
fields.set(ContentStreamField.REPOSITORY_ID, contentStream.repositoryId);
|
|
2242
|
+
fields.set(ContentStreamField.DIGEST, contentStream.digest);
|
|
2243
|
+
fields.set(ContentStreamField.ARCHIVE_PATH, contentStream.archivePath);
|
|
2244
|
+
content = {
|
|
2245
|
+
contentStreamId: contentStream.contentStreamId,
|
|
2246
|
+
repositoryId: contentStream.repositoryId,
|
|
2247
|
+
range: contentStream.range,
|
|
2248
|
+
digest: contentStream.digest,
|
|
2249
|
+
archivePath: contentStream.archivePath,
|
|
2250
|
+
fileName: contentStream.fileName,
|
|
2251
|
+
mimeType: contentStream.mimeType,
|
|
2252
|
+
size: contentStream.length
|
|
2253
|
+
};
|
|
2416
2254
|
}
|
|
2417
|
-
|
|
2418
|
-
|
|
2255
|
+
const objectTypeId = o.properties[BaseObjectTypeField.OBJECT_TYPE_ID] ? o.properties[BaseObjectTypeField.OBJECT_TYPE_ID].value : null;
|
|
2256
|
+
if (objectTypes.indexOf(objectTypeId) === -1) {
|
|
2257
|
+
objectTypes.push(objectTypeId);
|
|
2258
|
+
}
|
|
2259
|
+
resultListItems.push({
|
|
2260
|
+
objectTypeId,
|
|
2261
|
+
content,
|
|
2262
|
+
fields,
|
|
2263
|
+
permissions: o.permissions
|
|
2264
|
+
});
|
|
2265
|
+
});
|
|
2266
|
+
const totalPages = Math.ceil(searchResponse.totalNumItems / pageSize);
|
|
2267
|
+
const page = (!skipCount ? 0 : skipCount / pageSize) + 1;
|
|
2268
|
+
const result = {
|
|
2269
|
+
hasMoreItems: searchResponse.hasMoreItems,
|
|
2270
|
+
totalNumItems: searchResponse.totalNumItems,
|
|
2271
|
+
items: resultListItems,
|
|
2272
|
+
objectTypes: objectTypes,
|
|
2273
|
+
paging: totalPages > 1 ? { page, totalPages } : undefined
|
|
2274
|
+
};
|
|
2275
|
+
return result;
|
|
2419
2276
|
}
|
|
2420
2277
|
/**
|
|
2421
|
-
*
|
|
2422
|
-
*
|
|
2423
|
-
* @param
|
|
2424
|
-
*
|
|
2425
|
-
* the global scope
|
|
2278
|
+
* Maps data extracted from a search form to search filters. Every key of the form data object
|
|
2279
|
+
* will be mapped to a search filter.
|
|
2280
|
+
* @param formData form data
|
|
2281
|
+
* @returns Array of search filters
|
|
2426
2282
|
*/
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2283
|
+
formDataToSearchFilter(formData) {
|
|
2284
|
+
const isRangeValue = (v) => {
|
|
2285
|
+
return typeof v === 'object' && v !== null && 'firstValue' in v && 'operator' in v;
|
|
2286
|
+
};
|
|
2287
|
+
const filters = [];
|
|
2288
|
+
Object.keys(formData).forEach((key) => {
|
|
2289
|
+
const value = formData[key];
|
|
2290
|
+
if (isRangeValue(value)) {
|
|
2291
|
+
const f = this.rangeValueToSearchFilter(value, key);
|
|
2292
|
+
if (f)
|
|
2293
|
+
filters.push(f);
|
|
2436
2294
|
}
|
|
2437
2295
|
else {
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2296
|
+
filters.push({
|
|
2297
|
+
f: key,
|
|
2298
|
+
o: Array.isArray(value) ? Operator.IN : Operator.EQUAL,
|
|
2299
|
+
v1: value
|
|
2441
2300
|
});
|
|
2442
2301
|
}
|
|
2443
|
-
}
|
|
2444
|
-
|
|
2445
|
-
this.#registeredDefaultObjectConfigs.main = { ...this.#registeredDefaultObjectConfigs.main, ...configs };
|
|
2446
|
-
}
|
|
2302
|
+
});
|
|
2303
|
+
return filters;
|
|
2447
2304
|
}
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2305
|
+
rangeValueToSearchFilter(value, property) {
|
|
2306
|
+
return this.#system.getObjectTypeField(property)?.propertyType === 'datetime'
|
|
2307
|
+
? this.#dateRangeValueToSearchFilter(value, property)
|
|
2308
|
+
: {
|
|
2309
|
+
f: property,
|
|
2310
|
+
o: value.operator,
|
|
2311
|
+
v1: value.firstValue,
|
|
2312
|
+
v2: value.secondValue
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
#dateRangeValueToSearchFilter(rv, property) {
|
|
2316
|
+
const v1 = rv.firstValue;
|
|
2317
|
+
const v2 = rv.secondValue;
|
|
2318
|
+
switch (rv.operator) {
|
|
2319
|
+
case Operator.EQUAL: {
|
|
2320
|
+
return {
|
|
2321
|
+
f: property,
|
|
2322
|
+
o: Operator.INTERVAL_INCLUDE_BOTH,
|
|
2323
|
+
v1: this.#dateToISOString(v1, 'start'),
|
|
2324
|
+
v2: this.#dateToISOString(v1, 'end')
|
|
2325
|
+
};
|
|
2454
2326
|
}
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2327
|
+
case Operator.GREATER_OR_EQUAL: {
|
|
2328
|
+
return {
|
|
2329
|
+
f: property,
|
|
2330
|
+
o: rv.operator,
|
|
2331
|
+
v1: this.#dateToISOString(v1)
|
|
2332
|
+
};
|
|
2333
|
+
}
|
|
2334
|
+
case Operator.LESS_OR_EQUAL: {
|
|
2335
|
+
return {
|
|
2336
|
+
f: property,
|
|
2337
|
+
o: rv.operator,
|
|
2338
|
+
v1: this.#dateToISOString(v1, 'end')
|
|
2339
|
+
};
|
|
2340
|
+
}
|
|
2341
|
+
case Operator.INTERVAL_INCLUDE_BOTH: {
|
|
2342
|
+
return {
|
|
2343
|
+
f: property,
|
|
2344
|
+
o: rv.operator,
|
|
2345
|
+
v1: this.#dateToISOString(v1, 'start'),
|
|
2346
|
+
v2: v2 ? this.#dateToISOString(v2, 'end') : ''
|
|
2347
|
+
};
|
|
2348
|
+
}
|
|
2349
|
+
default:
|
|
2350
|
+
return undefined;
|
|
2460
2351
|
}
|
|
2461
2352
|
}
|
|
2462
|
-
getRegisteredDefault(objectTypeId, bucket) {
|
|
2463
|
-
if (bucket) {
|
|
2464
|
-
const b = this.#registeredDefaultObjectConfigs.buckets.find((b) => b.id === bucket);
|
|
2465
|
-
return b ? b.configs[objectTypeId] : undefined;
|
|
2466
|
-
}
|
|
2467
|
-
else {
|
|
2468
|
-
return this.#registeredDefaultObjectConfigs.main[objectTypeId];
|
|
2469
|
-
}
|
|
2470
|
-
}
|
|
2471
|
-
#getRegisteredDefaults(bucket) {
|
|
2472
|
-
if (bucket) {
|
|
2473
|
-
const defaultTileBucket = this.#registeredDefaultObjectConfigs.buckets.find((b) => b.id === bucket);
|
|
2474
|
-
return defaultTileBucket?.configs || {};
|
|
2475
|
-
}
|
|
2476
|
-
else
|
|
2477
|
-
return this.#registeredDefaultObjectConfigs.main;
|
|
2478
|
-
}
|
|
2479
2353
|
/**
|
|
2480
|
-
*
|
|
2481
|
-
*
|
|
2482
|
-
* @param
|
|
2483
|
-
*
|
|
2484
|
-
*
|
|
2485
|
-
* used accross the whole client application.
|
|
2354
|
+
* Checks if value is a date and retrieves an ISOString representation. Optionally you can determine, if it should be the beginning or the end of a day.
|
|
2355
|
+
*
|
|
2356
|
+
* @param value
|
|
2357
|
+
* @param range
|
|
2358
|
+
* @private
|
|
2486
2359
|
*/
|
|
2487
|
-
|
|
2488
|
-
const
|
|
2489
|
-
const
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
const
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2360
|
+
#dateToISOString(value, range = 'start') {
|
|
2361
|
+
const date = typeof value === 'string' ? new Date(value) : value;
|
|
2362
|
+
const offset = Utils.DEFAULT_TIME_OFFSET_V2; // T+23:59:59:999
|
|
2363
|
+
if (!Utils.isValidDate(date))
|
|
2364
|
+
return '';
|
|
2365
|
+
const isoDateString = date.toISOString();
|
|
2366
|
+
// const isoDateStringWithOffset = new Date(date.getTime() + offset).toISOString();
|
|
2367
|
+
switch (range) {
|
|
2368
|
+
case 'start':
|
|
2369
|
+
return isoDateString;
|
|
2370
|
+
case 'end':
|
|
2371
|
+
return isoDateString;
|
|
2372
|
+
default:
|
|
2373
|
+
return isoDateString;
|
|
2374
|
+
}
|
|
2497
2375
|
}
|
|
2498
|
-
|
|
2499
|
-
|
|
2376
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: SearchService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2377
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: SearchService, providedIn: 'root' }); }
|
|
2378
|
+
}
|
|
2379
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: SearchService, decorators: [{
|
|
2380
|
+
type: Injectable,
|
|
2381
|
+
args: [{
|
|
2382
|
+
providedIn: 'root'
|
|
2383
|
+
}]
|
|
2384
|
+
}] });
|
|
2385
|
+
|
|
2386
|
+
var Direction;
|
|
2387
|
+
(function (Direction) {
|
|
2388
|
+
Direction["LTR"] = "ltr";
|
|
2389
|
+
Direction["RTL"] = "rtl";
|
|
2390
|
+
})(Direction || (Direction = {}));
|
|
2391
|
+
|
|
2392
|
+
const CUSTOM_EVENTS = new InjectionToken('CUSTOM_EVENTS', { factory: () => [] });
|
|
2393
|
+
const CUSTOM_EVENTS_TRUSTED_ORIGINS = new InjectionToken('CUSTOM_EVENTS_TRUSTED_ORIGINS', { factory: () => [] });
|
|
2394
|
+
|
|
2395
|
+
/**
|
|
2396
|
+
* Mandatory Custom event prefix for all custom YUV events
|
|
2397
|
+
*/
|
|
2398
|
+
const CUSTOM_YUV_EVENT_PREFIX = 'yuv.';
|
|
2399
|
+
|
|
2400
|
+
/**
|
|
2401
|
+
* Service for providing triggered events
|
|
2402
|
+
*/
|
|
2403
|
+
class EventService {
|
|
2404
|
+
#customEvents;
|
|
2405
|
+
#customEventsTrustedOrigins;
|
|
2406
|
+
#ngZone;
|
|
2407
|
+
#eventSource;
|
|
2408
|
+
constructor() {
|
|
2409
|
+
this.#customEvents = inject(CUSTOM_EVENTS);
|
|
2410
|
+
this.#customEventsTrustedOrigins = inject(CUSTOM_EVENTS_TRUSTED_ORIGINS);
|
|
2411
|
+
this.#ngZone = inject(NgZone);
|
|
2412
|
+
this.#eventSource = new Subject();
|
|
2413
|
+
this.event$ = this.#eventSource.asObservable();
|
|
2414
|
+
this.#listenToWindowEvents();
|
|
2500
2415
|
}
|
|
2501
|
-
|
|
2502
|
-
this.#
|
|
2503
|
-
return this.#user.saveObjectConfig(this.#objectConfigs);
|
|
2416
|
+
#startsWithAllowed(value) {
|
|
2417
|
+
return typeof value === 'string' && this.#customEvents.some((prefix) => value.startsWith(prefix));
|
|
2504
2418
|
}
|
|
2505
|
-
#
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
Object.keys(configs).forEach((objectTypeId) => {
|
|
2517
|
-
const config = configs[objectTypeId];
|
|
2518
|
-
if (config) {
|
|
2519
|
-
this.#objectConfigs.buckets[tileBucketIdx].configs[objectTypeId] = config;
|
|
2520
|
-
}
|
|
2521
|
-
else {
|
|
2522
|
-
delete this.#objectConfigs.buckets[tileBucketIdx].configs[objectTypeId];
|
|
2523
|
-
}
|
|
2524
|
-
});
|
|
2525
|
-
}
|
|
2526
|
-
else {
|
|
2527
|
-
const newBucket = { id: bucket, configs: {} };
|
|
2528
|
-
Object.keys(configs).forEach((objectTypeId) => {
|
|
2529
|
-
const config = configs[objectTypeId];
|
|
2530
|
-
if (config) {
|
|
2531
|
-
newBucket.configs[objectTypeId] = config;
|
|
2532
|
-
}
|
|
2533
|
-
});
|
|
2534
|
-
this.#objectConfigs.buckets.push(newBucket);
|
|
2535
|
-
}
|
|
2536
|
-
}
|
|
2537
|
-
else {
|
|
2538
|
-
Object.keys(configs).forEach((objectTypeId) => {
|
|
2539
|
-
const config = configs[objectTypeId];
|
|
2540
|
-
if (config) {
|
|
2541
|
-
this.#objectConfigs.main[objectTypeId] = config;
|
|
2542
|
-
}
|
|
2543
|
-
else {
|
|
2544
|
-
delete this.#objectConfigs.main[objectTypeId];
|
|
2545
|
-
}
|
|
2546
|
-
});
|
|
2547
|
-
}
|
|
2548
|
-
this.#objectConfigsSource.next(this.#objectConfigs);
|
|
2419
|
+
#isValidExternalMessage(event) {
|
|
2420
|
+
this.#customEvents.push(CUSTOM_YUV_EVENT_PREFIX);
|
|
2421
|
+
if (!event.data || typeof event.data !== 'object')
|
|
2422
|
+
return false;
|
|
2423
|
+
if (!(this.#startsWithAllowed(event.data.source) || this.#startsWithAllowed(event.data.type)))
|
|
2424
|
+
return false;
|
|
2425
|
+
// Accept messages from trusted origins
|
|
2426
|
+
this.#customEventsTrustedOrigins.push(window.location.origin);
|
|
2427
|
+
const isFromTrustedOrigin = this.#customEventsTrustedOrigins.includes(event.origin);
|
|
2428
|
+
const hasValidStructure = event.data && (event.data.type || event.data.eventType) && typeof event.data === 'object';
|
|
2429
|
+
return isFromTrustedOrigin && hasValidStructure;
|
|
2549
2430
|
}
|
|
2550
|
-
|
|
2551
|
-
|
|
2431
|
+
#listenToWindowEvents() {
|
|
2432
|
+
window.addEventListener('message', (event) => {
|
|
2433
|
+
this.#ngZone.run(() => this.#isValidExternalMessage(event) && this.trigger(event.data.type, event.data.data));
|
|
2434
|
+
});
|
|
2552
2435
|
}
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2436
|
+
/**
|
|
2437
|
+
* Triggers a postMessage event that will be sent to the yuuvis global event Trigger
|
|
2438
|
+
* @param type Type/key of the event
|
|
2439
|
+
* @param data Data to be sent along with the event
|
|
2440
|
+
*/
|
|
2441
|
+
triggerPostMessageEvent(type, data) {
|
|
2442
|
+
const targetOrigin = window.location.origin;
|
|
2443
|
+
const payload = {
|
|
2444
|
+
type,
|
|
2445
|
+
data,
|
|
2446
|
+
timestamp: Date.now()
|
|
2564
2447
|
};
|
|
2565
|
-
|
|
2566
|
-
res.title = {
|
|
2567
|
-
propertyName: oc.title.propertyName,
|
|
2568
|
-
value: data[oc.title.propertyName]
|
|
2569
|
-
};
|
|
2570
|
-
if (oc.description)
|
|
2571
|
-
res.description = {
|
|
2572
|
-
propertyName: oc.description.propertyName,
|
|
2573
|
-
value: data[oc.description.propertyName]
|
|
2574
|
-
};
|
|
2575
|
-
if (oc.icon)
|
|
2576
|
-
res.icon = {
|
|
2577
|
-
propertyName: 'custom',
|
|
2578
|
-
value: oc.icon.svg
|
|
2579
|
-
};
|
|
2580
|
-
if (oc.meta)
|
|
2581
|
-
res.meta = {
|
|
2582
|
-
propertyName: oc.meta.propertyName,
|
|
2583
|
-
value: data[oc.meta.propertyName]
|
|
2584
|
-
};
|
|
2585
|
-
if (oc.aside)
|
|
2586
|
-
res.aside = {
|
|
2587
|
-
propertyName: oc.aside.propertyName,
|
|
2588
|
-
value: data[oc.aside.propertyName]
|
|
2589
|
-
};
|
|
2590
|
-
return res;
|
|
2448
|
+
window.postMessage(payload, targetOrigin);
|
|
2591
2449
|
}
|
|
2592
2450
|
/**
|
|
2593
|
-
*
|
|
2594
|
-
*
|
|
2451
|
+
* Trigger an global event
|
|
2452
|
+
* @param type Type/key of the event
|
|
2453
|
+
* @param data Data to be send along with the event
|
|
2595
2454
|
*/
|
|
2596
|
-
|
|
2597
|
-
this.#
|
|
2598
|
-
this.#defaultObjectConfigs[ot.id] = {
|
|
2599
|
-
objectTypeId: ot.id,
|
|
2600
|
-
title: this.#toObjectProperty(ot.fields[0]),
|
|
2601
|
-
description: this.#toObjectProperty(ot.fields[1]),
|
|
2602
|
-
meta: this.#toObjectProperty(ot.fields[2]),
|
|
2603
|
-
aside: this.#toObjectProperty(ot.fields[3])
|
|
2604
|
-
};
|
|
2605
|
-
});
|
|
2455
|
+
trigger(type, ...args) {
|
|
2456
|
+
this.#eventSource.next({ type: type, data: args[0] });
|
|
2606
2457
|
}
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
: undefined;
|
|
2458
|
+
/**
|
|
2459
|
+
* Listen on a triggered event
|
|
2460
|
+
* @param types Type/key of the event
|
|
2461
|
+
*/
|
|
2462
|
+
on(...types) {
|
|
2463
|
+
return this.event$.pipe(filter((event) => event && !!types.find((t) => t === event.type)));
|
|
2614
2464
|
}
|
|
2615
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type:
|
|
2616
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type:
|
|
2465
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: EventService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2466
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: EventService, providedIn: 'root' }); }
|
|
2617
2467
|
}
|
|
2618
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type:
|
|
2468
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: EventService, decorators: [{
|
|
2619
2469
|
type: Injectable,
|
|
2620
2470
|
args: [{
|
|
2621
2471
|
providedIn: 'root'
|
|
2622
2472
|
}]
|
|
2623
|
-
}] });
|
|
2624
|
-
|
|
2625
|
-
const YUV_USER = new InjectionToken('Currently logged in user', {
|
|
2626
|
-
factory: () => undefined
|
|
2627
|
-
});
|
|
2628
|
-
const provideUser = (user) => {
|
|
2629
|
-
return { provide: YUV_USER, useValue: user };
|
|
2630
|
-
};
|
|
2473
|
+
}], ctorParameters: () => [] });
|
|
2631
2474
|
|
|
2632
2475
|
/**
|
|
2633
|
-
*
|
|
2476
|
+
* Events emitted by parts of the application
|
|
2634
2477
|
*/
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
this.#eventService = inject(EventService);
|
|
2655
|
-
this.#userService = inject(UserService);
|
|
2656
|
-
this.#objectConfigService = inject(ObjectConfigService);
|
|
2657
|
-
this.#appCache = inject(AppCacheService);
|
|
2658
|
-
this.#systemService = inject(SystemService);
|
|
2659
|
-
this.#localizationService = inject(LocalizationService);
|
|
2478
|
+
var YuvEventType;
|
|
2479
|
+
(function (YuvEventType) {
|
|
2480
|
+
YuvEventType["LOGOUT"] = "yuv.user.logout";
|
|
2481
|
+
YuvEventType["CLIENT_LOCALE_CHANGED"] = "yuv.user.locale.client.changed";
|
|
2482
|
+
YuvEventType["DMS_OBJECT_LOADED"] = "yuv.dms.object.loaded";
|
|
2483
|
+
YuvEventType["DMS_OBJECT_CREATED"] = "yuv.dms.object.created";
|
|
2484
|
+
YuvEventType["DMS_OBJECT_DELETED"] = "yuv.dms.object.deleted";
|
|
2485
|
+
YuvEventType["DMS_OBJECT_UPDATED"] = "yuv.dms.object.updated";
|
|
2486
|
+
YuvEventType["DMS_OBJECT_CONTENT_UPDATED"] = "yuv.dms.object.content.updated";
|
|
2487
|
+
YuvEventType["DMS_OBJECTS_MOVED"] = "yuv.dms.objects.moved";
|
|
2488
|
+
YuvEventType["RELATIONSHIP_CREATED"] = "yuv.dms.relationship.created";
|
|
2489
|
+
YuvEventType["RELATIONSHIP_DELETED"] = "yuv.dms.relationship.deleted";
|
|
2490
|
+
})(YuvEventType || (YuvEventType = {}));
|
|
2491
|
+
|
|
2492
|
+
/**
|
|
2493
|
+
* Service providing user account configurations.
|
|
2494
|
+
*/
|
|
2495
|
+
class UserService {
|
|
2496
|
+
constructor() {
|
|
2660
2497
|
this.#backend = inject(BackendService);
|
|
2661
|
-
this.#
|
|
2662
|
-
this.#
|
|
2663
|
-
this.#
|
|
2664
|
-
this.#
|
|
2665
|
-
this
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2498
|
+
this.#translate = inject(TranslateService);
|
|
2499
|
+
this.#logger = inject(Logger);
|
|
2500
|
+
this.#system = inject(SystemService);
|
|
2501
|
+
this.#localization = inject(LocalizationService);
|
|
2502
|
+
this.#eventService = inject(EventService);
|
|
2503
|
+
this.#config = inject(ConfigService);
|
|
2504
|
+
this.#document = inject(DOCUMENT);
|
|
2505
|
+
this.#USERS_SETTINGS = '/users/settings/';
|
|
2506
|
+
this.#DEFAULT_SETTINGS = '/users/settings';
|
|
2507
|
+
this.#SETTINGS_SECTION_OBJECTCONFIG = 'object-config';
|
|
2508
|
+
this.#userSource = new BehaviorSubject(this.#user);
|
|
2509
|
+
this.user$ = this.#userSource.asObservable();
|
|
2510
|
+
this.globalSettings = new Map();
|
|
2511
|
+
this.canCreateObjects = false;
|
|
2669
2512
|
}
|
|
2513
|
+
#backend;
|
|
2514
|
+
#translate;
|
|
2515
|
+
#logger;
|
|
2516
|
+
#system;
|
|
2517
|
+
#localization;
|
|
2518
|
+
#eventService;
|
|
2519
|
+
#config;
|
|
2520
|
+
#document;
|
|
2521
|
+
#USERS_SETTINGS;
|
|
2522
|
+
#DEFAULT_SETTINGS;
|
|
2523
|
+
#SETTINGS_SECTION_OBJECTCONFIG;
|
|
2524
|
+
#user;
|
|
2525
|
+
#userSource;
|
|
2670
2526
|
/**
|
|
2671
|
-
*
|
|
2672
|
-
* @
|
|
2527
|
+
* Set a new current user
|
|
2528
|
+
* @param user The user to be set as current user
|
|
2673
2529
|
*/
|
|
2674
|
-
|
|
2675
|
-
|
|
2530
|
+
setCurrentUser(user) {
|
|
2531
|
+
this.#user = user;
|
|
2532
|
+
this.changeClientLocale('', false);
|
|
2533
|
+
this.#userSource.next(this.#user);
|
|
2676
2534
|
}
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
*/
|
|
2680
|
-
getTenant() {
|
|
2681
|
-
return this.#authData?.tenant;
|
|
2535
|
+
getCurrentUser() {
|
|
2536
|
+
return this.#user;
|
|
2682
2537
|
}
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
*/
|
|
2686
|
-
fetchUser() {
|
|
2687
|
-
return (this.#userToken ? of(this.#userToken) : this.#backend.get(this.#USER_FETCH_URI)).pipe(tap(() => {
|
|
2688
|
-
this.#authenticated = true;
|
|
2689
|
-
this.#authSource.next(this.#authenticated);
|
|
2690
|
-
}), switchMap((userJson) => this.#initApp(userJson)));
|
|
2538
|
+
get hasAdminRole() {
|
|
2539
|
+
return this.#user?.authorities?.includes(AdministrationRoles.ADMIN) || false;
|
|
2691
2540
|
}
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
this
|
|
2697
|
-
|
|
2698
|
-
|
|
2541
|
+
get hasSystemRole() {
|
|
2542
|
+
return this.#user?.authorities?.includes(AdministrationRoles.SYSTEM) || false;
|
|
2543
|
+
}
|
|
2544
|
+
get hasAdministrationRoles() {
|
|
2545
|
+
return this.hasAdminRole || this.hasSystemRole;
|
|
2546
|
+
}
|
|
2547
|
+
get hasManageSettingsRole() {
|
|
2548
|
+
const customRole = this.#config.get('core.permissions.manageSettingsRole');
|
|
2549
|
+
const manageSettingsRole = customRole || AdministrationRoles.MANAGE_SETTINGS;
|
|
2550
|
+
return this.#user?.authorities?.includes(manageSettingsRole) || false;
|
|
2551
|
+
}
|
|
2552
|
+
get isAdvancedUser() {
|
|
2553
|
+
const customRole = this.#config.get('core.permissions.advancedUserRole');
|
|
2554
|
+
const advancedUserRole = customRole || AdministrationRoles.MANAGE_SETTINGS;
|
|
2555
|
+
return this.#user?.authorities?.includes(advancedUserRole) || false;
|
|
2556
|
+
}
|
|
2557
|
+
get isRetentionManager() {
|
|
2558
|
+
const customRole = this.#config.get('core.permissions.retentionManagerRole');
|
|
2559
|
+
const retenetionManagerRole = customRole || AdministrationRoles.MANAGE_SETTINGS;
|
|
2560
|
+
return this.#user?.authorities?.includes(retenetionManagerRole) || false;
|
|
2699
2561
|
}
|
|
2700
2562
|
/**
|
|
2701
|
-
*
|
|
2702
|
-
*
|
|
2703
|
-
* This is done on app initialization (core-init).
|
|
2563
|
+
* Change the users client locale
|
|
2564
|
+
* @param iso ISO locale string to be set as new client locale
|
|
2704
2565
|
*/
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2566
|
+
changeClientLocale(iso, persist = true) {
|
|
2567
|
+
if (this.#user) {
|
|
2568
|
+
const languages = this.#config.getClientLocales().map((lang) => lang.iso);
|
|
2569
|
+
iso = iso || this.#user.getClientLocale(this.#config.getDefaultClientLocale());
|
|
2570
|
+
if (!languages.includes(iso)) {
|
|
2571
|
+
iso = this.#config.getDefaultClientLocale();
|
|
2572
|
+
}
|
|
2573
|
+
this.#logger.debug("Changed client locale to '" + iso + "'");
|
|
2574
|
+
this.#backend.setHeader('Accept-Language', iso);
|
|
2575
|
+
this.#user.uiDirection = this.#getUiDirection(iso);
|
|
2576
|
+
this.#document.body.dir = this.#user.uiDirection;
|
|
2577
|
+
this.#document.documentElement.lang = iso;
|
|
2578
|
+
this.#user.userSettings.locale = iso;
|
|
2579
|
+
if (this.#translate.getCurrentLang() !== iso || this.#system.authData?.language !== iso) {
|
|
2580
|
+
const obs = persist
|
|
2581
|
+
? forkJoin([
|
|
2582
|
+
this.#translate.use(iso),
|
|
2583
|
+
this.#system
|
|
2584
|
+
.updateAuthData({ language: iso })
|
|
2585
|
+
.pipe(switchMap(() => this.#localization.fetchLocalizations())),
|
|
2586
|
+
this.saveUserSettings(this.#user.userSettings).pipe(tap(() => {
|
|
2587
|
+
this.#logger.debug('Loading system definitions i18n resources for new locale.');
|
|
2588
|
+
}))
|
|
2589
|
+
])
|
|
2590
|
+
: this.#translate.use(iso);
|
|
2591
|
+
obs.subscribe(() => this.#eventService.trigger(YuvEventType.CLIENT_LOCALE_CHANGED, iso));
|
|
2592
|
+
}
|
|
2719
2593
|
}
|
|
2720
|
-
return of(false);
|
|
2721
2594
|
}
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2595
|
+
saveUserSettings(settings) {
|
|
2596
|
+
if (this.#user) {
|
|
2597
|
+
//console.log(this.#user.userSettings);
|
|
2598
|
+
this.#user.userSettings = { ...this.#user.userSettings, ...settings };
|
|
2599
|
+
return this.#backend
|
|
2600
|
+
.post(this.#DEFAULT_SETTINGS, this.#user.userSettings)
|
|
2601
|
+
.pipe(tap(() => this.#userSource.next(this.#user)));
|
|
2602
|
+
}
|
|
2603
|
+
else
|
|
2604
|
+
return of(null);
|
|
2728
2605
|
}
|
|
2729
|
-
|
|
2730
|
-
return this.#
|
|
2606
|
+
fetchUserSettings() {
|
|
2607
|
+
return this.#backend.get('/dms/permissions').pipe(catchError(() => of(undefined)), switchMap((res) => {
|
|
2608
|
+
this.#setUserPermissions(res);
|
|
2609
|
+
return this.#backend.get(this.#DEFAULT_SETTINGS);
|
|
2610
|
+
}));
|
|
2731
2611
|
}
|
|
2732
2612
|
/**
|
|
2733
|
-
*
|
|
2734
|
-
*
|
|
2735
|
-
* @param
|
|
2613
|
+
* Search for a user based on a search term
|
|
2614
|
+
* @param term Search term
|
|
2615
|
+
* @param excludeMe whether or not to exclude myself from the result list
|
|
2616
|
+
* @param roles narrow down the search results by certain roles
|
|
2736
2617
|
*/
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
language: currentUser.getClientLocale()
|
|
2744
|
-
};
|
|
2745
|
-
return forkJoin([
|
|
2746
|
-
this.#localizationService.fetchLocalizations(),
|
|
2747
|
-
this.#systemService.getSystemDefinition(this.#authData)
|
|
2748
|
-
]).pipe(switchMap(() => this.#objectConfigService.init()), map(() => currentUser));
|
|
2749
|
-
}));
|
|
2618
|
+
queryUser(term, excludeMe, roles) {
|
|
2619
|
+
let params = new HttpParams().set('search', term).set('excludeMe', `${!!excludeMe}`);
|
|
2620
|
+
roles?.length && roles.map((r) => (params = params.append(`roles`, r)));
|
|
2621
|
+
return this.#backend
|
|
2622
|
+
.get(`/idm/users?${params}`)
|
|
2623
|
+
.pipe(map((users) => (!users ? [] : users.map((u) => new YuvUser(u)))));
|
|
2750
2624
|
}
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
}
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2625
|
+
getUserById(id) {
|
|
2626
|
+
return this.#backend.get(`/idm/users/${id}`).pipe(map((user) => new YuvUser(user, this.#user.userSettings)));
|
|
2627
|
+
}
|
|
2628
|
+
logout(redirRoute) {
|
|
2629
|
+
const redir = redirRoute ? `?redir=${redirRoute}` : '';
|
|
2630
|
+
window.location.href = `${this.#backend.getApiBase('logout')}${redir}`;
|
|
2631
|
+
}
|
|
2632
|
+
getSettings(section) {
|
|
2633
|
+
return this.#user ? this.#backend.get(this.#USERS_SETTINGS + encodeURIComponent(section)) : of(null);
|
|
2634
|
+
}
|
|
2635
|
+
saveObjectConfig(objectConfigs) {
|
|
2636
|
+
return this.#backend.post(this.#USERS_SETTINGS + encodeURIComponent(this.#SETTINGS_SECTION_OBJECTCONFIG), objectConfigs);
|
|
2637
|
+
}
|
|
2638
|
+
loadObjectConfig() {
|
|
2639
|
+
return this.getSettings(this.#SETTINGS_SECTION_OBJECTCONFIG).pipe(catchError(() => of(undefined)));
|
|
2640
|
+
}
|
|
2641
|
+
#getUiDirection(iso) {
|
|
2642
|
+
// languages that are read right to left
|
|
2643
|
+
const rtlLanguages = ['ar', 'arc', 'dv', 'fa', 'ha', 'he', 'khw', 'ks', 'ku', 'ps', 'ur', 'yi'];
|
|
2644
|
+
return !rtlLanguages.includes(iso) ? Direction.LTR : Direction.RTL;
|
|
2645
|
+
}
|
|
2646
|
+
#setUserPermissions(res) {
|
|
2647
|
+
this.userPermissions = {
|
|
2648
|
+
create: this.#mapPermissions('CREATE', res),
|
|
2649
|
+
write: this.#mapPermissions('WRITE', res),
|
|
2650
|
+
read: this.#mapPermissions('READ', res),
|
|
2651
|
+
delete: this.#mapPermissions('DELETE', res)
|
|
2652
|
+
};
|
|
2653
|
+
const permissions = {
|
|
2654
|
+
createableObjectTypes: [
|
|
2655
|
+
...this.userPermissions.create.folderTypes,
|
|
2656
|
+
...this.userPermissions.create.objectTypes,
|
|
2657
|
+
...this.userPermissions.create.secondaryObjectTypes
|
|
2658
|
+
],
|
|
2659
|
+
searchableObjectTypes: [
|
|
2660
|
+
...this.userPermissions.read.folderTypes,
|
|
2661
|
+
...this.userPermissions.read.objectTypes,
|
|
2662
|
+
...this.userPermissions.read.secondaryObjectTypes
|
|
2663
|
+
]
|
|
2664
|
+
};
|
|
2665
|
+
this.#system.setPermissions(permissions);
|
|
2666
|
+
this.canCreateObjects = permissions.createableObjectTypes.length > 0;
|
|
2667
|
+
}
|
|
2668
|
+
#mapPermissions(section, apiResponse) {
|
|
2669
|
+
const res = apiResponse[section] || {};
|
|
2670
|
+
return {
|
|
2671
|
+
folderTypes: res['folderTypeIds'] || [],
|
|
2672
|
+
objectTypes: res['objectTypeIds'] || [],
|
|
2673
|
+
secondaryObjectTypes: res['secondaryObjectTypeIds'] || []
|
|
2674
|
+
};
|
|
2675
|
+
}
|
|
2676
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UserService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2677
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UserService, providedIn: 'root' }); }
|
|
2785
2678
|
}
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
})(LoginStateName || (LoginStateName = {}));
|
|
2679
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UserService, decorators: [{
|
|
2680
|
+
type: Injectable,
|
|
2681
|
+
args: [{
|
|
2682
|
+
providedIn: 'root'
|
|
2683
|
+
}]
|
|
2684
|
+
}] });
|
|
2793
2685
|
|
|
2794
2686
|
/**
|
|
2795
|
-
* Service to
|
|
2796
|
-
*
|
|
2797
|
-
*
|
|
2798
|
-
*
|
|
2799
|
-
*
|
|
2800
|
-
* whenever the online or offline state changes. The initial state is determined by
|
|
2801
|
-
* the `window.navigator.onLine` property.
|
|
2687
|
+
* Service providing access to the systems audit entries. Audits can be seen as the history of
|
|
2688
|
+
* an object. Actions perormed on an object (eg. read, write, delete, ...) will be recorded during
|
|
2689
|
+
* the objects lifecycle. Audits are provided based on a users permissions. Beside the audit entries
|
|
2690
|
+
* visible to regular users there are more technical ones that will only be shown to users that
|
|
2691
|
+
* have administrative role.
|
|
2802
2692
|
*/
|
|
2803
|
-
class
|
|
2693
|
+
class AuditService {
|
|
2694
|
+
constructor() {
|
|
2695
|
+
this.#searchService = inject(SearchService);
|
|
2696
|
+
this.#userService = inject(UserService);
|
|
2697
|
+
// default number of items to be fetched
|
|
2698
|
+
this.DEFAULT_RES_SIZE = 20;
|
|
2699
|
+
// audit action codes that should be visible to regular users
|
|
2700
|
+
this.userAuditActions = [
|
|
2701
|
+
100, // metadata created
|
|
2702
|
+
101, // metadata created (with content)
|
|
2703
|
+
110, // tag created
|
|
2704
|
+
201, // content deleted
|
|
2705
|
+
210, // tag deleted
|
|
2706
|
+
300, // metadata updated
|
|
2707
|
+
301, // content updated
|
|
2708
|
+
302, // metadata and content updated
|
|
2709
|
+
303, // content moved
|
|
2710
|
+
310, // tag updated
|
|
2711
|
+
325, // object restored form version
|
|
2712
|
+
340, // object moved
|
|
2713
|
+
10000 // custom audit entries
|
|
2714
|
+
];
|
|
2715
|
+
// audit action codes that should be visible to admin users
|
|
2716
|
+
this.adminAuditActions = [
|
|
2717
|
+
202, // marked for delete
|
|
2718
|
+
220, // version deleted
|
|
2719
|
+
400, // content read
|
|
2720
|
+
401, // metadata read
|
|
2721
|
+
402, // rendition read (text)
|
|
2722
|
+
403, // rendition read (pdf)
|
|
2723
|
+
404 // rendition read (thumbnail)
|
|
2724
|
+
];
|
|
2725
|
+
}
|
|
2726
|
+
#searchService;
|
|
2727
|
+
#userService;
|
|
2804
2728
|
/**
|
|
2805
|
-
*
|
|
2729
|
+
* Get audit entries of a dms object
|
|
2730
|
+
* @param id The id of the object to get the audit entries for
|
|
2731
|
+
* @param options Options
|
|
2806
2732
|
*/
|
|
2807
|
-
|
|
2808
|
-
this.
|
|
2809
|
-
|
|
2733
|
+
getAuditEntries(id, options = {}) {
|
|
2734
|
+
const auditActions = this.getAuditActions(!!options.allActions, options?.skipActions);
|
|
2735
|
+
const q = {
|
|
2736
|
+
size: this.DEFAULT_RES_SIZE,
|
|
2737
|
+
types: [SystemType.AUDIT],
|
|
2738
|
+
filters: [
|
|
2739
|
+
{
|
|
2740
|
+
f: AuditField.REFERRED_OBJECT_ID,
|
|
2741
|
+
o: Operator.EQUAL,
|
|
2742
|
+
v1: id
|
|
2743
|
+
},
|
|
2744
|
+
{
|
|
2745
|
+
f: AuditField.ACTION,
|
|
2746
|
+
o: Operator.IN,
|
|
2747
|
+
v1: auditActions
|
|
2748
|
+
}
|
|
2749
|
+
],
|
|
2750
|
+
sort: [
|
|
2751
|
+
{
|
|
2752
|
+
field: AuditField.CREATION_DATE,
|
|
2753
|
+
order: 'desc'
|
|
2754
|
+
}
|
|
2755
|
+
]
|
|
2810
2756
|
};
|
|
2811
|
-
this
|
|
2812
|
-
this.connection$ = this.connectionStateSource.asObservable();
|
|
2813
|
-
this.connectionStateSource.next(this.currentState);
|
|
2814
|
-
fromEvent(window, 'online').subscribe(() => {
|
|
2815
|
-
this.currentState.isOnline = true;
|
|
2816
|
-
this.connectionStateSource.next(this.currentState);
|
|
2817
|
-
});
|
|
2818
|
-
fromEvent(window, 'offline').subscribe(() => {
|
|
2819
|
-
this.currentState.isOnline = false;
|
|
2820
|
-
this.connectionStateSource.next(this.currentState);
|
|
2821
|
-
});
|
|
2757
|
+
return this.#fetchAudits(q);
|
|
2822
2758
|
}
|
|
2823
|
-
|
|
2824
|
-
|
|
2759
|
+
/**
|
|
2760
|
+
* Get an array of action codes that are provided by the service. Based on
|
|
2761
|
+
* whether or not the user has admin permissions you'll get a different
|
|
2762
|
+
* set of actions.
|
|
2763
|
+
* @param skipActions codes of actions that should not be fetched
|
|
2764
|
+
*/
|
|
2765
|
+
getAuditActions(allActions, skipActions) {
|
|
2766
|
+
const actions = allActions || this.#userService.isAdvancedUser ? [...this.userAuditActions, ...this.adminAuditActions] : this.userAuditActions;
|
|
2767
|
+
return actions.filter((a) => !skipActions || !skipActions.includes(a));
|
|
2768
|
+
}
|
|
2769
|
+
/**
|
|
2770
|
+
* Get a certain page for a former audits query.
|
|
2771
|
+
* @param auditsResult The result object of a former audits query
|
|
2772
|
+
* @param page The page to load
|
|
2773
|
+
*/
|
|
2774
|
+
getPage(auditsResult, page) {
|
|
2775
|
+
const q = auditsResult.query;
|
|
2776
|
+
q.from = (page - 1) * (q.size || this.DEFAULT_RES_SIZE);
|
|
2777
|
+
return this.#fetchAudits(q);
|
|
2778
|
+
}
|
|
2779
|
+
#fetchAudits(q) {
|
|
2780
|
+
return this.#searchService.searchRaw(q).pipe(map((res) => ({
|
|
2781
|
+
query: q,
|
|
2782
|
+
items: res.objects.map((o) => ({
|
|
2783
|
+
action: o.properties[AuditField.ACTION].value,
|
|
2784
|
+
actionGroup: this.#getActionGroup(o.properties[AuditField.ACTION].value),
|
|
2785
|
+
detail: o.properties[AuditField.DETAIL].value,
|
|
2786
|
+
subaction: o.properties[AuditField.SUBACTION] ? o.properties[AuditField.SUBACTION].value : null,
|
|
2787
|
+
version: o.properties[AuditField.VERSION].value,
|
|
2788
|
+
creationDate: o.properties[AuditField.CREATION_DATE].value,
|
|
2789
|
+
createdBy: {
|
|
2790
|
+
id: o.properties[AuditField.CREATED_BY].value,
|
|
2791
|
+
title: o.properties[AuditField.CREATED_BY].title
|
|
2792
|
+
}
|
|
2793
|
+
})),
|
|
2794
|
+
hasMoreItems: res.hasMoreItems,
|
|
2795
|
+
page: !q.from ? 1 : q.from / q.size + 1
|
|
2796
|
+
})));
|
|
2797
|
+
}
|
|
2798
|
+
#getActionGroup(action) {
|
|
2799
|
+
try {
|
|
2800
|
+
return parseInt(`${action}`.substr(0, 1));
|
|
2801
|
+
}
|
|
2802
|
+
catch {
|
|
2803
|
+
return -1;
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2806
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AuditService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2807
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AuditService, providedIn: 'root' }); }
|
|
2825
2808
|
}
|
|
2826
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type:
|
|
2809
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AuditService, decorators: [{
|
|
2827
2810
|
type: Injectable,
|
|
2828
2811
|
args: [{
|
|
2829
2812
|
providedIn: 'root'
|
|
2830
2813
|
}]
|
|
2831
|
-
}]
|
|
2832
|
-
|
|
2833
|
-
/**
|
|
2834
|
-
* Http Offline interceptor trys to serving offline content for method/url
|
|
2835
|
-
*/
|
|
2836
|
-
function OfflineInterceptorFnc(req, next) {
|
|
2837
|
-
return next(req);
|
|
2838
|
-
}
|
|
2814
|
+
}] });
|
|
2839
2815
|
|
|
2840
2816
|
/**
|
|
2841
|
-
*
|
|
2817
|
+
* @ignore
|
|
2842
2818
|
*/
|
|
2843
|
-
const
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
const configService = inject(ConfigService);
|
|
2848
|
-
const authService = inject(AuthService);
|
|
2849
|
-
return authService.setInitialRequestUri().pipe(switchMap(() => coreConfig.main
|
|
2850
|
-
? !Array.isArray(coreConfig.main)
|
|
2851
|
-
? of([coreConfig.main])
|
|
2852
|
-
: forkJoin([...coreConfig.main].map((uri) => http.get(`${Utils.getBaseHref()}${uri}`).pipe(catchError((e) => {
|
|
2853
|
-
logger.error('failed to catch config file', e);
|
|
2854
|
-
return of({});
|
|
2855
|
-
}), map((res) => res)))).pipe(
|
|
2856
|
-
// switchMap((configs: YuvConfig[]) => configService.extendConfig(configs)),
|
|
2857
|
-
tap((configs) => configService.extendConfig(configs)), switchMap(() => authService.initUser().pipe(catchError((e) => {
|
|
2858
|
-
authService.initError = {
|
|
2859
|
-
status: e.status,
|
|
2860
|
-
key: e.error.error
|
|
2861
|
-
};
|
|
2862
|
-
return of(true);
|
|
2863
|
-
}))))
|
|
2864
|
-
: of(false)));
|
|
2865
|
-
};
|
|
2819
|
+
const CUSTOM_CONFIG = new InjectionToken('CUSTOM_CONFIG', {
|
|
2820
|
+
factory: () => ({ main: ['assets/_yuuvis/config/main.json'], translations: ['assets/_yuuvis/i18n/'] })
|
|
2821
|
+
});
|
|
2822
|
+
const CORE_CONFIG = new InjectionToken('CORE_CONFIG');
|
|
2866
2823
|
|
|
2867
2824
|
/**
|
|
2868
|
-
* Handles missing translations
|
|
2869
2825
|
* @ignore
|
|
2870
2826
|
*/
|
|
2871
|
-
class
|
|
2872
|
-
|
|
2873
|
-
|
|
2827
|
+
let CoreConfig = class CoreConfig {
|
|
2828
|
+
constructor(__config) {
|
|
2829
|
+
this.main = ['assets/_yuuvis/config/main.json'];
|
|
2830
|
+
this.translations = ['assets/_yuuvis/i18n/'];
|
|
2831
|
+
this.environment = { production: true };
|
|
2832
|
+
Object.assign(this, __config);
|
|
2874
2833
|
}
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
}] });
|
|
2834
|
+
};
|
|
2835
|
+
CoreConfig = __decorate([
|
|
2836
|
+
__param(0, Inject(CUSTOM_CONFIG)),
|
|
2837
|
+
__metadata("design:paramtypes", [CoreConfig])
|
|
2838
|
+
], CoreConfig);
|
|
2881
2839
|
|
|
2882
2840
|
/**
|
|
2883
|
-
*
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
* Loader that fetches translations based on the configured locations
|
|
2887
|
-
* @ignore
|
|
2841
|
+
* Service managing the configuarions for object types.
|
|
2842
|
+
* Configuration means that you can pick certain fields
|
|
2843
|
+
* of an object type and assign them to a config object.
|
|
2888
2844
|
*/
|
|
2889
|
-
class
|
|
2890
|
-
constructor(
|
|
2891
|
-
this
|
|
2892
|
-
this
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
registerLocaleData(localeJa, 'ja', localeExtraJa); // Japanese
|
|
2906
|
-
registerLocaleData(localeKo, 'ko', localeExtraKo); // Korean
|
|
2907
|
-
registerLocaleData(localeHi, 'hi', localeExtraHi); // Hindi
|
|
2908
|
-
registerLocaleData(localeBn, 'bn', localeExtraBn); // Bengalese
|
|
2909
|
-
registerLocaleData(localeVi, 'vi', localeExtraVi); // Vietnamese
|
|
2910
|
-
registerLocaleData(localeTr, 'tr', localeExtraTr); // Turkish
|
|
2911
|
-
registerLocaleData(localeNl, 'nl', localeExtraNl); // Dutch
|
|
2912
|
-
registerLocaleData(localeNb, 'nb', localeExtraNb); // Norwegian
|
|
2913
|
-
registerLocaleData(localeTh, 'th', localeExtraTh); // Thai
|
|
2914
|
-
registerLocaleData(localeFi, 'fi', localeExtraFi); // Finnish
|
|
2915
|
-
registerLocaleData(localeSv, 'sv', localeExtraSv); // Swedish
|
|
2916
|
-
registerLocaleData(localeDeCh, 'de-CH', localeExtraDeCh); // German Swiss
|
|
2845
|
+
class ObjectConfigService {
|
|
2846
|
+
constructor() {
|
|
2847
|
+
this.#system = inject(SystemService);
|
|
2848
|
+
this.#user = inject(UserService);
|
|
2849
|
+
this.OBJECT_CONFIG_STORAGE_KEY = 'yuv.framework.object-config';
|
|
2850
|
+
this.#objectConfigsSource = new ReplaySubject();
|
|
2851
|
+
this.#objectConfigs$ = this.#objectConfigsSource.asObservable();
|
|
2852
|
+
this.#defaultObjectConfigs = {};
|
|
2853
|
+
this.#registeredDefaultObjectConfigs = {
|
|
2854
|
+
main: {},
|
|
2855
|
+
buckets: []
|
|
2856
|
+
};
|
|
2857
|
+
this.#objectConfigs = {
|
|
2858
|
+
main: {},
|
|
2859
|
+
buckets: []
|
|
2860
|
+
};
|
|
2917
2861
|
}
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2862
|
+
#system;
|
|
2863
|
+
#user;
|
|
2864
|
+
#objectConfigsSource;
|
|
2865
|
+
#objectConfigs$;
|
|
2866
|
+
#defaultObjectConfigs;
|
|
2867
|
+
#registeredDefaultObjectConfigs;
|
|
2868
|
+
#objectConfigs;
|
|
2869
|
+
#isValidObjectConfig(soc) {
|
|
2870
|
+
return coerceBooleanProperty(soc && Object.hasOwn(soc, 'main') && Object.hasOwn(soc, 'buckets'));
|
|
2926
2871
|
}
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2872
|
+
// called on core init (auth.service -> initApp)
|
|
2873
|
+
init() {
|
|
2874
|
+
return this.#user.loadObjectConfig().pipe(tap$1((res) => {
|
|
2875
|
+
this.#getDefaultObjectConfig();
|
|
2876
|
+
this.#objectConfigs = (this.#isValidObjectConfig(res) && res) || {
|
|
2877
|
+
main: {},
|
|
2878
|
+
buckets: []
|
|
2879
|
+
};
|
|
2880
|
+
this.#objectConfigsSource.next(this.#objectConfigs);
|
|
2935
2881
|
}));
|
|
2936
2882
|
}
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
Operator["GREATER_OR_EQUAL"] = "gte";
|
|
2954
|
-
Operator["LESS_THAN"] = "lt";
|
|
2955
|
-
Operator["LESS_OR_EQUAL"] = "lte";
|
|
2956
|
-
Operator["INTERVAL"] = "gtlt";
|
|
2957
|
-
Operator["INTERVAL_INCLUDE_BOTH"] = "gtelte";
|
|
2958
|
-
Operator["INTERVAL_INCLUDE_TO"] = "gtlte";
|
|
2959
|
-
Operator["INTERVAL_INCLUDE_FROM"] = "gtelt";
|
|
2960
|
-
Operator["RANGE"] = "rg";
|
|
2961
|
-
Operator["LIKE"] = "like";
|
|
2962
|
-
Operator["CONTAINS"] = "contains"; // contains
|
|
2963
|
-
})(Operator || (Operator = {}));
|
|
2964
|
-
const OperatorLabel = {
|
|
2965
|
-
/** equal */
|
|
2966
|
-
EQUAL: '=',
|
|
2967
|
-
/** exact equal */
|
|
2968
|
-
EEQUAL: '==',
|
|
2969
|
-
/** match at least one of the provided values (value has to be an array) */
|
|
2970
|
-
IN: '~',
|
|
2971
|
-
/** greater than */
|
|
2972
|
-
GREATER_THAN: '>',
|
|
2973
|
-
/** greater than or equal */
|
|
2974
|
-
GREATER_OR_EQUAL: '≽', //
|
|
2975
|
-
LESS_THAN: '<', // less than
|
|
2976
|
-
LESS_OR_EQUAL: '≼', // less than or equal
|
|
2977
|
-
INTERVAL: '<>', // interval
|
|
2978
|
-
INTERVAL_INCLUDE_BOTH: '-', // interval include left and right
|
|
2979
|
-
INTERVAL_INCLUDE_TO: '>-', // interval include right
|
|
2980
|
-
INTERVAL_INCLUDE_FROM: '-<', // interval include left
|
|
2981
|
-
RANGE: '=', // aggegation ranges
|
|
2982
|
-
LIKE: '~', // like
|
|
2983
|
-
CONTAINS: '~' // contains
|
|
2984
|
-
};
|
|
2985
|
-
|
|
2986
|
-
class SearchService {
|
|
2987
|
-
#backend = inject(BackendService);
|
|
2988
|
-
#system = inject(SystemService);
|
|
2989
|
-
static { this.DEFAULT_QUERY_SIZE = 50; }
|
|
2990
|
-
/**
|
|
2991
|
-
* Execute a search query ans transform the result to a SearchResult object
|
|
2992
|
-
* @param query The search query
|
|
2993
|
-
* @returns Observable of a SearchResult
|
|
2994
|
-
*/
|
|
2995
|
-
search(query) {
|
|
2996
|
-
return this.searchRaw(query).pipe(map((res) => this.toSearchResult(res, query.size || SearchService.DEFAULT_QUERY_SIZE, query.from || 0)));
|
|
2997
|
-
}
|
|
2998
|
-
/**
|
|
2999
|
-
* Execute a raw search query and return the result as is.
|
|
3000
|
-
* @param query The search query
|
|
3001
|
-
* @returns Observable of the raw search result
|
|
3002
|
-
*/
|
|
3003
|
-
searchRaw(query) {
|
|
3004
|
-
if (!query.size)
|
|
3005
|
-
query.size = SearchService.DEFAULT_QUERY_SIZE;
|
|
3006
|
-
return this.#backend.post(`/dms/objects/search`, query);
|
|
2883
|
+
getObjectConfigs$(bucket, includeDefaults) {
|
|
2884
|
+
return this.#objectConfigs$.pipe(map$1((soc) => {
|
|
2885
|
+
let ocr = soc.main;
|
|
2886
|
+
const defaults = { ...this.#defaultObjectConfigs, ...this.#getRegisteredDefaults(bucket) };
|
|
2887
|
+
if (bucket) {
|
|
2888
|
+
const tileBucket = soc.buckets.find((b) => b.id === bucket);
|
|
2889
|
+
if (tileBucket) {
|
|
2890
|
+
ocr = tileBucket.configs;
|
|
2891
|
+
if (includeDefaults)
|
|
2892
|
+
Object.keys(ocr).forEach((k) => {
|
|
2893
|
+
ocr[k] = { ...defaults[k], ...ocr[k] };
|
|
2894
|
+
});
|
|
2895
|
+
}
|
|
2896
|
+
}
|
|
2897
|
+
return includeDefaults ? { ...defaults, ...ocr } : { ...ocr };
|
|
2898
|
+
}));
|
|
3007
2899
|
}
|
|
3008
2900
|
/**
|
|
3009
|
-
*
|
|
3010
|
-
*
|
|
3011
|
-
* @param
|
|
3012
|
-
*
|
|
2901
|
+
* Register default object configs. Apps can pre-define how their
|
|
2902
|
+
* objects should be rendered.
|
|
2903
|
+
* @param bucket Name of a bucket to bind configs to (usually the ID of the app) to
|
|
2904
|
+
* separate the configs from other apps. If not provided configs will be saved for
|
|
2905
|
+
* the global scope
|
|
3013
2906
|
*/
|
|
3014
|
-
|
|
3015
|
-
|
|
2907
|
+
registerDefaults(configs, bucket) {
|
|
2908
|
+
if (bucket) {
|
|
2909
|
+
// does bucket exist?
|
|
2910
|
+
const tileBucketIdx = this.#registeredDefaultObjectConfigs.buckets.findIndex((b) => b.id === bucket);
|
|
2911
|
+
if (tileBucketIdx !== -1) {
|
|
2912
|
+
this.#registeredDefaultObjectConfigs.buckets[tileBucketIdx].configs = {
|
|
2913
|
+
...this.#registeredDefaultObjectConfigs.buckets[tileBucketIdx].configs,
|
|
2914
|
+
...configs
|
|
2915
|
+
};
|
|
2916
|
+
}
|
|
2917
|
+
else {
|
|
2918
|
+
this.#registeredDefaultObjectConfigs.buckets.push({
|
|
2919
|
+
id: bucket,
|
|
2920
|
+
configs
|
|
2921
|
+
});
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
else {
|
|
2925
|
+
this.#registeredDefaultObjectConfigs.main = { ...this.#registeredDefaultObjectConfigs.main, ...configs };
|
|
2926
|
+
}
|
|
3016
2927
|
}
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
handleDeletedDocuments: 'DELETED_DOCUMENTS_EXCLUDE'
|
|
2928
|
+
unregisterDefaults(configs, bucket) {
|
|
2929
|
+
if (bucket) {
|
|
2930
|
+
// does bucket exist?
|
|
2931
|
+
const tileBucketIdx = this.#registeredDefaultObjectConfigs.buckets.findIndex((b) => b.id === bucket);
|
|
2932
|
+
if (tileBucketIdx !== -1) {
|
|
2933
|
+
this.#registeredDefaultObjectConfigs.buckets.splice(tileBucketIdx, 1);
|
|
3024
2934
|
}
|
|
3025
|
-
};
|
|
3026
|
-
if (includePermissions) {
|
|
3027
|
-
payload.query.includePermissions = true;
|
|
3028
2935
|
}
|
|
3029
|
-
|
|
3030
|
-
.
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
.pipe(map((res) => this.toSearchResult(res, maxItems, skipCount)));
|
|
2936
|
+
else {
|
|
2937
|
+
Object.keys(configs).forEach((key) => {
|
|
2938
|
+
delete this.#registeredDefaultObjectConfigs.main[key];
|
|
2939
|
+
});
|
|
2940
|
+
}
|
|
3035
2941
|
}
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
* to get an aggregation of object types)
|
|
3041
|
-
*/
|
|
3042
|
-
aggregate(q, aggregations) {
|
|
3043
|
-
q.aggs = aggregations;
|
|
3044
|
-
return this.searchRaw(q).pipe(map((res) => this.#toAggregateResult(res, aggregations)));
|
|
3045
|
-
}
|
|
3046
|
-
/**
|
|
3047
|
-
* Map search result from the backend to applications AggregateResult object
|
|
3048
|
-
* @param searchResponse The backend response
|
|
3049
|
-
* @param aggregations The aggregations to be fetched
|
|
3050
|
-
*/
|
|
3051
|
-
#toAggregateResult(searchResponse, aggregations) {
|
|
3052
|
-
const agg = [];
|
|
3053
|
-
if (aggregations) {
|
|
3054
|
-
aggregations.forEach((a) => {
|
|
3055
|
-
const ag = {
|
|
3056
|
-
aggKey: a,
|
|
3057
|
-
entries: searchResponse.objects.map((o) => ({
|
|
3058
|
-
key: o.properties[a].value,
|
|
3059
|
-
count: o.properties['OBJECT_COUNT'].value
|
|
3060
|
-
}))
|
|
3061
|
-
};
|
|
3062
|
-
agg.push(ag);
|
|
3063
|
-
});
|
|
3064
|
-
}
|
|
3065
|
-
return {
|
|
3066
|
-
totalNumItems: searchResponse.totalNumItems,
|
|
3067
|
-
aggregations: agg
|
|
3068
|
-
};
|
|
3069
|
-
}
|
|
3070
|
-
/**
|
|
3071
|
-
* Go to a page of a search result.
|
|
3072
|
-
* @param query SearchQuery or CMIS query statement
|
|
3073
|
-
* @param page The number of the page to go to
|
|
3074
|
-
*/
|
|
3075
|
-
getPage(query, page, pageSize = SearchService.DEFAULT_QUERY_SIZE, includePermissions = false) {
|
|
3076
|
-
const isCmis = typeof query === 'string';
|
|
3077
|
-
if (isCmis) {
|
|
3078
|
-
return this.#executeCmisSearch(query, pageSize, (page - 1) * pageSize, includePermissions);
|
|
2942
|
+
getRegisteredDefault(objectTypeId, bucket) {
|
|
2943
|
+
if (bucket) {
|
|
2944
|
+
const b = this.#registeredDefaultObjectConfigs.buckets.find((b) => b.id === bucket);
|
|
2945
|
+
return b ? b.configs[objectTypeId] : undefined;
|
|
3079
2946
|
}
|
|
3080
2947
|
else {
|
|
3081
|
-
|
|
3082
|
-
|
|
2948
|
+
return this.#registeredDefaultObjectConfigs.main[objectTypeId];
|
|
2949
|
+
}
|
|
2950
|
+
}
|
|
2951
|
+
#getRegisteredDefaults(bucket) {
|
|
2952
|
+
if (bucket) {
|
|
2953
|
+
const defaultTileBucket = this.#registeredDefaultObjectConfigs.buckets.find((b) => b.id === bucket);
|
|
2954
|
+
return defaultTileBucket?.configs || {};
|
|
3083
2955
|
}
|
|
2956
|
+
else
|
|
2957
|
+
return this.#registeredDefaultObjectConfigs.main;
|
|
3084
2958
|
}
|
|
3085
2959
|
/**
|
|
3086
|
-
*
|
|
3087
|
-
* @param
|
|
2960
|
+
* Get object config for an object type.
|
|
2961
|
+
* @param objectTypeId ID of the object type to get the config for
|
|
2962
|
+
* @param bucket Optional bucket ID to fetch the config from. Buckets
|
|
2963
|
+
* define separated areas to store/receive those configs. This way
|
|
2964
|
+
* components/apps can store different object configs than the ones
|
|
2965
|
+
* used accross the whole client application.
|
|
3088
2966
|
*/
|
|
3089
|
-
|
|
3090
|
-
const
|
|
3091
|
-
const
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
// table fields will have a clientValue too ...
|
|
3099
|
-
value = o.properties[key].clvalue;
|
|
3100
|
-
// ... and also may contain values that need to be resolved
|
|
3101
|
-
if (o.properties[key].resolvedValues) {
|
|
3102
|
-
value.forEach((v) => {
|
|
3103
|
-
Object.keys(v).forEach((k) => {
|
|
3104
|
-
const resValue = Array.isArray(v[k]) ? v[k].map((i) => o.properties[key].resolvedValues[i]) : o.properties[key].resolvedValues[v[k]];
|
|
3105
|
-
if (resValue) {
|
|
3106
|
-
v[`${k}_title`] = resValue;
|
|
3107
|
-
}
|
|
3108
|
-
});
|
|
3109
|
-
});
|
|
3110
|
-
}
|
|
3111
|
-
}
|
|
3112
|
-
fields.set(key, value);
|
|
3113
|
-
if (o.properties[key].title) {
|
|
3114
|
-
fields.set(key + '_title', o.properties[key].title);
|
|
3115
|
-
}
|
|
3116
|
-
});
|
|
3117
|
-
// process contentStreams section of result if available.
|
|
3118
|
-
// Objects that don't have files attached won't have this section
|
|
3119
|
-
let content;
|
|
3120
|
-
if (o.contentStreams && o.contentStreams.length > 0) {
|
|
3121
|
-
// we assume that each result object only has ONE file attached, altough
|
|
3122
|
-
// this is an array and there may be more
|
|
3123
|
-
const contentStream = o.contentStreams[0];
|
|
3124
|
-
// also add contentstream related fields to the result fields
|
|
3125
|
-
fields.set(ContentStreamField.LENGTH, contentStream.length);
|
|
3126
|
-
fields.set(ContentStreamField.MIME_TYPE, contentStream.mimeType);
|
|
3127
|
-
fields.set(ContentStreamField.FILENAME, contentStream.fileName);
|
|
3128
|
-
fields.set(ContentStreamField.ID, contentStream.contentStreamId);
|
|
3129
|
-
fields.set(ContentStreamField.RANGE, contentStream.contentStreamRange);
|
|
3130
|
-
fields.set(ContentStreamField.REPOSITORY_ID, contentStream.repositoryId);
|
|
3131
|
-
fields.set(ContentStreamField.DIGEST, contentStream.digest);
|
|
3132
|
-
fields.set(ContentStreamField.ARCHIVE_PATH, contentStream.archivePath);
|
|
3133
|
-
content = {
|
|
3134
|
-
contentStreamId: contentStream.contentStreamId,
|
|
3135
|
-
repositoryId: contentStream.repositoryId,
|
|
3136
|
-
range: contentStream.range,
|
|
3137
|
-
digest: contentStream.digest,
|
|
3138
|
-
archivePath: contentStream.archivePath,
|
|
3139
|
-
fileName: contentStream.fileName,
|
|
3140
|
-
mimeType: contentStream.mimeType,
|
|
3141
|
-
size: contentStream.length
|
|
3142
|
-
};
|
|
3143
|
-
}
|
|
3144
|
-
const objectTypeId = o.properties[BaseObjectTypeField.OBJECT_TYPE_ID] ? o.properties[BaseObjectTypeField.OBJECT_TYPE_ID].value : null;
|
|
3145
|
-
if (objectTypes.indexOf(objectTypeId) === -1) {
|
|
3146
|
-
objectTypes.push(objectTypeId);
|
|
3147
|
-
}
|
|
3148
|
-
resultListItems.push({
|
|
3149
|
-
objectTypeId,
|
|
3150
|
-
content,
|
|
3151
|
-
fields,
|
|
3152
|
-
permissions: o.permissions
|
|
3153
|
-
});
|
|
3154
|
-
});
|
|
3155
|
-
const totalPages = Math.ceil(searchResponse.totalNumItems / pageSize);
|
|
3156
|
-
const page = (!skipCount ? 0 : skipCount / pageSize) + 1;
|
|
3157
|
-
const result = {
|
|
3158
|
-
hasMoreItems: searchResponse.hasMoreItems,
|
|
3159
|
-
totalNumItems: searchResponse.totalNumItems,
|
|
3160
|
-
items: resultListItems,
|
|
3161
|
-
objectTypes: objectTypes,
|
|
3162
|
-
paging: totalPages > 1 ? { page, totalPages } : undefined
|
|
3163
|
-
};
|
|
2967
|
+
getObjectConfig(type, bucket) {
|
|
2968
|
+
const b = bucket ? this.#objectConfigs.buckets.find((b) => b.id === bucket) : undefined;
|
|
2969
|
+
const otr = b ? b.configs : this.#objectConfigs.main;
|
|
2970
|
+
const oc = otr[type.id];
|
|
2971
|
+
// return oc || this.#getRegisteredDefaults(bucket)[type.id];
|
|
2972
|
+
// override icons by APP_SCHEMA-icons: temporary solution. Todo: remove when handling of custom svg-icons is clear!
|
|
2973
|
+
const result = oc || this.#getRegisteredDefaults(bucket)[type.id] || this.#defaultObjectConfigs[type.id];
|
|
2974
|
+
if (result?.icon)
|
|
2975
|
+
result.icon = type.icon ? { svg: type.icon } : result.icon;
|
|
3164
2976
|
return result;
|
|
3165
2977
|
}
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
2978
|
+
saveObjectConfig(type, config, bucket) {
|
|
2979
|
+
return this.saveObjectConfigs({ [type.id]: config }, bucket);
|
|
2980
|
+
}
|
|
2981
|
+
saveObjectConfigs(configs, bucket) {
|
|
2982
|
+
this.#updateObjectConfig(configs, bucket);
|
|
2983
|
+
return this.#user.saveObjectConfig(this.#objectConfigs);
|
|
2984
|
+
}
|
|
2985
|
+
#updateObjectConfig(configs, bucket) {
|
|
2986
|
+
if (!this.#objectConfigs) {
|
|
2987
|
+
this.#objectConfigs = {
|
|
2988
|
+
main: {},
|
|
2989
|
+
buckets: []
|
|
2990
|
+
};
|
|
2991
|
+
}
|
|
2992
|
+
if (bucket) {
|
|
2993
|
+
// does bucket exist?
|
|
2994
|
+
const tileBucketIdx = this.#objectConfigs.buckets.findIndex((b) => b.id === bucket);
|
|
2995
|
+
if (tileBucketIdx !== -1) {
|
|
2996
|
+
Object.keys(configs).forEach((objectTypeId) => {
|
|
2997
|
+
const config = configs[objectTypeId];
|
|
2998
|
+
if (config) {
|
|
2999
|
+
this.#objectConfigs.buckets[tileBucketIdx].configs[objectTypeId] = config;
|
|
3000
|
+
}
|
|
3001
|
+
else {
|
|
3002
|
+
delete this.#objectConfigs.buckets[tileBucketIdx].configs[objectTypeId];
|
|
3003
|
+
}
|
|
3004
|
+
});
|
|
3183
3005
|
}
|
|
3184
3006
|
else {
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3007
|
+
const newBucket = { id: bucket, configs: {} };
|
|
3008
|
+
Object.keys(configs).forEach((objectTypeId) => {
|
|
3009
|
+
const config = configs[objectTypeId];
|
|
3010
|
+
if (config) {
|
|
3011
|
+
newBucket.configs[objectTypeId] = config;
|
|
3012
|
+
}
|
|
3189
3013
|
});
|
|
3014
|
+
this.#objectConfigs.buckets.push(newBucket);
|
|
3190
3015
|
}
|
|
3191
|
-
}
|
|
3192
|
-
|
|
3016
|
+
}
|
|
3017
|
+
else {
|
|
3018
|
+
Object.keys(configs).forEach((objectTypeId) => {
|
|
3019
|
+
const config = configs[objectTypeId];
|
|
3020
|
+
if (config) {
|
|
3021
|
+
this.#objectConfigs.main[objectTypeId] = config;
|
|
3022
|
+
}
|
|
3023
|
+
else {
|
|
3024
|
+
delete this.#objectConfigs.main[objectTypeId];
|
|
3025
|
+
}
|
|
3026
|
+
});
|
|
3027
|
+
}
|
|
3028
|
+
this.#objectConfigsSource.next(this.#objectConfigs);
|
|
3193
3029
|
}
|
|
3194
|
-
|
|
3195
|
-
return this.#
|
|
3196
|
-
? this.#dateRangeValueToSearchFilter(value, property)
|
|
3197
|
-
: {
|
|
3198
|
-
f: property,
|
|
3199
|
-
o: value.operator,
|
|
3200
|
-
v1: value.firstValue,
|
|
3201
|
-
v2: value.secondValue
|
|
3202
|
-
};
|
|
3030
|
+
getDefaultConfig(objectTypeID) {
|
|
3031
|
+
return this.#defaultObjectConfigs[objectTypeID];
|
|
3203
3032
|
}
|
|
3204
|
-
|
|
3205
|
-
const
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3033
|
+
getResolvedObjectConfig(data, type, bucket, includeDefaults) {
|
|
3034
|
+
const defaultCfg = this.#defaultObjectConfigs[data[BaseObjectTypeField.OBJECT_TYPE_ID]];
|
|
3035
|
+
let oc = this.getObjectConfig(type, bucket) || defaultCfg;
|
|
3036
|
+
if (includeDefaults)
|
|
3037
|
+
oc = { ...defaultCfg, ...oc };
|
|
3038
|
+
const res = {
|
|
3039
|
+
id: data[BaseObjectTypeField.OBJECT_ID],
|
|
3040
|
+
objectTypeId: data[BaseObjectTypeField.OBJECT_TYPE_ID],
|
|
3041
|
+
actions: oc.actions,
|
|
3042
|
+
badges: oc.badges,
|
|
3043
|
+
instanceData: data
|
|
3044
|
+
};
|
|
3045
|
+
if (oc.title)
|
|
3046
|
+
res.title = {
|
|
3047
|
+
propertyName: oc.title.propertyName,
|
|
3048
|
+
value: data[oc.title.propertyName]
|
|
3049
|
+
};
|
|
3050
|
+
if (oc.description)
|
|
3051
|
+
res.description = {
|
|
3052
|
+
propertyName: oc.description.propertyName,
|
|
3053
|
+
value: data[oc.description.propertyName]
|
|
3054
|
+
};
|
|
3055
|
+
if (oc.icon)
|
|
3056
|
+
res.icon = {
|
|
3057
|
+
propertyName: 'custom',
|
|
3058
|
+
value: oc.icon.svg
|
|
3059
|
+
};
|
|
3060
|
+
if (oc.meta)
|
|
3061
|
+
res.meta = {
|
|
3062
|
+
propertyName: oc.meta.propertyName,
|
|
3063
|
+
value: data[oc.meta.propertyName]
|
|
3064
|
+
};
|
|
3065
|
+
if (oc.aside)
|
|
3066
|
+
res.aside = {
|
|
3067
|
+
propertyName: oc.aside.propertyName,
|
|
3068
|
+
value: data[oc.aside.propertyName]
|
|
3069
|
+
};
|
|
3070
|
+
return res;
|
|
3241
3071
|
}
|
|
3242
3072
|
/**
|
|
3243
|
-
*
|
|
3244
|
-
*
|
|
3245
|
-
* @param value
|
|
3246
|
-
* @param range
|
|
3247
|
-
* @private
|
|
3073
|
+
* Load default/fallbac configs based on the object types and
|
|
3074
|
+
* their first properties
|
|
3248
3075
|
*/
|
|
3249
|
-
#
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
case 'end':
|
|
3260
|
-
return isoDateString;
|
|
3261
|
-
default:
|
|
3262
|
-
return isoDateString;
|
|
3263
|
-
}
|
|
3076
|
+
#getDefaultObjectConfig() {
|
|
3077
|
+
this.#system.getObjectTypes(true).forEach((ot) => {
|
|
3078
|
+
this.#defaultObjectConfigs[ot.id] = {
|
|
3079
|
+
objectTypeId: ot.id,
|
|
3080
|
+
title: this.#toObjectProperty(ot.fields[0]),
|
|
3081
|
+
description: this.#toObjectProperty(ot.fields[1]),
|
|
3082
|
+
meta: this.#toObjectProperty(ot.fields[2]),
|
|
3083
|
+
aside: this.#toObjectProperty(ot.fields[3])
|
|
3084
|
+
};
|
|
3085
|
+
});
|
|
3264
3086
|
}
|
|
3265
|
-
|
|
3266
|
-
|
|
3087
|
+
#toObjectProperty(field) {
|
|
3088
|
+
return field
|
|
3089
|
+
? {
|
|
3090
|
+
label: this.#system.getLocalizedLabel(field.id),
|
|
3091
|
+
propertyName: field.id
|
|
3092
|
+
}
|
|
3093
|
+
: undefined;
|
|
3094
|
+
}
|
|
3095
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: ObjectConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3096
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: ObjectConfigService, providedIn: 'root' }); }
|
|
3267
3097
|
}
|
|
3268
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type:
|
|
3098
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: ObjectConfigService, decorators: [{
|
|
3269
3099
|
type: Injectable,
|
|
3270
3100
|
args: [{
|
|
3271
3101
|
providedIn: 'root'
|
|
3272
3102
|
}]
|
|
3273
3103
|
}] });
|
|
3274
3104
|
|
|
3105
|
+
const YUV_USER = new InjectionToken('Currently logged in user', {
|
|
3106
|
+
factory: () => undefined
|
|
3107
|
+
});
|
|
3108
|
+
const provideUser = (user) => {
|
|
3109
|
+
return { provide: YUV_USER, useValue: user };
|
|
3110
|
+
};
|
|
3111
|
+
|
|
3275
3112
|
/**
|
|
3276
|
-
* Service
|
|
3277
|
-
* an object. Actions perormed on an object (eg. read, write, delete, ...) will be recorded during
|
|
3278
|
-
* the objects lifecycle. Audits are provided based on a users permissions. Beside the audit entries
|
|
3279
|
-
* visible to regular users there are more technical ones that will only be shown to users that
|
|
3280
|
-
* have administrative role.
|
|
3113
|
+
* Service handling authentication related issues.
|
|
3281
3114
|
*/
|
|
3282
|
-
class
|
|
3283
|
-
|
|
3284
|
-
|
|
3115
|
+
class AuthService {
|
|
3116
|
+
// user may have been fetched already in bootstrapping process
|
|
3117
|
+
#userToken;
|
|
3118
|
+
#eventService;
|
|
3119
|
+
#userService;
|
|
3120
|
+
#objectConfigService;
|
|
3121
|
+
#appCache;
|
|
3122
|
+
#systemService;
|
|
3123
|
+
#localizationService;
|
|
3124
|
+
#backend;
|
|
3125
|
+
#INITIAL_REQUEST_STORAGE_KEY;
|
|
3126
|
+
#USER_FETCH_URI;
|
|
3127
|
+
#authenticated;
|
|
3128
|
+
#authSource;
|
|
3129
|
+
#authData;
|
|
3130
|
+
constructor(coreConfig) {
|
|
3131
|
+
this.coreConfig = coreConfig;
|
|
3132
|
+
// user may have been fetched already in bootstrapping process
|
|
3133
|
+
this.#userToken = inject(YUV_USER);
|
|
3134
|
+
this.#eventService = inject(EventService);
|
|
3285
3135
|
this.#userService = inject(UserService);
|
|
3286
|
-
|
|
3287
|
-
this
|
|
3288
|
-
|
|
3289
|
-
this
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
310, // tag updated
|
|
3300
|
-
325, // object restored form version
|
|
3301
|
-
340, // object moved
|
|
3302
|
-
10000 // custom audit entries
|
|
3303
|
-
];
|
|
3304
|
-
// audit action codes that should be visible to admin users
|
|
3305
|
-
this.adminAuditActions = [
|
|
3306
|
-
202, // marked for delete
|
|
3307
|
-
220, // version deleted
|
|
3308
|
-
400, // content read
|
|
3309
|
-
401, // metadata read
|
|
3310
|
-
402, // rendition read (text)
|
|
3311
|
-
403, // rendition read (pdf)
|
|
3312
|
-
404 // rendition read (thumbnail)
|
|
3313
|
-
];
|
|
3136
|
+
this.#objectConfigService = inject(ObjectConfigService);
|
|
3137
|
+
this.#appCache = inject(AppCacheService);
|
|
3138
|
+
this.#systemService = inject(SystemService);
|
|
3139
|
+
this.#localizationService = inject(LocalizationService);
|
|
3140
|
+
this.#backend = inject(BackendService);
|
|
3141
|
+
this.#INITIAL_REQUEST_STORAGE_KEY = 'yuv.core.auth.initialrequest';
|
|
3142
|
+
this.#USER_FETCH_URI = '/idm/whoami';
|
|
3143
|
+
this.#authenticated = false;
|
|
3144
|
+
this.#authSource = new BehaviorSubject(false);
|
|
3145
|
+
this.authenticated$ = this.#authSource.asObservable();
|
|
3146
|
+
}
|
|
3147
|
+
isLoggedIn() {
|
|
3148
|
+
return this.#authenticated;
|
|
3314
3149
|
}
|
|
3315
|
-
#searchService;
|
|
3316
|
-
#userService;
|
|
3317
3150
|
/**
|
|
3318
|
-
*
|
|
3319
|
-
* @
|
|
3320
|
-
* @param options Options
|
|
3151
|
+
* Called while app/core is initialized (APP_INITIALIZER)
|
|
3152
|
+
* @ignore
|
|
3321
3153
|
*/
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
const q = {
|
|
3325
|
-
size: this.DEFAULT_RES_SIZE,
|
|
3326
|
-
types: [SystemType.AUDIT],
|
|
3327
|
-
filters: [
|
|
3328
|
-
{
|
|
3329
|
-
f: AuditField.REFERRED_OBJECT_ID,
|
|
3330
|
-
o: Operator.EQUAL,
|
|
3331
|
-
v1: id
|
|
3332
|
-
},
|
|
3333
|
-
{
|
|
3334
|
-
f: AuditField.ACTION,
|
|
3335
|
-
o: Operator.IN,
|
|
3336
|
-
v1: auditActions
|
|
3337
|
-
}
|
|
3338
|
-
],
|
|
3339
|
-
sort: [
|
|
3340
|
-
{
|
|
3341
|
-
field: AuditField.CREATION_DATE,
|
|
3342
|
-
order: 'desc'
|
|
3343
|
-
}
|
|
3344
|
-
]
|
|
3345
|
-
};
|
|
3346
|
-
return this.#fetchAudits(q);
|
|
3154
|
+
initUser() {
|
|
3155
|
+
return this.fetchUser();
|
|
3347
3156
|
}
|
|
3348
3157
|
/**
|
|
3349
|
-
* Get
|
|
3350
|
-
* whether or not the user has admin permissions you'll get a different
|
|
3351
|
-
* set of actions.
|
|
3352
|
-
* @param skipActions codes of actions that should not be fetched
|
|
3158
|
+
* Get the current tenant or the previous one persisted locally
|
|
3353
3159
|
*/
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
return actions.filter((a) => !skipActions || !skipActions.includes(a));
|
|
3160
|
+
getTenant() {
|
|
3161
|
+
return this.#authData?.tenant;
|
|
3357
3162
|
}
|
|
3358
3163
|
/**
|
|
3359
|
-
*
|
|
3360
|
-
* @param auditsResult The result object of a former audits query
|
|
3361
|
-
* @param page The page to load
|
|
3164
|
+
* Fetch information about the user currently logged in
|
|
3362
3165
|
*/
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3166
|
+
fetchUser() {
|
|
3167
|
+
return (this.#userToken ? of(this.#userToken) : this.#backend.get(this.#USER_FETCH_URI)).pipe(tap(() => {
|
|
3168
|
+
this.#authenticated = true;
|
|
3169
|
+
this.#authSource.next(this.#authenticated);
|
|
3170
|
+
}), switchMap((userJson) => this.#initApp(userJson)));
|
|
3367
3171
|
}
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
subaction: o.properties[AuditField.SUBACTION] ? o.properties[AuditField.SUBACTION].value : null,
|
|
3376
|
-
version: o.properties[AuditField.VERSION].value,
|
|
3377
|
-
creationDate: o.properties[AuditField.CREATION_DATE].value,
|
|
3378
|
-
createdBy: {
|
|
3379
|
-
id: o.properties[AuditField.CREATED_BY].value,
|
|
3380
|
-
title: o.properties[AuditField.CREATED_BY].title
|
|
3381
|
-
}
|
|
3382
|
-
})),
|
|
3383
|
-
hasMoreItems: res.hasMoreItems,
|
|
3384
|
-
page: !q.from ? 1 : q.from / q.size + 1
|
|
3385
|
-
})));
|
|
3172
|
+
/**
|
|
3173
|
+
* Logs out the current user.
|
|
3174
|
+
*/
|
|
3175
|
+
logout() {
|
|
3176
|
+
this.#authenticated = false;
|
|
3177
|
+
this.#authSource.next(this.#authenticated);
|
|
3178
|
+
this.#eventService.trigger(YuvEventType.LOGOUT);
|
|
3386
3179
|
}
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3180
|
+
/**
|
|
3181
|
+
* Persists the initial request URI. This is nessesary to be able to
|
|
3182
|
+
* redirect the user to the requested page after authentication.
|
|
3183
|
+
* This is done on app initialization (core-init).
|
|
3184
|
+
*/
|
|
3185
|
+
setInitialRequestUri() {
|
|
3186
|
+
const ignore = ['/', '/index.html'];
|
|
3187
|
+
const baseHref = Utils.getBaseHref();
|
|
3188
|
+
// Check only the pathname against the ignore list so that auth callback
|
|
3189
|
+
// query params (e.g. ?session_state=…) don't bypass the check.
|
|
3190
|
+
let path = location.pathname.replace(baseHref, '');
|
|
3191
|
+
path = !path.startsWith('/') ? `/${path}` : path;
|
|
3192
|
+
if (!ignore.includes(path)) {
|
|
3193
|
+
let uri = `${location.pathname}${location.search}`.replace(baseHref, '');
|
|
3194
|
+
uri = !uri.startsWith('/') ? `/${uri}` : uri;
|
|
3195
|
+
return this.#appCache.setItem(this.#INITIAL_REQUEST_STORAGE_KEY, {
|
|
3196
|
+
uri: uri,
|
|
3197
|
+
timestamp: Date.now()
|
|
3198
|
+
});
|
|
3393
3199
|
}
|
|
3200
|
+
return of(false);
|
|
3201
|
+
}
|
|
3202
|
+
/**
|
|
3203
|
+
* Get the URL that entered the app. May be a deep link that could then be
|
|
3204
|
+
* picked up again after user has been authenticated.
|
|
3205
|
+
*/
|
|
3206
|
+
getInitialRequestUri() {
|
|
3207
|
+
return this.#appCache.getItem(this.#INITIAL_REQUEST_STORAGE_KEY);
|
|
3208
|
+
}
|
|
3209
|
+
resetInitialRequestUri() {
|
|
3210
|
+
return this.#appCache.removeItem(this.#INITIAL_REQUEST_STORAGE_KEY);
|
|
3211
|
+
}
|
|
3212
|
+
/**
|
|
3213
|
+
* Initialize/setup the application for a given user. This involves fetching
|
|
3214
|
+
* settings and schema information.
|
|
3215
|
+
* @param userJson Data retrieved from the backend
|
|
3216
|
+
*/
|
|
3217
|
+
#initApp(userJson) {
|
|
3218
|
+
return this.#userService.fetchUserSettings().pipe(switchMap((userSettings) => {
|
|
3219
|
+
const currentUser = new YuvUser(userJson, userSettings);
|
|
3220
|
+
this.#userService.setCurrentUser(currentUser);
|
|
3221
|
+
this.#authData = {
|
|
3222
|
+
tenant: currentUser.tenant,
|
|
3223
|
+
language: currentUser.getClientLocale()
|
|
3224
|
+
};
|
|
3225
|
+
return forkJoin([
|
|
3226
|
+
this.#localizationService.fetchLocalizations(),
|
|
3227
|
+
this.#systemService.getSystemDefinition(this.#authData)
|
|
3228
|
+
]).pipe(switchMap(() => this.#objectConfigService.init()), map(() => currentUser));
|
|
3229
|
+
}));
|
|
3394
3230
|
}
|
|
3395
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type:
|
|
3396
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type:
|
|
3231
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AuthService, deps: [{ token: CORE_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3232
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AuthService, providedIn: 'root' }); }
|
|
3397
3233
|
}
|
|
3398
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type:
|
|
3234
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AuthService, decorators: [{
|
|
3399
3235
|
type: Injectable,
|
|
3400
3236
|
args: [{
|
|
3401
3237
|
providedIn: 'root'
|
|
3402
3238
|
}]
|
|
3403
|
-
}]
|
|
3239
|
+
}], ctorParameters: () => [{ type: CoreConfig, decorators: [{
|
|
3240
|
+
type: Inject,
|
|
3241
|
+
args: [CORE_CONFIG]
|
|
3242
|
+
}] }] });
|
|
3243
|
+
|
|
3244
|
+
/**
|
|
3245
|
+
* Prevent app from running into 401 issues related to gateway timeouts.
|
|
3246
|
+
*/
|
|
3247
|
+
function AuthInterceptorFnc(req, next) {
|
|
3248
|
+
const userService = inject(UserService);
|
|
3249
|
+
const auth = inject(AuthService);
|
|
3250
|
+
return next(req).pipe(tap({
|
|
3251
|
+
next: (event) => {
|
|
3252
|
+
if (event instanceof HttpResponse) {
|
|
3253
|
+
// do stuff with response if you want
|
|
3254
|
+
}
|
|
3255
|
+
},
|
|
3256
|
+
error: (error) => {
|
|
3257
|
+
if (error instanceof HttpErrorResponse || error.isHttpErrorResponse) {
|
|
3258
|
+
if (error.status === 401) {
|
|
3259
|
+
auth.logout();
|
|
3260
|
+
userService.logout();
|
|
3261
|
+
}
|
|
3262
|
+
}
|
|
3263
|
+
}
|
|
3264
|
+
}));
|
|
3265
|
+
}
|
|
3266
|
+
|
|
3267
|
+
var LoginStateName;
|
|
3268
|
+
(function (LoginStateName) {
|
|
3269
|
+
LoginStateName["STATE_LOGIN_URI"] = "login.uri";
|
|
3270
|
+
LoginStateName["STATE_DONE"] = "login.done";
|
|
3271
|
+
LoginStateName["STATE_CANCELED"] = "login.canceled";
|
|
3272
|
+
})(LoginStateName || (LoginStateName = {}));
|
|
3404
3273
|
|
|
3405
3274
|
const ProcessAction = {
|
|
3406
3275
|
complete: 'complete',
|
|
@@ -3453,6 +3322,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
3453
3322
|
}]
|
|
3454
3323
|
}] });
|
|
3455
3324
|
|
|
3325
|
+
const LOCALIZATION_COLUMNS = ['locale', 'label', 'description'];
|
|
3326
|
+
|
|
3456
3327
|
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
3457
3328
|
const transformResponse = () => map((res) => (res.body ? res.body.objects.map((val) => val) : null));
|
|
3458
3329
|
/**
|
|
@@ -4352,8 +4223,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
4352
4223
|
}]
|
|
4353
4224
|
}] });
|
|
4354
4225
|
|
|
4355
|
-
const LOCALIZATION_COLUMNS = ['locale', 'label', 'description'];
|
|
4356
|
-
|
|
4357
4226
|
class CatalogService {
|
|
4358
4227
|
constructor() {
|
|
4359
4228
|
this.#backend = inject(BackendService);
|
|
@@ -4743,6 +4612,159 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
4743
4612
|
}]
|
|
4744
4613
|
}] });
|
|
4745
4614
|
|
|
4615
|
+
/**
|
|
4616
|
+
* Service to monitor the online/offline state of the application.
|
|
4617
|
+
* It listens to the browser's online and offline events and provides an observable
|
|
4618
|
+
* to track the current connection state.
|
|
4619
|
+
*
|
|
4620
|
+
* An observable `connection$` is provided which emits the current connection state
|
|
4621
|
+
* whenever the online or offline state changes. The initial state is determined by
|
|
4622
|
+
* the `window.navigator.onLine` property.
|
|
4623
|
+
*/
|
|
4624
|
+
class ConnectionService {
|
|
4625
|
+
/**
|
|
4626
|
+
* @ignore
|
|
4627
|
+
*/
|
|
4628
|
+
constructor() {
|
|
4629
|
+
this.currentState = {
|
|
4630
|
+
isOnline: window.navigator.onLine
|
|
4631
|
+
};
|
|
4632
|
+
this.connectionStateSource = new ReplaySubject();
|
|
4633
|
+
this.connection$ = this.connectionStateSource.asObservable();
|
|
4634
|
+
this.connectionStateSource.next(this.currentState);
|
|
4635
|
+
fromEvent(window, 'online').subscribe(() => {
|
|
4636
|
+
this.currentState.isOnline = true;
|
|
4637
|
+
this.connectionStateSource.next(this.currentState);
|
|
4638
|
+
});
|
|
4639
|
+
fromEvent(window, 'offline').subscribe(() => {
|
|
4640
|
+
this.currentState.isOnline = false;
|
|
4641
|
+
this.connectionStateSource.next(this.currentState);
|
|
4642
|
+
});
|
|
4643
|
+
}
|
|
4644
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: ConnectionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4645
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: ConnectionService, providedIn: 'root' }); }
|
|
4646
|
+
}
|
|
4647
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: ConnectionService, decorators: [{
|
|
4648
|
+
type: Injectable,
|
|
4649
|
+
args: [{
|
|
4650
|
+
providedIn: 'root'
|
|
4651
|
+
}]
|
|
4652
|
+
}], ctorParameters: () => [] });
|
|
4653
|
+
|
|
4654
|
+
/**
|
|
4655
|
+
* Http Offline interceptor trys to serving offline content for method/url
|
|
4656
|
+
*/
|
|
4657
|
+
function OfflineInterceptorFnc(req, next) {
|
|
4658
|
+
return next(req);
|
|
4659
|
+
}
|
|
4660
|
+
|
|
4661
|
+
/**
|
|
4662
|
+
* Providing functions,that are are injected at application startup and executed during app initialization.
|
|
4663
|
+
*/
|
|
4664
|
+
const init_moduleFnc = () => {
|
|
4665
|
+
const coreConfig = inject(CORE_CONFIG);
|
|
4666
|
+
const logger = inject(Logger);
|
|
4667
|
+
const http = inject(HttpClient);
|
|
4668
|
+
const configService = inject(ConfigService);
|
|
4669
|
+
const authService = inject(AuthService);
|
|
4670
|
+
return authService.setInitialRequestUri().pipe(switchMap(() => coreConfig.main
|
|
4671
|
+
? !Array.isArray(coreConfig.main)
|
|
4672
|
+
? of([coreConfig.main])
|
|
4673
|
+
: forkJoin([...coreConfig.main].map((uri) => http.get(`${Utils.getBaseHref()}${uri}`).pipe(catchError((e) => {
|
|
4674
|
+
logger.error('failed to catch config file', e);
|
|
4675
|
+
return of({});
|
|
4676
|
+
}), map((res) => res)))).pipe(
|
|
4677
|
+
// switchMap((configs: YuvConfig[]) => configService.extendConfig(configs)),
|
|
4678
|
+
tap((configs) => configService.extendConfig(configs)), switchMap(() => authService.initUser().pipe(catchError((e) => {
|
|
4679
|
+
authService.initError = {
|
|
4680
|
+
status: e.status,
|
|
4681
|
+
key: e.error.error
|
|
4682
|
+
};
|
|
4683
|
+
return of(true);
|
|
4684
|
+
}))))
|
|
4685
|
+
: of(false)));
|
|
4686
|
+
};
|
|
4687
|
+
|
|
4688
|
+
/**
|
|
4689
|
+
* Handles missing translations
|
|
4690
|
+
* @ignore
|
|
4691
|
+
*/
|
|
4692
|
+
class EoxMissingTranslationHandler {
|
|
4693
|
+
handle(params) {
|
|
4694
|
+
return '!missing key: ' + params.key;
|
|
4695
|
+
}
|
|
4696
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: EoxMissingTranslationHandler, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4697
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: EoxMissingTranslationHandler }); }
|
|
4698
|
+
}
|
|
4699
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: EoxMissingTranslationHandler, decorators: [{
|
|
4700
|
+
type: Injectable
|
|
4701
|
+
}] });
|
|
4702
|
+
|
|
4703
|
+
/**
|
|
4704
|
+
* i18n packages
|
|
4705
|
+
*/
|
|
4706
|
+
/**
|
|
4707
|
+
* Loader that fetches translations based on the configured locations
|
|
4708
|
+
* @ignore
|
|
4709
|
+
*/
|
|
4710
|
+
class EoxTranslateJsonLoader {
|
|
4711
|
+
constructor(http, config) {
|
|
4712
|
+
this.http = http;
|
|
4713
|
+
this.config = config;
|
|
4714
|
+
registerLocaleData(localeDe, 'de', localeExtraDe); // German
|
|
4715
|
+
registerLocaleData(localeAr, 'ar', localeExtraAr); // Arabic
|
|
4716
|
+
registerLocaleData(localeEs, 'es', localeExtraEs); // Spanish
|
|
4717
|
+
registerLocaleData(localePt, 'pt', localeExtraPt); // Portuguese
|
|
4718
|
+
registerLocaleData(localeFr, 'fr', localeExtraFr); // French
|
|
4719
|
+
registerLocaleData(localeZh, 'zh', localeExtraZh); // Chinese
|
|
4720
|
+
registerLocaleData(localeLv, 'lv', localeExtraLv); // Latvian
|
|
4721
|
+
registerLocaleData(localeRu, 'ru', localeExtraRu); // Russian
|
|
4722
|
+
registerLocaleData(localeIt, 'it', localeExtraIt); // Italian
|
|
4723
|
+
registerLocaleData(localeSk, 'sk', localeExtraSk); // Slovak
|
|
4724
|
+
registerLocaleData(localePl, 'pl', localeExtraPl); // Polish
|
|
4725
|
+
registerLocaleData(localeUk, 'uk', localeExtraUk); // Ukrainian
|
|
4726
|
+
registerLocaleData(localeJa, 'ja', localeExtraJa); // Japanese
|
|
4727
|
+
registerLocaleData(localeKo, 'ko', localeExtraKo); // Korean
|
|
4728
|
+
registerLocaleData(localeHi, 'hi', localeExtraHi); // Hindi
|
|
4729
|
+
registerLocaleData(localeBn, 'bn', localeExtraBn); // Bengalese
|
|
4730
|
+
registerLocaleData(localeVi, 'vi', localeExtraVi); // Vietnamese
|
|
4731
|
+
registerLocaleData(localeTr, 'tr', localeExtraTr); // Turkish
|
|
4732
|
+
registerLocaleData(localeNl, 'nl', localeExtraNl); // Dutch
|
|
4733
|
+
registerLocaleData(localeNb, 'nb', localeExtraNb); // Norwegian
|
|
4734
|
+
registerLocaleData(localeTh, 'th', localeExtraTh); // Thai
|
|
4735
|
+
registerLocaleData(localeFi, 'fi', localeExtraFi); // Finnish
|
|
4736
|
+
registerLocaleData(localeSv, 'sv', localeExtraSv); // Swedish
|
|
4737
|
+
registerLocaleData(localeDeCh, 'de-CH', localeExtraDeCh); // German Swiss
|
|
4738
|
+
}
|
|
4739
|
+
/**
|
|
4740
|
+
*
|
|
4741
|
+
* @param string lang
|
|
4742
|
+
* @returns Observable<Object>
|
|
4743
|
+
*/
|
|
4744
|
+
getTranslation(lang) {
|
|
4745
|
+
const t = (this.config.translations || []).map((path) => this.loadTranslationFile(path, lang));
|
|
4746
|
+
return forkJoin(t).pipe(map((res) => res.reduce((acc, x) => Object.assign(acc, x), {})));
|
|
4747
|
+
}
|
|
4748
|
+
loadTranslationFile(path, lang) {
|
|
4749
|
+
const version = document.body.dataset['bt'] ?? document.body.dataset['version'];
|
|
4750
|
+
const cacheBuster = version ? `?v=${version}` : '';
|
|
4751
|
+
return this.http.get(`${Utils.getBaseHref()}${path}${lang}.json${cacheBuster}`).pipe(catchError(() => {
|
|
4752
|
+
// ISO codes with more than 2 characters are sub-languages like de-CH.
|
|
4753
|
+
// If there is no translation file for that sub-language we'll try to load
|
|
4754
|
+
// the file for the base language (in this case de).
|
|
4755
|
+
return lang.length > 2 ? this.loadTranslationFile(path, lang.substring(0, 2)) : of({});
|
|
4756
|
+
}));
|
|
4757
|
+
}
|
|
4758
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: EoxTranslateJsonLoader, deps: [{ token: i1.HttpClient }, { token: CORE_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4759
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: EoxTranslateJsonLoader }); }
|
|
4760
|
+
}
|
|
4761
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: EoxTranslateJsonLoader, decorators: [{
|
|
4762
|
+
type: Injectable
|
|
4763
|
+
}], ctorParameters: () => [{ type: i1.HttpClient }, { type: CoreConfig, decorators: [{
|
|
4764
|
+
type: Inject,
|
|
4765
|
+
args: [CORE_CONFIG]
|
|
4766
|
+
}] }] });
|
|
4767
|
+
|
|
4746
4768
|
var DeviceScreenOrientation;
|
|
4747
4769
|
(function (DeviceScreenOrientation) {
|
|
4748
4770
|
DeviceScreenOrientation["PORTRAIT"] = "portrait";
|
|
@@ -5470,7 +5492,7 @@ class ObjectLockingService {
|
|
|
5470
5492
|
*/
|
|
5471
5493
|
lock(id) {
|
|
5472
5494
|
const { lockTag, state, override, includeObjects } = DEFAULT_LOCK_OPTIONS;
|
|
5473
|
-
return this.#backend.post(`/
|
|
5495
|
+
return this.#backend.post(`/dms/objects/${id}/tags/${lockTag}/state/${state}?overwrite=${override}&includeObjects=${includeObjects}`, undefined, ApiBase.core);
|
|
5474
5496
|
}
|
|
5475
5497
|
/**
|
|
5476
5498
|
* Remove the lock tag from a DMS object.
|
|
@@ -5479,7 +5501,7 @@ class ObjectLockingService {
|
|
|
5479
5501
|
* @returns Observable that completes once the tag has been deleted
|
|
5480
5502
|
*/
|
|
5481
5503
|
unlock(id, lockTag = LockField.LOCK_TAG) {
|
|
5482
|
-
return this.#backend.delete(`/
|
|
5504
|
+
return this.#backend.delete(`/dms/objects/${id}/tags/${lockTag}`, ApiBase.core);
|
|
5483
5505
|
}
|
|
5484
5506
|
/**
|
|
5485
5507
|
* Inspect the lock state of a DMS object relative to the current user.
|
|
@@ -5508,6 +5530,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
5508
5530
|
}]
|
|
5509
5531
|
}] });
|
|
5510
5532
|
|
|
5533
|
+
/**
|
|
5534
|
+
* Interface to be implemented by all components (state components) that are aware of pending changes
|
|
5535
|
+
*/
|
|
5536
|
+
|
|
5511
5537
|
/**
|
|
5512
5538
|
* EditingObserver service is used to track changes made inside the application, that should prevent
|
|
5513
5539
|
* doing something or going somewhere before the changes are persisted or ignored. For example when
|
|
@@ -5627,27 +5653,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
5627
5653
|
}]
|
|
5628
5654
|
}] });
|
|
5629
5655
|
|
|
5630
|
-
/**
|
|
5631
|
-
* Providing a `PendingChangesComponent`.
|
|
5632
|
-
*/
|
|
5633
|
-
class PendingChangesGuard {
|
|
5634
|
-
constructor(pendingChanges) {
|
|
5635
|
-
this.pendingChanges = pendingChanges;
|
|
5636
|
-
}
|
|
5637
|
-
canDeactivate(component) {
|
|
5638
|
-
// if there are no pending changes, just allow deactivation; else confirm first
|
|
5639
|
-
return !this.pendingChanges.check(component);
|
|
5640
|
-
}
|
|
5641
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: PendingChangesGuard, deps: [{ token: PendingChangesService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5642
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: PendingChangesGuard, providedIn: 'root' }); }
|
|
5643
|
-
}
|
|
5644
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: PendingChangesGuard, decorators: [{
|
|
5645
|
-
type: Injectable,
|
|
5646
|
-
args: [{
|
|
5647
|
-
providedIn: 'root'
|
|
5648
|
-
}]
|
|
5649
|
-
}], ctorParameters: () => [{ type: PendingChangesService }] });
|
|
5650
|
-
|
|
5651
5656
|
/**
|
|
5652
5657
|
* Service that provides guards for Material Dialog close operations.
|
|
5653
5658
|
*
|
|
@@ -5803,6 +5808,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
5803
5808
|
type: Injectable
|
|
5804
5809
|
}] });
|
|
5805
5810
|
|
|
5811
|
+
/**
|
|
5812
|
+
* Providing a `PendingChangesComponent`.
|
|
5813
|
+
*/
|
|
5814
|
+
class PendingChangesGuard {
|
|
5815
|
+
constructor(pendingChanges) {
|
|
5816
|
+
this.pendingChanges = pendingChanges;
|
|
5817
|
+
}
|
|
5818
|
+
canDeactivate(component) {
|
|
5819
|
+
// if there are no pending changes, just allow deactivation; else confirm first
|
|
5820
|
+
return !this.pendingChanges.check(component);
|
|
5821
|
+
}
|
|
5822
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: PendingChangesGuard, deps: [{ token: PendingChangesService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5823
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: PendingChangesGuard, providedIn: 'root' }); }
|
|
5824
|
+
}
|
|
5825
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: PendingChangesGuard, decorators: [{
|
|
5826
|
+
type: Injectable,
|
|
5827
|
+
args: [{
|
|
5828
|
+
providedIn: 'root'
|
|
5829
|
+
}]
|
|
5830
|
+
}], ctorParameters: () => [{ type: PendingChangesService }] });
|
|
5831
|
+
|
|
5806
5832
|
class TabGuardDirective {
|
|
5807
5833
|
#tabGroup = inject(MatTabGroup);
|
|
5808
5834
|
#pending = inject(PendingChangesService);
|
|
@@ -6556,5 +6582,5 @@ const provideYuvClientCore = (options = { translations: [] }, customEvents, cust
|
|
|
6556
6582
|
* Generated bundle index. Do not edit.
|
|
6557
6583
|
*/
|
|
6558
6584
|
|
|
6559
|
-
export { AFO_STATE, AVAILABLE_BACKEND_APPS, AdministrationRoles, ApiBase, AppCacheService, AuditField, AuditService, AuthInterceptorFnc, AuthService, BackendService, BaseObjectTypeField, BpmService, CLIENT_APP_REQUIREMENTS, CORE_CONFIG, CUSTOM_CONFIG, CUSTOM_YUV_EVENT_PREFIX, CatalogService, CatalogTypeField, Classification, ClassificationPrefix, ClientCacheService, ClientDefaultsObjectTypeField, ClipboardService, ColumnConfigSkipFields, ConfigService, ConnectionService, ContentStreamAllowed, ContentStreamField, CoreConfig, DEFAULT_LOCK_OPTIONS, DeviceScreenOrientation, DeviceService, DialogCloseGuard, Direction, DmsObject, DmsService, EoxMissingTranslationHandler, EoxTranslateJsonLoader, EventService, FileSizePipe, IdmService, InternalFieldType, KeysPipe, LOCALIZATION_COLUMNS, LOCK_TAG_OWNER_INDEX, LocaleCurrencyPipe, LocaleDatePipe, LocaleDecimalPipe, LocaleNumberPipe, LocalePercentPipe, LocalizationService, LockField, Logger, LoginStateName, NativeNotificationService, NotificationService, ObjectConfigService, ObjectFormControl, ObjectFormControlWrapper, ObjectFormGroup, ObjectLockingService, ObjectTag, ObjectTypeClassification, ObjectTypePropertyClassification, OfflineInterceptorFnc, Operator, OperatorLabel, ParentField, PendingChangesGuard, PendingChangesService, PredictionService, ProcessAction, RelationshipTypeField, RetentionField, RetentionService, SafeHtmlPipe, SafeUrlPipe, SearchService, SearchUtils, SecondaryObjectTypeClassification, SessionStorageService, Situation, Sort, SystemResult, SystemSOT, SystemService, SystemType, TENANT_HEADER, TabGuardDirective, ToastService, UploadService, UserRoles, UserService, UserStorageService, Utils, YUV_USER, YuvError, YuvEventType, YuvUser, findLockTag, init_moduleFnc, provideAvailabilityManagement, provideBeforeUnloadProtection, provideNavigationProtection, providePopstateDialogProtection, provideRequirements, provideUser, provideYuvClientCore };
|
|
6585
|
+
export { AFO_STATE, AVAILABLE_BACKEND_APPS, AdministrationRoles, ApiBase, AppCacheService, AuditAction, AuditField, AuditService, AuthInterceptorFnc, AuthService, BackendService, BaseObjectTypeField, BpmService, CLIENT_APP_REQUIREMENTS, CORE_CONFIG, CUSTOM_CONFIG, CUSTOM_EVENTS, CUSTOM_EVENTS_TRUSTED_ORIGINS, CUSTOM_YUV_EVENT_PREFIX, CatalogService, CatalogTypeField, Classification, ClassificationPrefix, ClientCacheService, ClientDefaultsObjectTypeField, ClipboardService, ColumnConfigSkipFields, ConfigService, ConnectionService, ContentStreamAllowed, ContentStreamField, CoreConfig, DEFAULT_LOCK_OPTIONS, DeviceScreenOrientation, DeviceService, DialogCloseGuard, Direction, DmsObject, DmsService, EoxMissingTranslationHandler, EoxTranslateJsonLoader, EventService, FileSizePipe, IdmService, InternalFieldType, KeysPipe, LOCALIZATION_COLUMNS, LOCK_TAG_OWNER_INDEX, LocaleCurrencyPipe, LocaleDatePipe, LocaleDecimalPipe, LocaleNumberPipe, LocalePercentPipe, LocalizationService, LockField, Logger, LoginStateName, NativeNotificationService, NotificationService, ObjectConfigService, ObjectFormControl, ObjectFormControlWrapper, ObjectFormGroup, ObjectLockingService, ObjectTag, ObjectTypeClassification, ObjectTypePropertyClassification, OfflineInterceptorFnc, Operator, OperatorLabel, ParentField, PendingChangesGuard, PendingChangesService, PredictionService, ProcessAction, RelationshipTypeField, RetentionField, RetentionService, SafeHtmlPipe, SafeUrlPipe, SearchService, SearchUtils, SecondaryObjectTypeClassification, SessionStorageService, Situation, Sort, SystemResult, SystemSOT, SystemService, SystemType, TENANT_HEADER, TabGuardDirective, ToastService, UploadService, UserRoles, UserService, UserStorageService, Utils, YUV_USER, YuvError, YuvEventType, YuvToastStyles, YuvUser, findLockTag, init_moduleFnc, provideAvailabilityManagement, provideBeforeUnloadProtection, provideNavigationProtection, providePopstateDialogProtection, provideRequirements, provideUser, provideYuvClientCore };
|
|
6560
6586
|
//# sourceMappingURL=yuuvis-client-core.mjs.map
|