@yuuvis/client-core 0.7.3 → 0.8.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.
@@ -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, filter, switchMap, first, scan, delay } from 'rxjs/operators';
8
- import { EMPTY, of, from, Observable, forkJoin, Subject, ReplaySubject, BehaviorSubject, tap as tap$1, map as map$1, merge, fromEvent, filter as filter$1, debounceTime, throwError } from 'rxjs';
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 } 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';
@@ -1235,179 +1235,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
1235
1235
  args: [{ providedIn: 'root' }]
1236
1236
  }] });
1237
1237
 
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
1238
  var Operator;
1412
1239
  (function (Operator) {
1413
1240
  Operator["EQUAL"] = "eq";
@@ -1447,60 +1274,6 @@ const OperatorLabel = {
1447
1274
  CONTAINS: '~' // contains
1448
1275
  };
1449
1276
 
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
1277
  /**
1505
1278
  * Service for saving or caching data on the users device. It uses the most efficient storage
1506
1279
  * available (IndexDB, localstorage, ...) on the device. Depending on the type of storage used,
@@ -2019,121 +1792,429 @@ class SystemService {
2019
1792
  return this.#backend.get(Utils.buildUri(`/dms/forms/${objectTypeId}`, { situation }));
2020
1793
  }
2021
1794
  /**
2022
- * Check whether or not the model has at least one form element. Recursive.
2023
- * @param element Form element to check child elements for
1795
+ * Check whether or not the model has at least one form element. Recursive.
1796
+ * @param element Form element to check child elements for
1797
+ */
1798
+ #formHasElements(element) {
1799
+ let hasElement = false;
1800
+ element.elements?.forEach((e) => {
1801
+ if (!['o2mGroup', 'o2mGroupStack'].includes(e.type)) {
1802
+ hasElement = true;
1803
+ }
1804
+ else if (!hasElement) {
1805
+ hasElement = this.#formHasElements(e);
1806
+ }
1807
+ });
1808
+ return hasElement;
1809
+ }
1810
+ /**
1811
+ * Generates an internal type for a given object type field.
1812
+ * Adding this to a form element or object type field enables us to render forms
1813
+ * based on object type fields in a more performant way. Otherwise we would
1814
+ * have to evaluate the conditions for every form element on every digest cycle.
1815
+ * @param type propertyType of the ObjectTypeField
1816
+ * @param classifications classifications of the ObjectTypeField
1817
+ */
1818
+ getInternalFormElementType(type, classifications) {
1819
+ const _classifications = this.getClassifications(classifications || []);
1820
+ if (type === 'string' && _classifications.has(Classification.STRING_REFERENCE)) {
1821
+ return InternalFieldType.STRING_REFERENCE;
1822
+ }
1823
+ else if (type === 'string' && _classifications.has(Classification.STRING_ORGANIZATION)) {
1824
+ return InternalFieldType.STRING_ORGANIZATION;
1825
+ }
1826
+ else if (type === 'string' && _classifications.has(Classification.STRING_ORGANIZATION_SET)) {
1827
+ return InternalFieldType.STRING_ORGANIZATION_SET;
1828
+ }
1829
+ else if (type === 'string' && _classifications.has(Classification.STRING_CATALOG)) {
1830
+ return InternalFieldType.STRING_CATALOG;
1831
+ }
1832
+ else if (type === 'boolean' && _classifications.has(Classification.BOOLEAN_SWITCH)) {
1833
+ return InternalFieldType.BOOLEAN_SWITCH;
1834
+ }
1835
+ else if (type === 'string' &&
1836
+ (_classifications.has(Classification.STRING_CATALOG_DYNAMIC) || _classifications.has(Classification.STRING_CATALOG_CUSTOM))) {
1837
+ return InternalFieldType.STRING_DYNAMIC_CATALOG;
1838
+ }
1839
+ else {
1840
+ // if there are no matching conditions just return the original type
1841
+ return type;
1842
+ }
1843
+ }
1844
+ getObjectTypeField(id) {
1845
+ const f = this.system?.allFields[id];
1846
+ return f ? { ...f, _internalType: this.getInternalFormElementType(f.propertyType, f.classifications) } : undefined;
1847
+ }
1848
+ /**
1849
+ * Extract classifications from object type fields classification
1850
+ * string. This string may contain more than one classification entry.
1851
+ *
1852
+ * Classification is a comma separated string that may contain additional
1853
+ * properties related to on classification entry. Example:
1854
+ *
1855
+ * `id:reference[system:folder], email`
1856
+ *
1857
+ * @param classifications Object type fields classification property (schema)
1858
+ */
1859
+ getClassifications(classifications) {
1860
+ const res = new Map();
1861
+ if (classifications) {
1862
+ classifications.forEach((c) => {
1863
+ const matches = c.match(/^([^\[]*)(\[(.*)\])?$/);
1864
+ if (matches && matches.length) {
1865
+ res.set(matches[1], {
1866
+ classification: matches[1],
1867
+ options: matches[3] ? matches[3].split(',').map((o) => o.trim()) : []
1868
+ });
1869
+ }
1870
+ });
1871
+ }
1872
+ return res;
1873
+ }
1874
+ toFormElement(field) {
1875
+ return { ...field, label: this.getLocalizedLabel(field.id), name: field.id, type: field.propertyType };
1876
+ }
1877
+ updateAuthData(data) {
1878
+ this.authData = { ...this.authData, ...data };
1879
+ this.#backend.setHeader('Accept-Language', this.authData.language);
1880
+ return this.#appCache.setItem(this.#STORAGE_KEY_AUTH_DATA, this.authData);
1881
+ }
1882
+ updateLocalizations(iso) {
1883
+ return this.updateAuthData({ language: iso }).pipe(switchMap(() => this.#fetchLocalizations()), tap((res) => {
1884
+ this.system.i18n = res;
1885
+ this.#appCache.setItem(this.#STORAGE_KEY, this.system).subscribe();
1886
+ this.#systemSource.next(this.system);
1887
+ }));
1888
+ }
1889
+ #fetchLocalizations() {
1890
+ return this.#backend.get('/resources/text');
1891
+ }
1892
+ fetchResources(id) {
1893
+ return this.#backend
1894
+ .batch([
1895
+ { uri: `/system/resources/${id}`, base: ApiBase.core },
1896
+ { uri: `/admin/resources/${id}`, base: ApiBase.core }
1897
+ ])
1898
+ .pipe(map(([global, tenant]) => ({ global, tenant })));
1899
+ }
1900
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SystemService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1901
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SystemService, providedIn: 'root' }); }
1902
+ }
1903
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SystemService, decorators: [{
1904
+ type: Injectable,
1905
+ args: [{
1906
+ providedIn: 'root'
1907
+ }]
1908
+ }] });
1909
+
1910
+ class SearchService {
1911
+ #backend = inject(BackendService);
1912
+ #system = inject(SystemService);
1913
+ static { this.DEFAULT_QUERY_SIZE = 50; }
1914
+ /**
1915
+ * Execute a search query ans transform the result to a SearchResult object
1916
+ * @param query The search query
1917
+ * @returns Observable of a SearchResult
1918
+ */
1919
+ search(query) {
1920
+ return this.searchRaw(query).pipe(map((res) => this.toSearchResult(res)));
1921
+ }
1922
+ /**
1923
+ * Execute a raw search query and return the result as is.
1924
+ * @param query The search query
1925
+ * @returns Observable of the raw search result
1926
+ */
1927
+ searchRaw(query) {
1928
+ if (!query.size)
1929
+ query.size = SearchService.DEFAULT_QUERY_SIZE;
1930
+ return this.#backend.post(`/dms/objects/search`, query);
1931
+ }
1932
+ /**
1933
+ * Search for objects in the dms using CMIS like SQL syntax.
1934
+ * @param statement The query statement
1935
+ * @param size The number of items to return
1936
+ * @returns Observable of a SearchResult
1937
+ */
1938
+ searchCmis(statement, size = 50) {
1939
+ return this.#backend
1940
+ .post('/dms/objects/search', {
1941
+ query: {
1942
+ statement,
1943
+ skipCount: 0,
1944
+ maxItems: size,
1945
+ handleDeletedDocuments: 'DELETED_DOCUMENTS_EXCLUDE'
1946
+ }
1947
+ }
1948
+ // Using API-WEB because it enriches the response with additional information (resolved user names, etc.)
1949
+ // ApiBase.core
1950
+ )
1951
+ .pipe(map((res) => this.toSearchResult(res)));
1952
+ }
1953
+ /**
1954
+ * Fetch aggragations for a given query.
1955
+ * @param q The query
1956
+ * @param aggregations List of aggregations to be fetched (e.g. `enaio:objectTypeId`
1957
+ * to get an aggregation of object types)
1958
+ */
1959
+ aggregate(q, aggregations) {
1960
+ q.aggs = aggregations;
1961
+ return this.searchRaw(q).pipe(map((res) => this.#toAggregateResult(res, aggregations)));
1962
+ }
1963
+ /**
1964
+ * Map search result from the backend to applications AggregateResult object
1965
+ * @param searchResponse The backend response
1966
+ * @param aggregations The aggregations to be fetched
1967
+ */
1968
+ #toAggregateResult(searchResponse, aggregations) {
1969
+ const agg = [];
1970
+ if (aggregations) {
1971
+ aggregations.forEach((a) => {
1972
+ const ag = {
1973
+ aggKey: a,
1974
+ entries: searchResponse.objects.map((o) => ({
1975
+ key: o.properties[a].value,
1976
+ count: o.properties['OBJECT_COUNT'].value
1977
+ }))
1978
+ };
1979
+ agg.push(ag);
1980
+ });
1981
+ }
1982
+ return {
1983
+ totalNumItems: searchResponse.totalNumItems,
1984
+ aggregations: agg
1985
+ };
1986
+ }
1987
+ /**
1988
+ * Go to a page of a search result.
1989
+ * @param searchResult The search result (that supports pagination)
1990
+ * @param page The number of the page to go to
1991
+ */
1992
+ getPage(query, page) {
1993
+ query.from = (page - 1) * (query.size || SearchService.DEFAULT_QUERY_SIZE);
1994
+ return this.search(query);
1995
+ }
1996
+ /**
1997
+ * Map search result from the backend to applications SearchResult object
1998
+ * @param searchResponse The backend response
1999
+ */
2000
+ toSearchResult(searchResponse) {
2001
+ const resultListItems = [];
2002
+ const objectTypes = [];
2003
+ searchResponse.objects.forEach((o) => {
2004
+ const fields = new Map();
2005
+ // process properties section of result
2006
+ Object.keys(o.properties).forEach((key) => {
2007
+ let value = o.properties[key].value;
2008
+ if (o.properties[key].clvalue) {
2009
+ // table fields will have a clientValue too ...
2010
+ value = o.properties[key].clvalue;
2011
+ // ... and also may contain values that need to be resolved
2012
+ if (o.properties[key].resolvedValues) {
2013
+ value.forEach((v) => {
2014
+ Object.keys(v).forEach((k) => {
2015
+ const resValue = Array.isArray(v[k]) ? v[k].map((i) => o.properties[key].resolvedValues[i]) : o.properties[key].resolvedValues[v[k]];
2016
+ if (resValue) {
2017
+ v[`${k}_title`] = resValue;
2018
+ }
2019
+ });
2020
+ });
2021
+ }
2022
+ }
2023
+ fields.set(key, value);
2024
+ if (o.properties[key].title) {
2025
+ fields.set(key + '_title', o.properties[key].title);
2026
+ }
2027
+ });
2028
+ // process contentStreams section of result if available.
2029
+ // Objects that don't have files attached won't have this section
2030
+ let content;
2031
+ if (o.contentStreams && o.contentStreams.length > 0) {
2032
+ // we assume that each result object only has ONE file attached, altough
2033
+ // this is an array and there may be more
2034
+ const contentStream = o.contentStreams[0];
2035
+ // also add contentstream related fields to the result fields
2036
+ fields.set(ContentStreamField.LENGTH, contentStream.length);
2037
+ fields.set(ContentStreamField.MIME_TYPE, contentStream.mimeType);
2038
+ fields.set(ContentStreamField.FILENAME, contentStream.fileName);
2039
+ fields.set(ContentStreamField.ID, contentStream.contentStreamId);
2040
+ fields.set(ContentStreamField.RANGE, contentStream.contentStreamRange);
2041
+ fields.set(ContentStreamField.REPOSITORY_ID, contentStream.repositoryId);
2042
+ fields.set(ContentStreamField.DIGEST, contentStream.digest);
2043
+ fields.set(ContentStreamField.ARCHIVE_PATH, contentStream.archivePath);
2044
+ content = {
2045
+ contentStreamId: contentStream.contentStreamId,
2046
+ repositoryId: contentStream.repositoryId,
2047
+ range: contentStream.range,
2048
+ digest: contentStream.digest,
2049
+ archivePath: contentStream.archivePath,
2050
+ fileName: contentStream.fileName,
2051
+ mimeType: contentStream.mimeType,
2052
+ size: contentStream.length
2053
+ };
2054
+ }
2055
+ const objectTypeId = o.properties[BaseObjectTypeField.OBJECT_TYPE_ID] ? o.properties[BaseObjectTypeField.OBJECT_TYPE_ID].value : null;
2056
+ if (objectTypes.indexOf(objectTypeId) === -1) {
2057
+ objectTypes.push(objectTypeId);
2058
+ }
2059
+ resultListItems.push({
2060
+ objectTypeId,
2061
+ content,
2062
+ fields,
2063
+ permissions: o.permissions
2064
+ });
2065
+ });
2066
+ const result = {
2067
+ hasMoreItems: searchResponse.hasMoreItems,
2068
+ totalNumItems: searchResponse.totalNumItems,
2069
+ items: resultListItems,
2070
+ objectTypes
2071
+ };
2072
+ return result;
2073
+ }
2074
+ /**
2075
+ * Maps data extracted from a search form to search filters. Every key of the form data object
2076
+ * will be mapped to a search filter.
2077
+ * @param formData form data
2078
+ * @returns Array of search filters
2024
2079
  */
2025
- #formHasElements(element) {
2026
- let hasElement = false;
2027
- element.elements?.forEach((e) => {
2028
- if (!['o2mGroup', 'o2mGroupStack'].includes(e.type)) {
2029
- hasElement = true;
2080
+ formDataToSearchFilter(formData) {
2081
+ const isRangeValue = (v) => {
2082
+ return typeof v === 'object' && v !== null && 'firstValue' in v && 'operator' in v;
2083
+ };
2084
+ const filters = [];
2085
+ Object.keys(formData).forEach((key) => {
2086
+ const value = formData[key];
2087
+ if (isRangeValue(value)) {
2088
+ const f = this.rangeValueToSearchFilter(value, key);
2089
+ if (f)
2090
+ filters.push(f);
2030
2091
  }
2031
- else if (!hasElement) {
2032
- hasElement = this.#formHasElements(e);
2092
+ else {
2093
+ filters.push({
2094
+ f: key,
2095
+ o: Array.isArray(value) ? Operator.IN : Operator.EQUAL,
2096
+ v1: value
2097
+ });
2033
2098
  }
2034
2099
  });
2035
- return hasElement;
2100
+ return filters;
2101
+ }
2102
+ rangeValueToSearchFilter(value, property) {
2103
+ return this.#system.getObjectTypeField(property)?.propertyType === 'datetime'
2104
+ ? this.#dateRangeValueToSearchFilter(value, property)
2105
+ : {
2106
+ f: property,
2107
+ o: value.operator,
2108
+ v1: value.firstValue,
2109
+ v2: value.secondValue
2110
+ };
2036
2111
  }
2037
- /**
2038
- * Generates an internal type for a given object type field.
2039
- * Adding this to a form element or object type field enables us to render forms
2040
- * based on object type fields in a more performant way. Otherwise we would
2041
- * have to evaluate the conditions for every form element on every digest cycle.
2042
- * @param type propertyType of the ObjectTypeField
2043
- * @param classifications classifications of the ObjectTypeField
2044
- */
2045
- getInternalFormElementType(type, classifications) {
2046
- const _classifications = this.getClassifications(classifications || []);
2047
- if (type === 'string' && _classifications.has(Classification.STRING_REFERENCE)) {
2048
- return InternalFieldType.STRING_REFERENCE;
2049
- }
2050
- else if (type === 'string' && _classifications.has(Classification.STRING_ORGANIZATION)) {
2051
- return InternalFieldType.STRING_ORGANIZATION;
2052
- }
2053
- else if (type === 'string' && _classifications.has(Classification.STRING_ORGANIZATION_SET)) {
2054
- return InternalFieldType.STRING_ORGANIZATION_SET;
2055
- }
2056
- else if (type === 'string' && _classifications.has(Classification.STRING_CATALOG)) {
2057
- return InternalFieldType.STRING_CATALOG;
2058
- }
2059
- else if (type === 'boolean' && _classifications.has(Classification.BOOLEAN_SWITCH)) {
2060
- return InternalFieldType.BOOLEAN_SWITCH;
2061
- }
2062
- else if (type === 'string' &&
2063
- (_classifications.has(Classification.STRING_CATALOG_DYNAMIC) || _classifications.has(Classification.STRING_CATALOG_CUSTOM))) {
2064
- return InternalFieldType.STRING_DYNAMIC_CATALOG;
2065
- }
2066
- else {
2067
- // if there are no matching conditions just return the original type
2068
- return type;
2112
+ #dateRangeValueToSearchFilter(rv, property) {
2113
+ const v1 = rv.firstValue.toISOString();
2114
+ const v2 = rv.secondValue ? rv.secondValue.toISOString() : undefined;
2115
+ let filter;
2116
+ switch (rv.operator) {
2117
+ case Operator.EQUAL: {
2118
+ filter = {
2119
+ f: property,
2120
+ o: Operator.INTERVAL_INCLUDE_BOTH,
2121
+ v1: v1.split('T')[0] + 'T00:00:00.000',
2122
+ v2: v1.split('T')[0] + 'T23:59:59.000'
2123
+ };
2124
+ break;
2125
+ }
2126
+ case Operator.GREATER_OR_EQUAL: {
2127
+ filter = {
2128
+ f: property,
2129
+ o: rv.operator,
2130
+ v1: v1.split('T')[0] + 'T00:00:00.000'
2131
+ };
2132
+ break;
2133
+ }
2134
+ case Operator.LESS_OR_EQUAL: {
2135
+ filter = {
2136
+ f: property,
2137
+ o: rv.operator,
2138
+ v1: v1.split('T')[0] + 'T23:59:59.000'
2139
+ };
2140
+ break;
2141
+ }
2142
+ case Operator.INTERVAL_INCLUDE_BOTH: {
2143
+ filter = {
2144
+ f: property,
2145
+ o: rv.operator,
2146
+ v1: v1.split('T')[0] + 'T00:00:00.000',
2147
+ v2: v2.split('T')[0] + 'T23:59:59.000'
2148
+ };
2149
+ break;
2150
+ }
2069
2151
  }
2152
+ return filter;
2070
2153
  }
2071
- getObjectTypeField(id) {
2072
- const f = this.system?.allFields[id];
2073
- return f ? { ...f, _internalType: this.getInternalFormElementType(f.propertyType, f.classifications) } : undefined;
2154
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SearchService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2155
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SearchService, providedIn: 'root' }); }
2156
+ }
2157
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SearchService, decorators: [{
2158
+ type: Injectable,
2159
+ args: [{
2160
+ providedIn: 'root'
2161
+ }]
2162
+ }] });
2163
+
2164
+ var Direction;
2165
+ (function (Direction) {
2166
+ Direction["LTR"] = "ltr";
2167
+ Direction["RTL"] = "rtl";
2168
+ })(Direction || (Direction = {}));
2169
+
2170
+ /**
2171
+ * Service for providing triggered events
2172
+ */
2173
+ class EventService {
2174
+ constructor() {
2175
+ this.#eventSource = new Subject();
2176
+ this.event$ = this.#eventSource.asObservable();
2074
2177
  }
2178
+ #eventSource;
2075
2179
  /**
2076
- * Extract classifications from object type fields classification
2077
- * string. This string may contain more than one classification entry.
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)
2180
+ * Trigger an global event
2181
+ * @param type Type/key of the event
2182
+ * @param data Data to be send along with the event
2085
2183
  */
2086
- getClassifications(classifications) {
2087
- const res = new Map();
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');
2184
+ trigger(type, data) {
2185
+ this.#eventSource.next({ type, data });
2118
2186
  }
2119
- fetchResources(id) {
2120
- return this.#backend
2121
- .batch([
2122
- { uri: `/system/resources/${id}`, base: ApiBase.core },
2123
- { uri: `/admin/resources/${id}`, base: ApiBase.core }
2124
- ])
2125
- .pipe(map(([global, tenant]) => ({ global, tenant })));
2187
+ /**
2188
+ * Listen on a triggered event
2189
+ * @param types Type/key of the event
2190
+ */
2191
+ on(...types) {
2192
+ return this.event$.pipe(filter((event) => event && !!types.find((t) => t === event.type)));
2126
2193
  }
2127
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SystemService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2128
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SystemService, providedIn: 'root' }); }
2194
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EventService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2195
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EventService, providedIn: 'root' }); }
2129
2196
  }
2130
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SystemService, decorators: [{
2197
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EventService, decorators: [{
2131
2198
  type: Injectable,
2132
2199
  args: [{
2133
2200
  providedIn: 'root'
2134
2201
  }]
2135
2202
  }] });
2136
2203
 
2204
+ /**
2205
+ * Events emitted by parts of the application
2206
+ */
2207
+ var YuvEventType;
2208
+ (function (YuvEventType) {
2209
+ YuvEventType["LOGOUT"] = "yuv.user.logout";
2210
+ YuvEventType["CLIENT_LOCALE_CHANGED"] = "yuv.user.locale.client.changed";
2211
+ YuvEventType["DMS_OBJECT_LOADED"] = "yuv.dms.object.loaded";
2212
+ YuvEventType["DMS_OBJECT_CREATED"] = "yuv.dms.object.created";
2213
+ YuvEventType["DMS_OBJECT_DELETED"] = "yuv.dms.object.deleted";
2214
+ YuvEventType["DMS_OBJECT_UPDATED"] = "yuv.dms.object.updated";
2215
+ YuvEventType["DMS_OBJECTS_MOVED"] = "yuv.dms.objects.moved";
2216
+ })(YuvEventType || (YuvEventType = {}));
2217
+
2137
2218
  /**
2138
2219
  * Service providing user account configurations.
2139
2220
  */
@@ -2488,7 +2569,6 @@ class ObjectConfigService {
2488
2569
  #objectConfigs;
2489
2570
  // called on core init (auth.service -> initApp)
2490
2571
  init() {
2491
- console.log('ObjectConfigService.init', this.#user.getCurrentUser().userSettings);
2492
2572
  return this.#user.loadObjectConfig().pipe(tap$1((res) => {
2493
2573
  this.#getDefaultObjectConfig();
2494
2574
  this.#objectConfigs = res || {
@@ -4140,6 +4220,147 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
4140
4220
  }]
4141
4221
  }] });
4142
4222
 
4223
+ class SearchUtils {
4224
+ static { this.dateRanges = ['today', 'yesterday', 'thisWeek', 'lastWeek', 'thisMonth', 'lastMonth', 'thisYear', 'lastYear']; }
4225
+ static { this.filesizeRanges = ['small', 'medium', 'large', 'verylarge']; }
4226
+ static dateRangeStartEnd(dateRange) {
4227
+ let start;
4228
+ let end;
4229
+ switch (dateRange) {
4230
+ case 'today': {
4231
+ start = new Date();
4232
+ end = new Date();
4233
+ break;
4234
+ }
4235
+ case 'yesterday': {
4236
+ const yesterday = new Date();
4237
+ yesterday.setDate(yesterday.getDate() - 1);
4238
+ start = yesterday;
4239
+ end = yesterday;
4240
+ break;
4241
+ }
4242
+ case 'thisWeek': {
4243
+ const firstDay = new Date();
4244
+ firstDay.setDate(firstDay.getDate() - firstDay.getDay());
4245
+ start = firstDay;
4246
+ end = new Date();
4247
+ break;
4248
+ }
4249
+ case 'lastWeek': {
4250
+ const firstDay = new Date();
4251
+ firstDay.setDate(firstDay.getDate() - firstDay.getDay() - 7);
4252
+ const lastDay = new Date();
4253
+ lastDay.setDate(lastDay.getDate() - lastDay.getDay() - 1);
4254
+ start = firstDay;
4255
+ end = lastDay;
4256
+ break;
4257
+ }
4258
+ case 'thisMonth': {
4259
+ const firstDay = new Date();
4260
+ firstDay.setDate(1);
4261
+ start = firstDay;
4262
+ end = new Date();
4263
+ break;
4264
+ }
4265
+ case 'lastMonth': {
4266
+ const firstDay = new Date();
4267
+ firstDay.setDate(1);
4268
+ firstDay.setMonth(firstDay.getMonth() - 1);
4269
+ const lastDay = new Date();
4270
+ lastDay.setDate(0);
4271
+ start = firstDay;
4272
+ end = lastDay;
4273
+ break;
4274
+ }
4275
+ case 'thisYear': {
4276
+ const firstDay = new Date();
4277
+ firstDay.setMonth(0);
4278
+ firstDay.setDate(1);
4279
+ start = firstDay;
4280
+ end = new Date();
4281
+ break;
4282
+ }
4283
+ case 'lastYear': {
4284
+ const firstDay = new Date();
4285
+ firstDay.setFullYear(firstDay.getFullYear() - 1);
4286
+ firstDay.setMonth(0);
4287
+ firstDay.setDate(1);
4288
+ const lastDay = new Date();
4289
+ lastDay.setFullYear(lastDay.getFullYear() - 1);
4290
+ lastDay.setMonth(11);
4291
+ lastDay.setDate(31);
4292
+ start = firstDay;
4293
+ end = lastDay;
4294
+ break;
4295
+ }
4296
+ }
4297
+ return { start, end };
4298
+ }
4299
+ /**
4300
+ * Maps a date range filter to a date range value like 'thisWeek', 'lastMonth', etc.
4301
+ * @param rangeValue the range value
4302
+ * @returns the date range (eg. 'thisWeek', 'lastMonth', etc.)
4303
+ */
4304
+ static getMatchingDateRange(rangeValue) {
4305
+ return SearchUtils.dateRanges.find((dateRange) => {
4306
+ const { start, end } = SearchUtils.dateRangeStartEnd(dateRange);
4307
+ return (rangeValue.firstValue === start.toISOString().split('T')[0] + 'T00:00:00.000' &&
4308
+ rangeValue.secondValue === end.toISOString().split('T')[0] + 'T23:59:59.000');
4309
+ });
4310
+ }
4311
+ // Files size ranges
4312
+ static getMatchingFilesizeRange(rangeValue) {
4313
+ let filesizeRange = undefined;
4314
+ if (rangeValue.operator === Operator.INTERVAL_INCLUDE_BOTH) {
4315
+ if (rangeValue.firstValue === 1024 * 1024 && rangeValue.secondValue === 1024 * 1024 * 10)
4316
+ filesizeRange = 'medium';
4317
+ else if (rangeValue.firstValue === 1024 * 1024 * 10 && rangeValue.secondValue === 1024 * 1024 * 100)
4318
+ filesizeRange = 'large';
4319
+ }
4320
+ else if (rangeValue.operator === Operator.LESS_THAN) {
4321
+ if (rangeValue.firstValue === 1024 * 1024)
4322
+ filesizeRange = 'small';
4323
+ }
4324
+ else if (rangeValue.operator === Operator.GREATER_THAN) {
4325
+ if (rangeValue.firstValue === 1024 * 1024 * 100)
4326
+ filesizeRange = 'verylarge';
4327
+ }
4328
+ return filesizeRange;
4329
+ }
4330
+ static filesizeRangeToRangeValue(filesizeRange) {
4331
+ let rv = undefined;
4332
+ switch (filesizeRange) {
4333
+ case 'small':
4334
+ rv = {
4335
+ operator: Operator.LESS_THAN,
4336
+ firstValue: 1024 * 1024
4337
+ };
4338
+ break;
4339
+ case 'medium':
4340
+ rv = {
4341
+ operator: Operator.INTERVAL_INCLUDE_BOTH,
4342
+ firstValue: 1024 * 1024,
4343
+ secondValue: 1024 * 1024 * 10
4344
+ };
4345
+ break;
4346
+ case 'large':
4347
+ rv = {
4348
+ operator: Operator.INTERVAL_INCLUDE_BOTH,
4349
+ firstValue: 1024 * 1024 * 10,
4350
+ secondValue: 1024 * 1024 * 100
4351
+ };
4352
+ break;
4353
+ case 'verylarge':
4354
+ rv = {
4355
+ operator: Operator.GREATER_THAN,
4356
+ firstValue: 1024 * 1024 * 100
4357
+ };
4358
+ break;
4359
+ }
4360
+ return rv;
4361
+ }
4362
+ }
4363
+
4143
4364
  class SessionStorageService {
4144
4365
  #TEMP_STORAGE_ENTRIES_KEY = 'yuv.core.sessionstorage.entries';
4145
4366
  constructor() {
@@ -4771,5 +4992,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
4771
4992
  * Generated bundle index. Do not edit.
4772
4993
  */
4773
4994
 
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, RetentionState, SafeHtmlPipe, SafeUrlPipe, SearchService, SecondaryObjectTypeClassification, SessionStorageService, Situation, Sort, SystemResult, SystemSOT, SystemService, SystemType, TENANT_HEADER, UploadService, UserRoles, UserService, Utils, YuvClientCoreModule, YuvClientCoreSharedModule, YuvError, YuvEventType, YuvUser, init_moduleFnc, storageFactory };
4995
+ 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, RetentionState, SafeHtmlPipe, SafeUrlPipe, SearchService, SearchUtils, SecondaryObjectTypeClassification, SessionStorageService, Situation, Sort, SystemResult, SystemSOT, SystemService, SystemType, TENANT_HEADER, UploadService, UserRoles, UserService, Utils, YuvClientCoreModule, YuvClientCoreSharedModule, YuvError, YuvEventType, YuvUser, init_moduleFnc, storageFactory };
4775
4996
  //# sourceMappingURL=yuuvis-client-core.mjs.map