@yuuvis/client-core 0.7.4 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/index.mjs +5 -1
- package/esm2022/lib/service/clipboard/clipboard.service.mjs +10 -1
- package/esm2022/lib/service/object-config/object-config.service.mjs +1 -2
- package/esm2022/lib/service/retention/retention.interface.mjs +2 -0
- package/esm2022/lib/service/retention/retention.service.mjs +65 -0
- package/esm2022/lib/service/search/search.service.interface.mjs +1 -1
- package/esm2022/lib/service/search/search.service.mjs +84 -1
- package/esm2022/lib/service/search/search.utils.mjs +142 -0
- package/esm2022/lib/service/system/system.enum.mjs +2 -14
- package/esm2022/lib/service/system/system.service.mjs +1 -1
- package/esm2022/lib/service/user/user-storage.service.mjs +38 -0
- package/fesm2022/yuuvis-client-core.mjs +653 -340
- package/fesm2022/yuuvis-client-core.mjs.map +1 -1
- package/index.d.ts +4 -0
- package/lib/service/clipboard/clipboard.service.d.ts +1 -0
- package/lib/service/retention/retention.interface.d.ts +5 -0
- package/lib/service/retention/retention.service.d.ts +26 -0
- package/lib/service/search/search.service.d.ts +10 -1
- package/lib/service/search/search.service.interface.d.ts +3 -1
- package/lib/service/search/search.utils.d.ts +18 -0
- package/lib/service/system/system.enum.d.ts +0 -6
- package/lib/service/user/user-storage.service.d.ts +18 -0
- package/package.json +1 -1
|
@@ -4,8 +4,8 @@ export { TranslateDirective, TranslateLoader, TranslateModule, TranslatePipe, Tr
|
|
|
4
4
|
import * as i0 from '@angular/core';
|
|
5
5
|
import { NgModule, InjectionToken, Inject, Injectable, Optional, inject, APP_INITIALIZER, SkipSelf, Pipe } from '@angular/core';
|
|
6
6
|
import { HttpErrorResponse, HttpHeaders, HttpClient, HttpParams, HttpRequest, HttpEventType, HttpResponse, HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
|
|
7
|
-
import { map, tap, finalize, shareReplay, catchError,
|
|
8
|
-
import { EMPTY, of, from, Observable, forkJoin,
|
|
7
|
+
import { map, tap, finalize, shareReplay, catchError, switchMap, first, filter, scan, delay } from 'rxjs/operators';
|
|
8
|
+
import { EMPTY, of, from, Observable, forkJoin, ReplaySubject, Subject, BehaviorSubject, tap as tap$1, map as map$1, merge, fromEvent, filter as filter$1, debounceTime, throwError, switchMap as switchMap$1 } from 'rxjs';
|
|
9
9
|
import * as i1 from 'angular-oauth2-oidc';
|
|
10
10
|
import { OAuthStorage, OAuthModule } from 'angular-oauth2-oidc';
|
|
11
11
|
import { __decorate, __param, __metadata } from 'tslib';
|
|
@@ -94,7 +94,7 @@ const SystemType = {
|
|
|
94
94
|
SOT: 'system:secondray'
|
|
95
95
|
};
|
|
96
96
|
const SystemResult = {
|
|
97
|
-
DELETE: 'system:deletionResult'
|
|
97
|
+
DELETE: 'system:deletionResult'
|
|
98
98
|
};
|
|
99
99
|
const AdministrationRoles = {
|
|
100
100
|
ADMIN: 'YUUVIS_TENANT_ADMIN',
|
|
@@ -112,17 +112,6 @@ const RetentionField = {
|
|
|
112
112
|
RETENTION_START: 'system:rmStartOfRetention',
|
|
113
113
|
DESTRUCTION_DATE: 'system:rmDestructionDate'
|
|
114
114
|
};
|
|
115
|
-
var RetentionState;
|
|
116
|
-
(function (RetentionState) {
|
|
117
|
-
// no retention
|
|
118
|
-
RetentionState[RetentionState["NONE"] = 0] = "NONE";
|
|
119
|
-
// retention is active
|
|
120
|
-
RetentionState[RetentionState["ACTIVE"] = 1] = "ACTIVE";
|
|
121
|
-
// supposed to be destructed
|
|
122
|
-
RetentionState[RetentionState["DESTRUCT"] = 2] = "DESTRUCT";
|
|
123
|
-
// retention is not active yet
|
|
124
|
-
RetentionState[RetentionState["INACTIVE"] = 3] = "INACTIVE";
|
|
125
|
-
})(RetentionState || (RetentionState = {}));
|
|
126
115
|
const BaseObjectTypeField = {
|
|
127
116
|
OBJECT_TYPE_ID: 'system:objectTypeId',
|
|
128
117
|
VERSION_NUMBER: 'system:versionNumber',
|
|
@@ -229,7 +218,6 @@ var InternalFieldType;
|
|
|
229
218
|
InternalFieldType["STRING_DYNAMIC_CATALOG"] = "string:catalog:dynamic";
|
|
230
219
|
InternalFieldType["BOOLEAN_SWITCH"] = "boolean:switch";
|
|
231
220
|
})(InternalFieldType || (InternalFieldType = {}));
|
|
232
|
-
;
|
|
233
221
|
var ObjectTag;
|
|
234
222
|
(function (ObjectTag) {
|
|
235
223
|
ObjectTag["AFO"] = "appclient:dlm:prepare";
|
|
@@ -1235,179 +1223,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
1235
1223
|
args: [{ providedIn: 'root' }]
|
|
1236
1224
|
}] });
|
|
1237
1225
|
|
|
1238
|
-
class SearchService {
|
|
1239
|
-
#backend = inject(BackendService);
|
|
1240
|
-
static { this.DEFAULT_QUERY_SIZE = 50; }
|
|
1241
|
-
/**
|
|
1242
|
-
* Execute a search query ans transform the result to a SearchResult object
|
|
1243
|
-
* @param query The search query
|
|
1244
|
-
* @returns Observable of a SearchResult
|
|
1245
|
-
*/
|
|
1246
|
-
search(query) {
|
|
1247
|
-
return this.searchRaw(query).pipe(map((res) => this.toSearchResult(res)));
|
|
1248
|
-
}
|
|
1249
|
-
/**
|
|
1250
|
-
* Execute a raw search query and return the result as is.
|
|
1251
|
-
* @param query The search query
|
|
1252
|
-
* @returns Observable of the raw search result
|
|
1253
|
-
*/
|
|
1254
|
-
searchRaw(query) {
|
|
1255
|
-
if (!query.size)
|
|
1256
|
-
query.size = SearchService.DEFAULT_QUERY_SIZE;
|
|
1257
|
-
return this.#backend.post(`/dms/objects/search`, query);
|
|
1258
|
-
}
|
|
1259
|
-
/**
|
|
1260
|
-
* Search for objects in the dms using CMIS like SQL syntax.
|
|
1261
|
-
* @param statement The query statement
|
|
1262
|
-
* @param size The number of items to return
|
|
1263
|
-
* @returns Observable of a SearchResult
|
|
1264
|
-
*/
|
|
1265
|
-
searchCmis(statement, size = 50) {
|
|
1266
|
-
return this.#backend
|
|
1267
|
-
.post('/dms/objects/search', {
|
|
1268
|
-
query: {
|
|
1269
|
-
statement,
|
|
1270
|
-
skipCount: 0,
|
|
1271
|
-
maxItems: size,
|
|
1272
|
-
handleDeletedDocuments: 'DELETED_DOCUMENTS_EXCLUDE'
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
// Using API-WEB because it enriches the response with additional information (resolved user names, etc.)
|
|
1276
|
-
// ApiBase.core
|
|
1277
|
-
)
|
|
1278
|
-
.pipe(map((res) => this.toSearchResult(res)));
|
|
1279
|
-
}
|
|
1280
|
-
/**
|
|
1281
|
-
* Fetch aggragations for a given query.
|
|
1282
|
-
* @param q The query
|
|
1283
|
-
* @param aggregations List of aggregations to be fetched (e.g. `enaio:objectTypeId`
|
|
1284
|
-
* to get an aggregation of object types)
|
|
1285
|
-
*/
|
|
1286
|
-
aggregate(q, aggregations) {
|
|
1287
|
-
q.aggs = aggregations;
|
|
1288
|
-
return this.searchRaw(q).pipe(map((res) => this.#toAggregateResult(res, aggregations)));
|
|
1289
|
-
}
|
|
1290
|
-
/**
|
|
1291
|
-
* Map search result from the backend to applications AggregateResult object
|
|
1292
|
-
* @param searchResponse The backend response
|
|
1293
|
-
* @param aggregations The aggregations to be fetched
|
|
1294
|
-
*/
|
|
1295
|
-
#toAggregateResult(searchResponse, aggregations) {
|
|
1296
|
-
const agg = [];
|
|
1297
|
-
if (aggregations) {
|
|
1298
|
-
aggregations.forEach((a) => {
|
|
1299
|
-
const ag = {
|
|
1300
|
-
aggKey: a,
|
|
1301
|
-
entries: searchResponse.objects.map((o) => ({
|
|
1302
|
-
key: o.properties[a].value,
|
|
1303
|
-
count: o.properties['OBJECT_COUNT'].value
|
|
1304
|
-
}))
|
|
1305
|
-
};
|
|
1306
|
-
agg.push(ag);
|
|
1307
|
-
});
|
|
1308
|
-
}
|
|
1309
|
-
return {
|
|
1310
|
-
totalNumItems: searchResponse.totalNumItems,
|
|
1311
|
-
aggregations: agg
|
|
1312
|
-
};
|
|
1313
|
-
}
|
|
1314
|
-
/**
|
|
1315
|
-
* Go to a page of a search result.
|
|
1316
|
-
* @param searchResult The search result (that supports pagination)
|
|
1317
|
-
* @param page The number of the page to go to
|
|
1318
|
-
*/
|
|
1319
|
-
getPage(query, page) {
|
|
1320
|
-
query.from = (page - 1) * (query.size || SearchService.DEFAULT_QUERY_SIZE);
|
|
1321
|
-
return this.search(query);
|
|
1322
|
-
}
|
|
1323
|
-
/**
|
|
1324
|
-
* Map search result from the backend to applications SearchResult object
|
|
1325
|
-
* @param searchResponse The backend response
|
|
1326
|
-
*/
|
|
1327
|
-
toSearchResult(searchResponse) {
|
|
1328
|
-
const resultListItems = [];
|
|
1329
|
-
const objectTypes = [];
|
|
1330
|
-
searchResponse.objects.forEach((o) => {
|
|
1331
|
-
const fields = new Map();
|
|
1332
|
-
// process properties section of result
|
|
1333
|
-
Object.keys(o.properties).forEach((key) => {
|
|
1334
|
-
let value = o.properties[key].value;
|
|
1335
|
-
if (o.properties[key].clvalue) {
|
|
1336
|
-
// table fields will have a clientValue too ...
|
|
1337
|
-
value = o.properties[key].clvalue;
|
|
1338
|
-
// ... and also may contain values that need to be resolved
|
|
1339
|
-
if (o.properties[key].resolvedValues) {
|
|
1340
|
-
value.forEach((v) => {
|
|
1341
|
-
Object.keys(v).forEach((k) => {
|
|
1342
|
-
const resValue = Array.isArray(v[k]) ? v[k].map((i) => o.properties[key].resolvedValues[i]) : o.properties[key].resolvedValues[v[k]];
|
|
1343
|
-
if (resValue) {
|
|
1344
|
-
v[`${k}_title`] = resValue;
|
|
1345
|
-
}
|
|
1346
|
-
});
|
|
1347
|
-
});
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
fields.set(key, value);
|
|
1351
|
-
if (o.properties[key].title) {
|
|
1352
|
-
fields.set(key + '_title', o.properties[key].title);
|
|
1353
|
-
}
|
|
1354
|
-
});
|
|
1355
|
-
// process contentStreams section of result if available.
|
|
1356
|
-
// Objects that don't have files attached won't have this section
|
|
1357
|
-
let content;
|
|
1358
|
-
if (o.contentStreams && o.contentStreams.length > 0) {
|
|
1359
|
-
// we assume that each result object only has ONE file attached, altough
|
|
1360
|
-
// this is an array and there may be more
|
|
1361
|
-
const contentStream = o.contentStreams[0];
|
|
1362
|
-
// also add contentstream related fields to the result fields
|
|
1363
|
-
fields.set(ContentStreamField.LENGTH, contentStream.length);
|
|
1364
|
-
fields.set(ContentStreamField.MIME_TYPE, contentStream.mimeType);
|
|
1365
|
-
fields.set(ContentStreamField.FILENAME, contentStream.fileName);
|
|
1366
|
-
fields.set(ContentStreamField.ID, contentStream.contentStreamId);
|
|
1367
|
-
fields.set(ContentStreamField.RANGE, contentStream.contentStreamRange);
|
|
1368
|
-
fields.set(ContentStreamField.REPOSITORY_ID, contentStream.repositoryId);
|
|
1369
|
-
fields.set(ContentStreamField.DIGEST, contentStream.digest);
|
|
1370
|
-
fields.set(ContentStreamField.ARCHIVE_PATH, contentStream.archivePath);
|
|
1371
|
-
content = {
|
|
1372
|
-
contentStreamId: contentStream.contentStreamId,
|
|
1373
|
-
repositoryId: contentStream.repositoryId,
|
|
1374
|
-
range: contentStream.range,
|
|
1375
|
-
digest: contentStream.digest,
|
|
1376
|
-
archivePath: contentStream.archivePath,
|
|
1377
|
-
fileName: contentStream.fileName,
|
|
1378
|
-
mimeType: contentStream.mimeType,
|
|
1379
|
-
size: contentStream.length
|
|
1380
|
-
};
|
|
1381
|
-
}
|
|
1382
|
-
const objectTypeId = o.properties[BaseObjectTypeField.OBJECT_TYPE_ID] ? o.properties[BaseObjectTypeField.OBJECT_TYPE_ID].value : null;
|
|
1383
|
-
if (objectTypes.indexOf(objectTypeId) === -1) {
|
|
1384
|
-
objectTypes.push(objectTypeId);
|
|
1385
|
-
}
|
|
1386
|
-
resultListItems.push({
|
|
1387
|
-
objectTypeId,
|
|
1388
|
-
content,
|
|
1389
|
-
fields,
|
|
1390
|
-
permissions: o.permissions
|
|
1391
|
-
});
|
|
1392
|
-
});
|
|
1393
|
-
const result = {
|
|
1394
|
-
hasMoreItems: searchResponse.hasMoreItems,
|
|
1395
|
-
totalNumItems: searchResponse.totalNumItems,
|
|
1396
|
-
items: resultListItems,
|
|
1397
|
-
objectTypes
|
|
1398
|
-
};
|
|
1399
|
-
return result;
|
|
1400
|
-
}
|
|
1401
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SearchService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1402
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SearchService, providedIn: 'root' }); }
|
|
1403
|
-
}
|
|
1404
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SearchService, decorators: [{
|
|
1405
|
-
type: Injectable,
|
|
1406
|
-
args: [{
|
|
1407
|
-
providedIn: 'root'
|
|
1408
|
-
}]
|
|
1409
|
-
}] });
|
|
1410
|
-
|
|
1411
1226
|
var Operator;
|
|
1412
1227
|
(function (Operator) {
|
|
1413
1228
|
Operator["EQUAL"] = "eq";
|
|
@@ -1447,60 +1262,6 @@ const OperatorLabel = {
|
|
|
1447
1262
|
CONTAINS: '~' // contains
|
|
1448
1263
|
};
|
|
1449
1264
|
|
|
1450
|
-
var Direction;
|
|
1451
|
-
(function (Direction) {
|
|
1452
|
-
Direction["LTR"] = "ltr";
|
|
1453
|
-
Direction["RTL"] = "rtl";
|
|
1454
|
-
})(Direction || (Direction = {}));
|
|
1455
|
-
|
|
1456
|
-
/**
|
|
1457
|
-
* Service for providing triggered events
|
|
1458
|
-
*/
|
|
1459
|
-
class EventService {
|
|
1460
|
-
constructor() {
|
|
1461
|
-
this.#eventSource = new Subject();
|
|
1462
|
-
this.event$ = this.#eventSource.asObservable();
|
|
1463
|
-
}
|
|
1464
|
-
#eventSource;
|
|
1465
|
-
/**
|
|
1466
|
-
* Trigger an global event
|
|
1467
|
-
* @param type Type/key of the event
|
|
1468
|
-
* @param data Data to be send along with the event
|
|
1469
|
-
*/
|
|
1470
|
-
trigger(type, data) {
|
|
1471
|
-
this.#eventSource.next({ type, data });
|
|
1472
|
-
}
|
|
1473
|
-
/**
|
|
1474
|
-
* Listen on a triggered event
|
|
1475
|
-
* @param types Type/key of the event
|
|
1476
|
-
*/
|
|
1477
|
-
on(...types) {
|
|
1478
|
-
return this.event$.pipe(filter((event) => event && !!types.find((t) => t === event.type)));
|
|
1479
|
-
}
|
|
1480
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EventService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1481
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EventService, providedIn: 'root' }); }
|
|
1482
|
-
}
|
|
1483
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EventService, decorators: [{
|
|
1484
|
-
type: Injectable,
|
|
1485
|
-
args: [{
|
|
1486
|
-
providedIn: 'root'
|
|
1487
|
-
}]
|
|
1488
|
-
}] });
|
|
1489
|
-
|
|
1490
|
-
/**
|
|
1491
|
-
* Events emitted by parts of the application
|
|
1492
|
-
*/
|
|
1493
|
-
var YuvEventType;
|
|
1494
|
-
(function (YuvEventType) {
|
|
1495
|
-
YuvEventType["LOGOUT"] = "yuv.user.logout";
|
|
1496
|
-
YuvEventType["CLIENT_LOCALE_CHANGED"] = "yuv.user.locale.client.changed";
|
|
1497
|
-
YuvEventType["DMS_OBJECT_LOADED"] = "yuv.dms.object.loaded";
|
|
1498
|
-
YuvEventType["DMS_OBJECT_CREATED"] = "yuv.dms.object.created";
|
|
1499
|
-
YuvEventType["DMS_OBJECT_DELETED"] = "yuv.dms.object.deleted";
|
|
1500
|
-
YuvEventType["DMS_OBJECT_UPDATED"] = "yuv.dms.object.updated";
|
|
1501
|
-
YuvEventType["DMS_OBJECTS_MOVED"] = "yuv.dms.objects.moved";
|
|
1502
|
-
})(YuvEventType || (YuvEventType = {}));
|
|
1503
|
-
|
|
1504
1265
|
/**
|
|
1505
1266
|
* Service for saving or caching data on the users device. It uses the most efficient storage
|
|
1506
1267
|
* available (IndexDB, localstorage, ...) on the device. Depending on the type of storage used,
|
|
@@ -2019,121 +1780,429 @@ class SystemService {
|
|
|
2019
1780
|
return this.#backend.get(Utils.buildUri(`/dms/forms/${objectTypeId}`, { situation }));
|
|
2020
1781
|
}
|
|
2021
1782
|
/**
|
|
2022
|
-
* Check whether or not the model has at least one form element. Recursive.
|
|
2023
|
-
* @param element Form element to check child elements for
|
|
1783
|
+
* Check whether or not the model has at least one form element. Recursive.
|
|
1784
|
+
* @param element Form element to check child elements for
|
|
1785
|
+
*/
|
|
1786
|
+
#formHasElements(element) {
|
|
1787
|
+
let hasElement = false;
|
|
1788
|
+
element.elements?.forEach((e) => {
|
|
1789
|
+
if (!['o2mGroup', 'o2mGroupStack'].includes(e.type)) {
|
|
1790
|
+
hasElement = true;
|
|
1791
|
+
}
|
|
1792
|
+
else if (!hasElement) {
|
|
1793
|
+
hasElement = this.#formHasElements(e);
|
|
1794
|
+
}
|
|
1795
|
+
});
|
|
1796
|
+
return hasElement;
|
|
1797
|
+
}
|
|
1798
|
+
/**
|
|
1799
|
+
* Generates an internal type for a given object type field.
|
|
1800
|
+
* Adding this to a form element or object type field enables us to render forms
|
|
1801
|
+
* based on object type fields in a more performant way. Otherwise we would
|
|
1802
|
+
* have to evaluate the conditions for every form element on every digest cycle.
|
|
1803
|
+
* @param type propertyType of the ObjectTypeField
|
|
1804
|
+
* @param classifications classifications of the ObjectTypeField
|
|
1805
|
+
*/
|
|
1806
|
+
getInternalFormElementType(type, classifications) {
|
|
1807
|
+
const _classifications = this.getClassifications(classifications || []);
|
|
1808
|
+
if (type === 'string' && _classifications.has(Classification.STRING_REFERENCE)) {
|
|
1809
|
+
return InternalFieldType.STRING_REFERENCE;
|
|
1810
|
+
}
|
|
1811
|
+
else if (type === 'string' && _classifications.has(Classification.STRING_ORGANIZATION)) {
|
|
1812
|
+
return InternalFieldType.STRING_ORGANIZATION;
|
|
1813
|
+
}
|
|
1814
|
+
else if (type === 'string' && _classifications.has(Classification.STRING_ORGANIZATION_SET)) {
|
|
1815
|
+
return InternalFieldType.STRING_ORGANIZATION_SET;
|
|
1816
|
+
}
|
|
1817
|
+
else if (type === 'string' && _classifications.has(Classification.STRING_CATALOG)) {
|
|
1818
|
+
return InternalFieldType.STRING_CATALOG;
|
|
1819
|
+
}
|
|
1820
|
+
else if (type === 'boolean' && _classifications.has(Classification.BOOLEAN_SWITCH)) {
|
|
1821
|
+
return InternalFieldType.BOOLEAN_SWITCH;
|
|
1822
|
+
}
|
|
1823
|
+
else if (type === 'string' &&
|
|
1824
|
+
(_classifications.has(Classification.STRING_CATALOG_DYNAMIC) || _classifications.has(Classification.STRING_CATALOG_CUSTOM))) {
|
|
1825
|
+
return InternalFieldType.STRING_DYNAMIC_CATALOG;
|
|
1826
|
+
}
|
|
1827
|
+
else {
|
|
1828
|
+
// if there are no matching conditions just return the original type
|
|
1829
|
+
return type;
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
getObjectTypeField(id) {
|
|
1833
|
+
const f = this.system?.allFields[id];
|
|
1834
|
+
return f ? { ...f, _internalType: this.getInternalFormElementType(f.propertyType, f.classifications) } : undefined;
|
|
1835
|
+
}
|
|
1836
|
+
/**
|
|
1837
|
+
* Extract classifications from object type fields classification
|
|
1838
|
+
* string. This string may contain more than one classification entry.
|
|
1839
|
+
*
|
|
1840
|
+
* Classification is a comma separated string that may contain additional
|
|
1841
|
+
* properties related to on classification entry. Example:
|
|
1842
|
+
*
|
|
1843
|
+
* `id:reference[system:folder], email`
|
|
1844
|
+
*
|
|
1845
|
+
* @param classifications Object type fields classification property (schema)
|
|
1846
|
+
*/
|
|
1847
|
+
getClassifications(classifications) {
|
|
1848
|
+
const res = new Map();
|
|
1849
|
+
if (classifications) {
|
|
1850
|
+
classifications.forEach((c) => {
|
|
1851
|
+
const matches = c.match(/^([^\[]*)(\[(.*)\])?$/);
|
|
1852
|
+
if (matches && matches.length) {
|
|
1853
|
+
res.set(matches[1], {
|
|
1854
|
+
classification: matches[1],
|
|
1855
|
+
options: matches[3] ? matches[3].split(',').map((o) => o.trim()) : []
|
|
1856
|
+
});
|
|
1857
|
+
}
|
|
1858
|
+
});
|
|
1859
|
+
}
|
|
1860
|
+
return res;
|
|
1861
|
+
}
|
|
1862
|
+
toFormElement(field) {
|
|
1863
|
+
return { ...field, label: this.getLocalizedLabel(field.id), name: field.id, type: field.propertyType };
|
|
1864
|
+
}
|
|
1865
|
+
updateAuthData(data) {
|
|
1866
|
+
this.authData = { ...this.authData, ...data };
|
|
1867
|
+
this.#backend.setHeader('Accept-Language', this.authData.language);
|
|
1868
|
+
return this.#appCache.setItem(this.#STORAGE_KEY_AUTH_DATA, this.authData);
|
|
1869
|
+
}
|
|
1870
|
+
updateLocalizations(iso) {
|
|
1871
|
+
return this.updateAuthData({ language: iso }).pipe(switchMap(() => this.#fetchLocalizations()), tap((res) => {
|
|
1872
|
+
this.system.i18n = res;
|
|
1873
|
+
this.#appCache.setItem(this.#STORAGE_KEY, this.system).subscribe();
|
|
1874
|
+
this.#systemSource.next(this.system);
|
|
1875
|
+
}));
|
|
1876
|
+
}
|
|
1877
|
+
#fetchLocalizations() {
|
|
1878
|
+
return this.#backend.get('/resources/text');
|
|
1879
|
+
}
|
|
1880
|
+
fetchResources(id) {
|
|
1881
|
+
return this.#backend
|
|
1882
|
+
.batch([
|
|
1883
|
+
{ uri: `/system/resources/${id}`, base: ApiBase.core },
|
|
1884
|
+
{ uri: `/admin/resources/${id}`, base: ApiBase.core }
|
|
1885
|
+
])
|
|
1886
|
+
.pipe(map(([global, tenant]) => ({ global, tenant })));
|
|
1887
|
+
}
|
|
1888
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SystemService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1889
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SystemService, providedIn: 'root' }); }
|
|
1890
|
+
}
|
|
1891
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SystemService, decorators: [{
|
|
1892
|
+
type: Injectable,
|
|
1893
|
+
args: [{
|
|
1894
|
+
providedIn: 'root'
|
|
1895
|
+
}]
|
|
1896
|
+
}] });
|
|
1897
|
+
|
|
1898
|
+
class SearchService {
|
|
1899
|
+
#backend = inject(BackendService);
|
|
1900
|
+
#system = inject(SystemService);
|
|
1901
|
+
static { this.DEFAULT_QUERY_SIZE = 50; }
|
|
1902
|
+
/**
|
|
1903
|
+
* Execute a search query ans transform the result to a SearchResult object
|
|
1904
|
+
* @param query The search query
|
|
1905
|
+
* @returns Observable of a SearchResult
|
|
1906
|
+
*/
|
|
1907
|
+
search(query) {
|
|
1908
|
+
return this.searchRaw(query).pipe(map((res) => this.toSearchResult(res)));
|
|
1909
|
+
}
|
|
1910
|
+
/**
|
|
1911
|
+
* Execute a raw search query and return the result as is.
|
|
1912
|
+
* @param query The search query
|
|
1913
|
+
* @returns Observable of the raw search result
|
|
1914
|
+
*/
|
|
1915
|
+
searchRaw(query) {
|
|
1916
|
+
if (!query.size)
|
|
1917
|
+
query.size = SearchService.DEFAULT_QUERY_SIZE;
|
|
1918
|
+
return this.#backend.post(`/dms/objects/search`, query);
|
|
1919
|
+
}
|
|
1920
|
+
/**
|
|
1921
|
+
* Search for objects in the dms using CMIS like SQL syntax.
|
|
1922
|
+
* @param statement The query statement
|
|
1923
|
+
* @param size The number of items to return
|
|
1924
|
+
* @returns Observable of a SearchResult
|
|
1925
|
+
*/
|
|
1926
|
+
searchCmis(statement, size = 50) {
|
|
1927
|
+
return this.#backend
|
|
1928
|
+
.post('/dms/objects/search', {
|
|
1929
|
+
query: {
|
|
1930
|
+
statement,
|
|
1931
|
+
skipCount: 0,
|
|
1932
|
+
maxItems: size,
|
|
1933
|
+
handleDeletedDocuments: 'DELETED_DOCUMENTS_EXCLUDE'
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
// Using API-WEB because it enriches the response with additional information (resolved user names, etc.)
|
|
1937
|
+
// ApiBase.core
|
|
1938
|
+
)
|
|
1939
|
+
.pipe(map((res) => this.toSearchResult(res)));
|
|
1940
|
+
}
|
|
1941
|
+
/**
|
|
1942
|
+
* Fetch aggragations for a given query.
|
|
1943
|
+
* @param q The query
|
|
1944
|
+
* @param aggregations List of aggregations to be fetched (e.g. `enaio:objectTypeId`
|
|
1945
|
+
* to get an aggregation of object types)
|
|
1946
|
+
*/
|
|
1947
|
+
aggregate(q, aggregations) {
|
|
1948
|
+
q.aggs = aggregations;
|
|
1949
|
+
return this.searchRaw(q).pipe(map((res) => this.#toAggregateResult(res, aggregations)));
|
|
1950
|
+
}
|
|
1951
|
+
/**
|
|
1952
|
+
* Map search result from the backend to applications AggregateResult object
|
|
1953
|
+
* @param searchResponse The backend response
|
|
1954
|
+
* @param aggregations The aggregations to be fetched
|
|
1955
|
+
*/
|
|
1956
|
+
#toAggregateResult(searchResponse, aggregations) {
|
|
1957
|
+
const agg = [];
|
|
1958
|
+
if (aggregations) {
|
|
1959
|
+
aggregations.forEach((a) => {
|
|
1960
|
+
const ag = {
|
|
1961
|
+
aggKey: a,
|
|
1962
|
+
entries: searchResponse.objects.map((o) => ({
|
|
1963
|
+
key: o.properties[a].value,
|
|
1964
|
+
count: o.properties['OBJECT_COUNT'].value
|
|
1965
|
+
}))
|
|
1966
|
+
};
|
|
1967
|
+
agg.push(ag);
|
|
1968
|
+
});
|
|
1969
|
+
}
|
|
1970
|
+
return {
|
|
1971
|
+
totalNumItems: searchResponse.totalNumItems,
|
|
1972
|
+
aggregations: agg
|
|
1973
|
+
};
|
|
1974
|
+
}
|
|
1975
|
+
/**
|
|
1976
|
+
* Go to a page of a search result.
|
|
1977
|
+
* @param searchResult The search result (that supports pagination)
|
|
1978
|
+
* @param page The number of the page to go to
|
|
1979
|
+
*/
|
|
1980
|
+
getPage(query, page) {
|
|
1981
|
+
query.from = (page - 1) * (query.size || SearchService.DEFAULT_QUERY_SIZE);
|
|
1982
|
+
return this.search(query);
|
|
1983
|
+
}
|
|
1984
|
+
/**
|
|
1985
|
+
* Map search result from the backend to applications SearchResult object
|
|
1986
|
+
* @param searchResponse The backend response
|
|
1987
|
+
*/
|
|
1988
|
+
toSearchResult(searchResponse) {
|
|
1989
|
+
const resultListItems = [];
|
|
1990
|
+
const objectTypes = [];
|
|
1991
|
+
searchResponse.objects.forEach((o) => {
|
|
1992
|
+
const fields = new Map();
|
|
1993
|
+
// process properties section of result
|
|
1994
|
+
Object.keys(o.properties).forEach((key) => {
|
|
1995
|
+
let value = o.properties[key].value;
|
|
1996
|
+
if (o.properties[key].clvalue) {
|
|
1997
|
+
// table fields will have a clientValue too ...
|
|
1998
|
+
value = o.properties[key].clvalue;
|
|
1999
|
+
// ... and also may contain values that need to be resolved
|
|
2000
|
+
if (o.properties[key].resolvedValues) {
|
|
2001
|
+
value.forEach((v) => {
|
|
2002
|
+
Object.keys(v).forEach((k) => {
|
|
2003
|
+
const resValue = Array.isArray(v[k]) ? v[k].map((i) => o.properties[key].resolvedValues[i]) : o.properties[key].resolvedValues[v[k]];
|
|
2004
|
+
if (resValue) {
|
|
2005
|
+
v[`${k}_title`] = resValue;
|
|
2006
|
+
}
|
|
2007
|
+
});
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
fields.set(key, value);
|
|
2012
|
+
if (o.properties[key].title) {
|
|
2013
|
+
fields.set(key + '_title', o.properties[key].title);
|
|
2014
|
+
}
|
|
2015
|
+
});
|
|
2016
|
+
// process contentStreams section of result if available.
|
|
2017
|
+
// Objects that don't have files attached won't have this section
|
|
2018
|
+
let content;
|
|
2019
|
+
if (o.contentStreams && o.contentStreams.length > 0) {
|
|
2020
|
+
// we assume that each result object only has ONE file attached, altough
|
|
2021
|
+
// this is an array and there may be more
|
|
2022
|
+
const contentStream = o.contentStreams[0];
|
|
2023
|
+
// also add contentstream related fields to the result fields
|
|
2024
|
+
fields.set(ContentStreamField.LENGTH, contentStream.length);
|
|
2025
|
+
fields.set(ContentStreamField.MIME_TYPE, contentStream.mimeType);
|
|
2026
|
+
fields.set(ContentStreamField.FILENAME, contentStream.fileName);
|
|
2027
|
+
fields.set(ContentStreamField.ID, contentStream.contentStreamId);
|
|
2028
|
+
fields.set(ContentStreamField.RANGE, contentStream.contentStreamRange);
|
|
2029
|
+
fields.set(ContentStreamField.REPOSITORY_ID, contentStream.repositoryId);
|
|
2030
|
+
fields.set(ContentStreamField.DIGEST, contentStream.digest);
|
|
2031
|
+
fields.set(ContentStreamField.ARCHIVE_PATH, contentStream.archivePath);
|
|
2032
|
+
content = {
|
|
2033
|
+
contentStreamId: contentStream.contentStreamId,
|
|
2034
|
+
repositoryId: contentStream.repositoryId,
|
|
2035
|
+
range: contentStream.range,
|
|
2036
|
+
digest: contentStream.digest,
|
|
2037
|
+
archivePath: contentStream.archivePath,
|
|
2038
|
+
fileName: contentStream.fileName,
|
|
2039
|
+
mimeType: contentStream.mimeType,
|
|
2040
|
+
size: contentStream.length
|
|
2041
|
+
};
|
|
2042
|
+
}
|
|
2043
|
+
const objectTypeId = o.properties[BaseObjectTypeField.OBJECT_TYPE_ID] ? o.properties[BaseObjectTypeField.OBJECT_TYPE_ID].value : null;
|
|
2044
|
+
if (objectTypes.indexOf(objectTypeId) === -1) {
|
|
2045
|
+
objectTypes.push(objectTypeId);
|
|
2046
|
+
}
|
|
2047
|
+
resultListItems.push({
|
|
2048
|
+
objectTypeId,
|
|
2049
|
+
content,
|
|
2050
|
+
fields,
|
|
2051
|
+
permissions: o.permissions
|
|
2052
|
+
});
|
|
2053
|
+
});
|
|
2054
|
+
const result = {
|
|
2055
|
+
hasMoreItems: searchResponse.hasMoreItems,
|
|
2056
|
+
totalNumItems: searchResponse.totalNumItems,
|
|
2057
|
+
items: resultListItems,
|
|
2058
|
+
objectTypes
|
|
2059
|
+
};
|
|
2060
|
+
return result;
|
|
2061
|
+
}
|
|
2062
|
+
/**
|
|
2063
|
+
* Maps data extracted from a search form to search filters. Every key of the form data object
|
|
2064
|
+
* will be mapped to a search filter.
|
|
2065
|
+
* @param formData form data
|
|
2066
|
+
* @returns Array of search filters
|
|
2024
2067
|
*/
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2068
|
+
formDataToSearchFilter(formData) {
|
|
2069
|
+
const isRangeValue = (v) => {
|
|
2070
|
+
return typeof v === 'object' && v !== null && 'firstValue' in v && 'operator' in v;
|
|
2071
|
+
};
|
|
2072
|
+
const filters = [];
|
|
2073
|
+
Object.keys(formData).forEach((key) => {
|
|
2074
|
+
const value = formData[key];
|
|
2075
|
+
if (isRangeValue(value)) {
|
|
2076
|
+
const f = this.rangeValueToSearchFilter(value, key);
|
|
2077
|
+
if (f)
|
|
2078
|
+
filters.push(f);
|
|
2030
2079
|
}
|
|
2031
|
-
else
|
|
2032
|
-
|
|
2080
|
+
else {
|
|
2081
|
+
filters.push({
|
|
2082
|
+
f: key,
|
|
2083
|
+
o: Array.isArray(value) ? Operator.IN : Operator.EQUAL,
|
|
2084
|
+
v1: value
|
|
2085
|
+
});
|
|
2033
2086
|
}
|
|
2034
2087
|
});
|
|
2035
|
-
return
|
|
2088
|
+
return filters;
|
|
2089
|
+
}
|
|
2090
|
+
rangeValueToSearchFilter(value, property) {
|
|
2091
|
+
return this.#system.getObjectTypeField(property)?.propertyType === 'datetime'
|
|
2092
|
+
? this.#dateRangeValueToSearchFilter(value, property)
|
|
2093
|
+
: {
|
|
2094
|
+
f: property,
|
|
2095
|
+
o: value.operator,
|
|
2096
|
+
v1: value.firstValue,
|
|
2097
|
+
v2: value.secondValue
|
|
2098
|
+
};
|
|
2036
2099
|
}
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2100
|
+
#dateRangeValueToSearchFilter(rv, property) {
|
|
2101
|
+
const v1 = rv.firstValue.toISOString();
|
|
2102
|
+
const v2 = rv.secondValue ? rv.secondValue.toISOString() : undefined;
|
|
2103
|
+
let filter;
|
|
2104
|
+
switch (rv.operator) {
|
|
2105
|
+
case Operator.EQUAL: {
|
|
2106
|
+
filter = {
|
|
2107
|
+
f: property,
|
|
2108
|
+
o: Operator.INTERVAL_INCLUDE_BOTH,
|
|
2109
|
+
v1: v1.split('T')[0] + 'T00:00:00.000',
|
|
2110
|
+
v2: v1.split('T')[0] + 'T23:59:59.000'
|
|
2111
|
+
};
|
|
2112
|
+
break;
|
|
2113
|
+
}
|
|
2114
|
+
case Operator.GREATER_OR_EQUAL: {
|
|
2115
|
+
filter = {
|
|
2116
|
+
f: property,
|
|
2117
|
+
o: rv.operator,
|
|
2118
|
+
v1: v1.split('T')[0] + 'T00:00:00.000'
|
|
2119
|
+
};
|
|
2120
|
+
break;
|
|
2121
|
+
}
|
|
2122
|
+
case Operator.LESS_OR_EQUAL: {
|
|
2123
|
+
filter = {
|
|
2124
|
+
f: property,
|
|
2125
|
+
o: rv.operator,
|
|
2126
|
+
v1: v1.split('T')[0] + 'T23:59:59.000'
|
|
2127
|
+
};
|
|
2128
|
+
break;
|
|
2129
|
+
}
|
|
2130
|
+
case Operator.INTERVAL_INCLUDE_BOTH: {
|
|
2131
|
+
filter = {
|
|
2132
|
+
f: property,
|
|
2133
|
+
o: rv.operator,
|
|
2134
|
+
v1: v1.split('T')[0] + 'T00:00:00.000',
|
|
2135
|
+
v2: v2.split('T')[0] + 'T23:59:59.000'
|
|
2136
|
+
};
|
|
2137
|
+
break;
|
|
2138
|
+
}
|
|
2069
2139
|
}
|
|
2140
|
+
return filter;
|
|
2070
2141
|
}
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2142
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SearchService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2143
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SearchService, providedIn: 'root' }); }
|
|
2144
|
+
}
|
|
2145
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SearchService, decorators: [{
|
|
2146
|
+
type: Injectable,
|
|
2147
|
+
args: [{
|
|
2148
|
+
providedIn: 'root'
|
|
2149
|
+
}]
|
|
2150
|
+
}] });
|
|
2151
|
+
|
|
2152
|
+
var Direction;
|
|
2153
|
+
(function (Direction) {
|
|
2154
|
+
Direction["LTR"] = "ltr";
|
|
2155
|
+
Direction["RTL"] = "rtl";
|
|
2156
|
+
})(Direction || (Direction = {}));
|
|
2157
|
+
|
|
2158
|
+
/**
|
|
2159
|
+
* Service for providing triggered events
|
|
2160
|
+
*/
|
|
2161
|
+
class EventService {
|
|
2162
|
+
constructor() {
|
|
2163
|
+
this.#eventSource = new Subject();
|
|
2164
|
+
this.event$ = this.#eventSource.asObservable();
|
|
2074
2165
|
}
|
|
2166
|
+
#eventSource;
|
|
2075
2167
|
/**
|
|
2076
|
-
*
|
|
2077
|
-
*
|
|
2078
|
-
*
|
|
2079
|
-
* Classification is a comma separated string that may contain additional
|
|
2080
|
-
* properties related to on classification entry. Example:
|
|
2081
|
-
*
|
|
2082
|
-
* `id:reference[system:folder], email`
|
|
2083
|
-
*
|
|
2084
|
-
* @param classifications Object type fields classification property (schema)
|
|
2168
|
+
* Trigger an global event
|
|
2169
|
+
* @param type Type/key of the event
|
|
2170
|
+
* @param data Data to be send along with the event
|
|
2085
2171
|
*/
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
if (classifications) {
|
|
2089
|
-
classifications.forEach((c) => {
|
|
2090
|
-
const matches = c.match(/^([^\[]*)(\[(.*)\])?$/);
|
|
2091
|
-
if (matches && matches.length) {
|
|
2092
|
-
res.set(matches[1], {
|
|
2093
|
-
classification: matches[1],
|
|
2094
|
-
options: matches[3] ? matches[3].split(',').map((o) => o.trim()) : []
|
|
2095
|
-
});
|
|
2096
|
-
}
|
|
2097
|
-
});
|
|
2098
|
-
}
|
|
2099
|
-
return res;
|
|
2100
|
-
}
|
|
2101
|
-
toFormElement(field) {
|
|
2102
|
-
return { ...field, label: this.getLocalizedLabel(field.id), name: field.id, type: field.propertyType };
|
|
2103
|
-
}
|
|
2104
|
-
updateAuthData(data) {
|
|
2105
|
-
this.authData = { ...this.authData, ...data };
|
|
2106
|
-
this.#backend.setHeader('Accept-Language', this.authData.language);
|
|
2107
|
-
return this.#appCache.setItem(this.#STORAGE_KEY_AUTH_DATA, this.authData);
|
|
2108
|
-
}
|
|
2109
|
-
updateLocalizations(iso) {
|
|
2110
|
-
return this.updateAuthData({ language: iso }).pipe(switchMap(() => this.#fetchLocalizations()), tap((res) => {
|
|
2111
|
-
this.system.i18n = res;
|
|
2112
|
-
this.#appCache.setItem(this.#STORAGE_KEY, this.system).subscribe();
|
|
2113
|
-
this.#systemSource.next(this.system);
|
|
2114
|
-
}));
|
|
2115
|
-
}
|
|
2116
|
-
#fetchLocalizations() {
|
|
2117
|
-
return this.#backend.get('/resources/text');
|
|
2172
|
+
trigger(type, data) {
|
|
2173
|
+
this.#eventSource.next({ type, data });
|
|
2118
2174
|
}
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
.pipe(map(([global, tenant]) => ({ global, tenant })));
|
|
2175
|
+
/**
|
|
2176
|
+
* Listen on a triggered event
|
|
2177
|
+
* @param types Type/key of the event
|
|
2178
|
+
*/
|
|
2179
|
+
on(...types) {
|
|
2180
|
+
return this.event$.pipe(filter((event) => event && !!types.find((t) => t === event.type)));
|
|
2126
2181
|
}
|
|
2127
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type:
|
|
2128
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type:
|
|
2182
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EventService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2183
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EventService, providedIn: 'root' }); }
|
|
2129
2184
|
}
|
|
2130
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type:
|
|
2185
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EventService, decorators: [{
|
|
2131
2186
|
type: Injectable,
|
|
2132
2187
|
args: [{
|
|
2133
2188
|
providedIn: 'root'
|
|
2134
2189
|
}]
|
|
2135
2190
|
}] });
|
|
2136
2191
|
|
|
2192
|
+
/**
|
|
2193
|
+
* Events emitted by parts of the application
|
|
2194
|
+
*/
|
|
2195
|
+
var YuvEventType;
|
|
2196
|
+
(function (YuvEventType) {
|
|
2197
|
+
YuvEventType["LOGOUT"] = "yuv.user.logout";
|
|
2198
|
+
YuvEventType["CLIENT_LOCALE_CHANGED"] = "yuv.user.locale.client.changed";
|
|
2199
|
+
YuvEventType["DMS_OBJECT_LOADED"] = "yuv.dms.object.loaded";
|
|
2200
|
+
YuvEventType["DMS_OBJECT_CREATED"] = "yuv.dms.object.created";
|
|
2201
|
+
YuvEventType["DMS_OBJECT_DELETED"] = "yuv.dms.object.deleted";
|
|
2202
|
+
YuvEventType["DMS_OBJECT_UPDATED"] = "yuv.dms.object.updated";
|
|
2203
|
+
YuvEventType["DMS_OBJECTS_MOVED"] = "yuv.dms.objects.moved";
|
|
2204
|
+
})(YuvEventType || (YuvEventType = {}));
|
|
2205
|
+
|
|
2137
2206
|
/**
|
|
2138
2207
|
* Service providing user account configurations.
|
|
2139
2208
|
*/
|
|
@@ -2488,7 +2557,6 @@ class ObjectConfigService {
|
|
|
2488
2557
|
#objectConfigs;
|
|
2489
2558
|
// called on core init (auth.service -> initApp)
|
|
2490
2559
|
init() {
|
|
2491
|
-
console.log('ObjectConfigService.init', this.#user.getCurrentUser().userSettings);
|
|
2492
2560
|
return this.#user.loadObjectConfig().pipe(tap$1((res) => {
|
|
2493
2561
|
this.#getDefaultObjectConfig();
|
|
2494
2562
|
this.#objectConfigs = res || {
|
|
@@ -2933,6 +3001,15 @@ class ClipboardService {
|
|
|
2933
3001
|
}
|
|
2934
3002
|
this.#clipboardSource.next(this.#clipboard);
|
|
2935
3003
|
}
|
|
3004
|
+
async addToNavigatorClipBoard(data) {
|
|
3005
|
+
try {
|
|
3006
|
+
await navigator.clipboard.writeText(data);
|
|
3007
|
+
console.log('Text copied to clipboard');
|
|
3008
|
+
}
|
|
3009
|
+
catch (error) {
|
|
3010
|
+
console.error('Failed to copy text: ', error);
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
2936
3013
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ClipboardService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2937
3014
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ClipboardService, providedIn: 'root' }); }
|
|
2938
3015
|
}
|
|
@@ -4140,6 +4217,208 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
4140
4217
|
}]
|
|
4141
4218
|
}] });
|
|
4142
4219
|
|
|
4220
|
+
/**
|
|
4221
|
+
* Service to manage retention for DMS objects. This service allows to set retention
|
|
4222
|
+
* for objects and revert retention if necessary/possible.
|
|
4223
|
+
*/
|
|
4224
|
+
class RetentionService {
|
|
4225
|
+
#dms = inject(DmsService);
|
|
4226
|
+
/**
|
|
4227
|
+
* Set retention for given objects. This will add the retention SOT to the objects
|
|
4228
|
+
* and set the retention start and end date. If the retetion start date is in the
|
|
4229
|
+
* future, you can revert the retention until then by calling `revertRetention`.
|
|
4230
|
+
* @param dmsObjects The objects to set retention for
|
|
4231
|
+
* @param retentionStart Date when retention period should begin
|
|
4232
|
+
* @param retentionEnd Date when retention period should end
|
|
4233
|
+
* @param destructionDate Date when the object should be destroyed. This right now is just a
|
|
4234
|
+
* marker and has no effect on the object lifecycle.
|
|
4235
|
+
* @returns The updated objects
|
|
4236
|
+
*/
|
|
4237
|
+
setRetention(dmsObjects, retentionStart, retentionEnd, destructionDate) {
|
|
4238
|
+
const payload = [];
|
|
4239
|
+
dmsObjects.forEach((o) => {
|
|
4240
|
+
const data = {
|
|
4241
|
+
[BaseObjectTypeField.SECONDARY_OBJECT_TYPE_IDS]: [
|
|
4242
|
+
...o.data[BaseObjectTypeField.SECONDARY_OBJECT_TYPE_IDS],
|
|
4243
|
+
SystemSOT.DESTRUCTION_RETENTION
|
|
4244
|
+
],
|
|
4245
|
+
[RetentionField.RETENTION_START]: retentionStart
|
|
4246
|
+
};
|
|
4247
|
+
if (retentionEnd)
|
|
4248
|
+
data[RetentionField.RETENTION_END] = retentionEnd;
|
|
4249
|
+
if (destructionDate)
|
|
4250
|
+
data[RetentionField.DESTRUCTION_DATE] = destructionDate;
|
|
4251
|
+
payload.push({ id: o.id, data });
|
|
4252
|
+
});
|
|
4253
|
+
return this.#dms.updateDmsObjects(payload);
|
|
4254
|
+
}
|
|
4255
|
+
getRetentionState(dmsObject) {
|
|
4256
|
+
const hasRetentionSOT = dmsObject.data[BaseObjectTypeField.SECONDARY_OBJECT_TYPE_IDS].includes(SystemSOT.DESTRUCTION_RETENTION);
|
|
4257
|
+
if (hasRetentionSOT) {
|
|
4258
|
+
const now = new Date();
|
|
4259
|
+
const retentionStart = new Date(dmsObject.data[RetentionField.RETENTION_START]);
|
|
4260
|
+
const retentionEnd = dmsObject.data[RetentionField.RETENTION_END] ? new Date(dmsObject.data[RetentionField.RETENTION_END]) : null;
|
|
4261
|
+
const underRetention = !!(retentionStart < now || (retentionEnd && retentionEnd > now));
|
|
4262
|
+
return {
|
|
4263
|
+
underRetention,
|
|
4264
|
+
start: new Date(retentionStart),
|
|
4265
|
+
end: retentionEnd ? new Date(retentionEnd) : undefined
|
|
4266
|
+
};
|
|
4267
|
+
}
|
|
4268
|
+
else
|
|
4269
|
+
return { underRetention: false };
|
|
4270
|
+
}
|
|
4271
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RetentionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4272
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RetentionService, providedIn: 'root' }); }
|
|
4273
|
+
}
|
|
4274
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RetentionService, decorators: [{
|
|
4275
|
+
type: Injectable,
|
|
4276
|
+
args: [{
|
|
4277
|
+
providedIn: 'root'
|
|
4278
|
+
}]
|
|
4279
|
+
}] });
|
|
4280
|
+
|
|
4281
|
+
class SearchUtils {
|
|
4282
|
+
static { this.dateRanges = ['today', 'yesterday', 'thisWeek', 'lastWeek', 'thisMonth', 'lastMonth', 'thisYear', 'lastYear']; }
|
|
4283
|
+
static { this.filesizeRanges = ['small', 'medium', 'large', 'verylarge']; }
|
|
4284
|
+
static dateRangeStartEnd(dateRange) {
|
|
4285
|
+
let start;
|
|
4286
|
+
let end;
|
|
4287
|
+
switch (dateRange) {
|
|
4288
|
+
case 'today': {
|
|
4289
|
+
start = new Date();
|
|
4290
|
+
end = new Date();
|
|
4291
|
+
break;
|
|
4292
|
+
}
|
|
4293
|
+
case 'yesterday': {
|
|
4294
|
+
const yesterday = new Date();
|
|
4295
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
4296
|
+
start = yesterday;
|
|
4297
|
+
end = yesterday;
|
|
4298
|
+
break;
|
|
4299
|
+
}
|
|
4300
|
+
case 'thisWeek': {
|
|
4301
|
+
const firstDay = new Date();
|
|
4302
|
+
firstDay.setDate(firstDay.getDate() - firstDay.getDay());
|
|
4303
|
+
start = firstDay;
|
|
4304
|
+
end = new Date();
|
|
4305
|
+
break;
|
|
4306
|
+
}
|
|
4307
|
+
case 'lastWeek': {
|
|
4308
|
+
const firstDay = new Date();
|
|
4309
|
+
firstDay.setDate(firstDay.getDate() - firstDay.getDay() - 7);
|
|
4310
|
+
const lastDay = new Date();
|
|
4311
|
+
lastDay.setDate(lastDay.getDate() - lastDay.getDay() - 1);
|
|
4312
|
+
start = firstDay;
|
|
4313
|
+
end = lastDay;
|
|
4314
|
+
break;
|
|
4315
|
+
}
|
|
4316
|
+
case 'thisMonth': {
|
|
4317
|
+
const firstDay = new Date();
|
|
4318
|
+
firstDay.setDate(1);
|
|
4319
|
+
start = firstDay;
|
|
4320
|
+
end = new Date();
|
|
4321
|
+
break;
|
|
4322
|
+
}
|
|
4323
|
+
case 'lastMonth': {
|
|
4324
|
+
const firstDay = new Date();
|
|
4325
|
+
firstDay.setDate(1);
|
|
4326
|
+
firstDay.setMonth(firstDay.getMonth() - 1);
|
|
4327
|
+
const lastDay = new Date();
|
|
4328
|
+
lastDay.setDate(0);
|
|
4329
|
+
start = firstDay;
|
|
4330
|
+
end = lastDay;
|
|
4331
|
+
break;
|
|
4332
|
+
}
|
|
4333
|
+
case 'thisYear': {
|
|
4334
|
+
const firstDay = new Date();
|
|
4335
|
+
firstDay.setMonth(0);
|
|
4336
|
+
firstDay.setDate(1);
|
|
4337
|
+
start = firstDay;
|
|
4338
|
+
end = new Date();
|
|
4339
|
+
break;
|
|
4340
|
+
}
|
|
4341
|
+
case 'lastYear': {
|
|
4342
|
+
const firstDay = new Date();
|
|
4343
|
+
firstDay.setFullYear(firstDay.getFullYear() - 1);
|
|
4344
|
+
firstDay.setMonth(0);
|
|
4345
|
+
firstDay.setDate(1);
|
|
4346
|
+
const lastDay = new Date();
|
|
4347
|
+
lastDay.setFullYear(lastDay.getFullYear() - 1);
|
|
4348
|
+
lastDay.setMonth(11);
|
|
4349
|
+
lastDay.setDate(31);
|
|
4350
|
+
start = firstDay;
|
|
4351
|
+
end = lastDay;
|
|
4352
|
+
break;
|
|
4353
|
+
}
|
|
4354
|
+
}
|
|
4355
|
+
return { start, end };
|
|
4356
|
+
}
|
|
4357
|
+
/**
|
|
4358
|
+
* Maps a date range filter to a date range value like 'thisWeek', 'lastMonth', etc.
|
|
4359
|
+
* @param rangeValue the range value
|
|
4360
|
+
* @returns the date range (eg. 'thisWeek', 'lastMonth', etc.)
|
|
4361
|
+
*/
|
|
4362
|
+
static getMatchingDateRange(rangeValue) {
|
|
4363
|
+
return SearchUtils.dateRanges.find((dateRange) => {
|
|
4364
|
+
const { start, end } = SearchUtils.dateRangeStartEnd(dateRange);
|
|
4365
|
+
return (rangeValue.firstValue === start.toISOString().split('T')[0] + 'T00:00:00.000' &&
|
|
4366
|
+
rangeValue.secondValue === end.toISOString().split('T')[0] + 'T23:59:59.000');
|
|
4367
|
+
});
|
|
4368
|
+
}
|
|
4369
|
+
// Files size ranges
|
|
4370
|
+
static getMatchingFilesizeRange(rangeValue) {
|
|
4371
|
+
let filesizeRange = undefined;
|
|
4372
|
+
if (rangeValue.operator === Operator.INTERVAL_INCLUDE_BOTH) {
|
|
4373
|
+
if (rangeValue.firstValue === 1024 * 1024 && rangeValue.secondValue === 1024 * 1024 * 10)
|
|
4374
|
+
filesizeRange = 'medium';
|
|
4375
|
+
else if (rangeValue.firstValue === 1024 * 1024 * 10 && rangeValue.secondValue === 1024 * 1024 * 100)
|
|
4376
|
+
filesizeRange = 'large';
|
|
4377
|
+
}
|
|
4378
|
+
else if (rangeValue.operator === Operator.LESS_THAN) {
|
|
4379
|
+
if (rangeValue.firstValue === 1024 * 1024)
|
|
4380
|
+
filesizeRange = 'small';
|
|
4381
|
+
}
|
|
4382
|
+
else if (rangeValue.operator === Operator.GREATER_THAN) {
|
|
4383
|
+
if (rangeValue.firstValue === 1024 * 1024 * 100)
|
|
4384
|
+
filesizeRange = 'verylarge';
|
|
4385
|
+
}
|
|
4386
|
+
return filesizeRange;
|
|
4387
|
+
}
|
|
4388
|
+
static filesizeRangeToRangeValue(filesizeRange) {
|
|
4389
|
+
let rv = undefined;
|
|
4390
|
+
switch (filesizeRange) {
|
|
4391
|
+
case 'small':
|
|
4392
|
+
rv = {
|
|
4393
|
+
operator: Operator.LESS_THAN,
|
|
4394
|
+
firstValue: 1024 * 1024
|
|
4395
|
+
};
|
|
4396
|
+
break;
|
|
4397
|
+
case 'medium':
|
|
4398
|
+
rv = {
|
|
4399
|
+
operator: Operator.INTERVAL_INCLUDE_BOTH,
|
|
4400
|
+
firstValue: 1024 * 1024,
|
|
4401
|
+
secondValue: 1024 * 1024 * 10
|
|
4402
|
+
};
|
|
4403
|
+
break;
|
|
4404
|
+
case 'large':
|
|
4405
|
+
rv = {
|
|
4406
|
+
operator: Operator.INTERVAL_INCLUDE_BOTH,
|
|
4407
|
+
firstValue: 1024 * 1024 * 10,
|
|
4408
|
+
secondValue: 1024 * 1024 * 100
|
|
4409
|
+
};
|
|
4410
|
+
break;
|
|
4411
|
+
case 'verylarge':
|
|
4412
|
+
rv = {
|
|
4413
|
+
operator: Operator.GREATER_THAN,
|
|
4414
|
+
firstValue: 1024 * 1024 * 100
|
|
4415
|
+
};
|
|
4416
|
+
break;
|
|
4417
|
+
}
|
|
4418
|
+
return rv;
|
|
4419
|
+
}
|
|
4420
|
+
}
|
|
4421
|
+
|
|
4143
4422
|
class SessionStorageService {
|
|
4144
4423
|
#TEMP_STORAGE_ENTRIES_KEY = 'yuv.core.sessionstorage.entries';
|
|
4145
4424
|
constructor() {
|
|
@@ -4188,6 +4467,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
4188
4467
|
}]
|
|
4189
4468
|
}], ctorParameters: () => [] });
|
|
4190
4469
|
|
|
4470
|
+
/**
|
|
4471
|
+
* Service providing user related remote storage. This service is used load and
|
|
4472
|
+
* store user related data from any device.
|
|
4473
|
+
*/
|
|
4474
|
+
class UserStorageService {
|
|
4475
|
+
#backend = inject(BackendService);
|
|
4476
|
+
#USERS_SETTINGS = '/users/settings';
|
|
4477
|
+
// prefix to be added to every section key to be able to later distinguish
|
|
4478
|
+
// between user settings and other settings
|
|
4479
|
+
#SECTION_PREFIX = 'x-user-';
|
|
4480
|
+
/**
|
|
4481
|
+
*
|
|
4482
|
+
* @param section section key for
|
|
4483
|
+
* @param value value to be stored
|
|
4484
|
+
*/
|
|
4485
|
+
getItem(section) {
|
|
4486
|
+
return this.#backend.get(`${this.#USERS_SETTINGS}/${this.#sanitizeSection(this.#SECTION_PREFIX + section)}`);
|
|
4487
|
+
}
|
|
4488
|
+
setItem(section, data) {
|
|
4489
|
+
return this.getItem(section).pipe(switchMap$1((current) => this.#backend.post(`${this.#USERS_SETTINGS}/${this.#sanitizeSection(this.#SECTION_PREFIX + section)}`, { ...current, ...data })));
|
|
4490
|
+
}
|
|
4491
|
+
#sanitizeSection(section) {
|
|
4492
|
+
return encodeURIComponent(section);
|
|
4493
|
+
}
|
|
4494
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: UserStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4495
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: UserStorageService, providedIn: 'root' }); }
|
|
4496
|
+
}
|
|
4497
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: UserStorageService, decorators: [{
|
|
4498
|
+
type: Injectable,
|
|
4499
|
+
args: [{
|
|
4500
|
+
providedIn: 'root'
|
|
4501
|
+
}]
|
|
4502
|
+
}] });
|
|
4503
|
+
|
|
4191
4504
|
/**
|
|
4192
4505
|
* Prevent app from running into 401 issues related to gateway timeouts.
|
|
4193
4506
|
*/
|
|
@@ -4771,5 +5084,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
4771
5084
|
* Generated bundle index. Do not edit.
|
|
4772
5085
|
*/
|
|
4773
5086
|
|
|
4774
|
-
export { AFO_STATE, AdministrationRoles, ApiBase, AppCacheService, AuditField, AuditService, AuthService, BackendService, BaseObjectTypeField, BpmService, CORE_CONFIG, CUSTOM_CONFIG, CatalogService, Classification, ClassificationPrefix, ClientDefaultsObjectTypeField, ClipboardService, ColumnConfigSkipFields, ConfigService, ConnectionService, ContentStreamAllowed, ContentStreamField, CoreConfig, DeviceScreenOrientation, DeviceService, Direction, DmsObject, DmsService, EventService, FileSizePipe, IdmService, InternalFieldType, KeysPipe, LocaleCurrencyPipe, LocaleDatePipe, LocaleDecimalPipe, LocaleNumberPipe, LocalePercentPipe, Logger, LoginStateName, NativeNotificationService, NotificationService, ObjectConfigService, ObjectTag, ObjectTypeClassification, ObjectTypePropertyClassification, OidcService, Operator, OperatorLabel, ParentField, PendingChangesGuard, PendingChangesService, PredictionService, ProcessAction, RetentionField,
|
|
5087
|
+
export { AFO_STATE, AdministrationRoles, ApiBase, AppCacheService, AuditField, AuditService, AuthService, BackendService, BaseObjectTypeField, BpmService, CORE_CONFIG, CUSTOM_CONFIG, CatalogService, Classification, ClassificationPrefix, ClientDefaultsObjectTypeField, ClipboardService, ColumnConfigSkipFields, ConfigService, ConnectionService, ContentStreamAllowed, ContentStreamField, CoreConfig, DeviceScreenOrientation, DeviceService, Direction, DmsObject, DmsService, EventService, FileSizePipe, IdmService, InternalFieldType, KeysPipe, LocaleCurrencyPipe, LocaleDatePipe, LocaleDecimalPipe, LocaleNumberPipe, LocalePercentPipe, Logger, LoginStateName, NativeNotificationService, NotificationService, ObjectConfigService, ObjectTag, ObjectTypeClassification, ObjectTypePropertyClassification, OidcService, Operator, OperatorLabel, ParentField, PendingChangesGuard, PendingChangesService, PredictionService, ProcessAction, RetentionField, RetentionService, SafeHtmlPipe, SafeUrlPipe, SearchService, SearchUtils, SecondaryObjectTypeClassification, SessionStorageService, Situation, Sort, SystemResult, SystemSOT, SystemService, SystemType, TENANT_HEADER, UploadService, UserRoles, UserService, UserStorageService, Utils, YuvClientCoreModule, YuvClientCoreSharedModule, YuvError, YuvEventType, YuvUser, init_moduleFnc, storageFactory };
|
|
4775
5088
|
//# sourceMappingURL=yuuvis-client-core.mjs.map
|