@yuuvis/client-core 0.6.5

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.
Files changed (153) hide show
  1. package/README.md +111 -0
  2. package/esm2022/index.mjs +65 -0
  3. package/esm2022/lib/client-core.module.mjs +117 -0
  4. package/esm2022/lib/client-core.shared.module.mjs +18 -0
  5. package/esm2022/lib/common/pipes/filesize.pipe.mjs +37 -0
  6. package/esm2022/lib/common/pipes/index.mjs +6 -0
  7. package/esm2022/lib/common/pipes/keys.pipe.mjs +17 -0
  8. package/esm2022/lib/common/pipes/locale-date.pipe.mjs +45 -0
  9. package/esm2022/lib/common/pipes/locale-number.pipe.mjs +115 -0
  10. package/esm2022/lib/common/pipes/safe-html.pipe.mjs +44 -0
  11. package/esm2022/lib/common/services/native-notifications.interface.mjs +2 -0
  12. package/esm2022/lib/common/services/native-notifications.mjs +40 -0
  13. package/esm2022/lib/model/dms-object.interface.mjs +2 -0
  14. package/esm2022/lib/model/dms-object.model.mjs +79 -0
  15. package/esm2022/lib/model/object-flavor.interface.mjs +2 -0
  16. package/esm2022/lib/model/range-value.interface.mjs +2 -0
  17. package/esm2022/lib/model/yuv-error.model.mjs +37 -0
  18. package/esm2022/lib/model/yuv-user.model.mjs +38 -0
  19. package/esm2022/lib/service/audit/audit.interface.mjs +2 -0
  20. package/esm2022/lib/service/audit/audit.service.mjs +135 -0
  21. package/esm2022/lib/service/auth/auth.interceptor.mjs +50 -0
  22. package/esm2022/lib/service/auth/auth.interface.mjs +7 -0
  23. package/esm2022/lib/service/auth/auth.service.mjs +130 -0
  24. package/esm2022/lib/service/auth/oidc.service.mjs +81 -0
  25. package/esm2022/lib/service/backend/api.enum.mjs +11 -0
  26. package/esm2022/lib/service/backend/backend.interface.mjs +2 -0
  27. package/esm2022/lib/service/backend/backend.service.mjs +206 -0
  28. package/esm2022/lib/service/bpm/bpm.interface.mjs +8 -0
  29. package/esm2022/lib/service/bpm/bpm.service.mjs +51 -0
  30. package/esm2022/lib/service/cache/app-cache.service.mjs +51 -0
  31. package/esm2022/lib/service/catalog/catalog.interface.mjs +2 -0
  32. package/esm2022/lib/service/catalog/catalog.service.mjs +13 -0
  33. package/esm2022/lib/service/clipboard/clipboard.interface.mjs +2 -0
  34. package/esm2022/lib/service/clipboard/clipboard.service.mjs +90 -0
  35. package/esm2022/lib/service/config/config.interface.mjs +6 -0
  36. package/esm2022/lib/service/config/config.service.mjs +115 -0
  37. package/esm2022/lib/service/config/core-config.mjs +20 -0
  38. package/esm2022/lib/service/config/core-config.tokens.mjs +9 -0
  39. package/esm2022/lib/service/connection/connection.service.mjs +36 -0
  40. package/esm2022/lib/service/connection/offline.interceptor.mjs +28 -0
  41. package/esm2022/lib/service/core-init/core-init.service.mjs +29 -0
  42. package/esm2022/lib/service/core-init/missing-translation-handler.mjs +10 -0
  43. package/esm2022/lib/service/core-init/translate-json-loader.mjs +117 -0
  44. package/esm2022/lib/service/device/device.interface.mjs +6 -0
  45. package/esm2022/lib/service/device/device.service.mjs +144 -0
  46. package/esm2022/lib/service/dms/dms.service.interface.mjs +2 -0
  47. package/esm2022/lib/service/dms/dms.service.mjs +440 -0
  48. package/esm2022/lib/service/event/event.interface.mjs +2 -0
  49. package/esm2022/lib/service/event/event.service.mjs +38 -0
  50. package/esm2022/lib/service/event/events.mjs +14 -0
  51. package/esm2022/lib/service/idm/idm.interface.mjs +2 -0
  52. package/esm2022/lib/service/idm/idm.service.mjs +34 -0
  53. package/esm2022/lib/service/logger/logger-console.service.mjs +73 -0
  54. package/esm2022/lib/service/logger/logger.interface.mjs +2 -0
  55. package/esm2022/lib/service/logger/logger.mjs +27 -0
  56. package/esm2022/lib/service/notification/notification.service.mjs +131 -0
  57. package/esm2022/lib/service/object-config/object-config.interface.mjs +2 -0
  58. package/esm2022/lib/service/object-config/object-config.service.mjs +229 -0
  59. package/esm2022/lib/service/pending-changes/pending-changes-component.interface.mjs +5 -0
  60. package/esm2022/lib/service/pending-changes/pending-changes-guard.service.mjs +25 -0
  61. package/esm2022/lib/service/pending-changes/pending-changes.service.mjs +123 -0
  62. package/esm2022/lib/service/prediction/prediction.interface.mjs +2 -0
  63. package/esm2022/lib/service/prediction/prediction.service.mjs +60 -0
  64. package/esm2022/lib/service/search/search.service.interface.mjs +39 -0
  65. package/esm2022/lib/service/search/search.service.mjs +178 -0
  66. package/esm2022/lib/service/session-storage/session-storage.service.mjs +50 -0
  67. package/esm2022/lib/service/system/object-form.interface.mjs +2 -0
  68. package/esm2022/lib/service/system/system.enum.mjs +179 -0
  69. package/esm2022/lib/service/system/system.interface.mjs +2 -0
  70. package/esm2022/lib/service/system/system.service.mjs +597 -0
  71. package/esm2022/lib/service/upload/upload.interface.mjs +2 -0
  72. package/esm2022/lib/service/upload/upload.service.mjs +228 -0
  73. package/esm2022/lib/service/user/user.service.mjs +211 -0
  74. package/esm2022/lib/util/utils.helper.enum.mjs +15 -0
  75. package/esm2022/lib/util/utils.mjs +373 -0
  76. package/esm2022/yuuvis-client-core.mjs +5 -0
  77. package/fesm2022/yuuvis-client-core.mjs +4775 -0
  78. package/fesm2022/yuuvis-client-core.mjs.map +1 -0
  79. package/index.d.ts +61 -0
  80. package/lib/client-core.module.d.ts +20 -0
  81. package/lib/client-core.shared.module.d.ts +10 -0
  82. package/lib/common/pipes/filesize.pipe.d.ts +18 -0
  83. package/lib/common/pipes/index.d.ts +5 -0
  84. package/lib/common/pipes/keys.pipe.d.ts +10 -0
  85. package/lib/common/pipes/locale-date.pipe.d.ts +12 -0
  86. package/lib/common/pipes/locale-number.pipe.d.ts +47 -0
  87. package/lib/common/pipes/safe-html.pipe.d.ts +28 -0
  88. package/lib/common/services/native-notifications.d.ts +8 -0
  89. package/lib/common/services/native-notifications.interface.d.ts +5 -0
  90. package/lib/model/dms-object.interface.d.ts +16 -0
  91. package/lib/model/dms-object.model.d.ts +26 -0
  92. package/lib/model/object-flavor.interface.d.ts +30 -0
  93. package/lib/model/range-value.interface.d.ts +9 -0
  94. package/lib/model/yuv-error.model.d.ts +18 -0
  95. package/lib/model/yuv-user.model.d.ts +44 -0
  96. package/lib/service/audit/audit.interface.d.ts +47 -0
  97. package/lib/service/audit/audit.service.d.ts +35 -0
  98. package/lib/service/auth/auth.interceptor.d.ts +12 -0
  99. package/lib/service/auth/auth.interface.d.ts +34 -0
  100. package/lib/service/auth/auth.service.d.ts +50 -0
  101. package/lib/service/auth/oidc.service.d.ts +16 -0
  102. package/lib/service/backend/api.enum.d.ts +7 -0
  103. package/lib/service/backend/backend.interface.d.ts +29 -0
  104. package/lib/service/backend/backend.service.d.ts +118 -0
  105. package/lib/service/bpm/bpm.interface.d.ts +86 -0
  106. package/lib/service/bpm/bpm.service.d.ts +19 -0
  107. package/lib/service/cache/app-cache.service.d.ts +18 -0
  108. package/lib/service/catalog/catalog.interface.d.ts +12 -0
  109. package/lib/service/catalog/catalog.service.d.ts +5 -0
  110. package/lib/service/clipboard/clipboard.interface.d.ts +11 -0
  111. package/lib/service/clipboard/clipboard.service.d.ts +23 -0
  112. package/lib/service/config/config.interface.d.ts +34 -0
  113. package/lib/service/config/config.service.d.ts +45 -0
  114. package/lib/service/config/core-config.d.ts +14 -0
  115. package/lib/service/config/core-config.tokens.d.ts +7 -0
  116. package/lib/service/connection/connection.service.d.ts +25 -0
  117. package/lib/service/connection/offline.interceptor.d.ts +15 -0
  118. package/lib/service/core-init/core-init.service.d.ts +11 -0
  119. package/lib/service/core-init/missing-translation-handler.d.ts +8 -0
  120. package/lib/service/core-init/translate-json-loader.d.ts +20 -0
  121. package/lib/service/device/device.interface.d.ts +15 -0
  122. package/lib/service/device/device.service.d.ts +54 -0
  123. package/lib/service/dms/dms.service.d.ts +153 -0
  124. package/lib/service/dms/dms.service.interface.d.ts +59 -0
  125. package/lib/service/event/event.interface.d.ts +13 -0
  126. package/lib/service/event/event.service.d.ts +23 -0
  127. package/lib/service/event/events.d.ts +12 -0
  128. package/lib/service/idm/idm.interface.d.ts +5 -0
  129. package/lib/service/idm/idm.service.d.ts +9 -0
  130. package/lib/service/logger/logger-console.service.d.ts +20 -0
  131. package/lib/service/logger/logger.d.ts +17 -0
  132. package/lib/service/logger/logger.interface.d.ts +10 -0
  133. package/lib/service/notification/notification.service.d.ts +71 -0
  134. package/lib/service/object-config/object-config.interface.d.ts +62 -0
  135. package/lib/service/object-config/object-config.service.d.ts +38 -0
  136. package/lib/service/pending-changes/pending-changes-component.interface.d.ts +6 -0
  137. package/lib/service/pending-changes/pending-changes-guard.service.d.ts +14 -0
  138. package/lib/service/pending-changes/pending-changes.service.d.ts +57 -0
  139. package/lib/service/prediction/prediction.interface.d.ts +18 -0
  140. package/lib/service/prediction/prediction.service.d.ts +15 -0
  141. package/lib/service/search/search.service.d.ts +46 -0
  142. package/lib/service/search/search.service.interface.d.ts +119 -0
  143. package/lib/service/session-storage/session-storage.service.d.ts +15 -0
  144. package/lib/service/system/object-form.interface.d.ts +46 -0
  145. package/lib/service/system/system.enum.d.ts +141 -0
  146. package/lib/service/system/system.interface.d.ts +146 -0
  147. package/lib/service/system/system.service.d.ts +168 -0
  148. package/lib/service/upload/upload.interface.d.ts +55 -0
  149. package/lib/service/upload/upload.service.d.ts +34 -0
  150. package/lib/service/user/user.service.d.ts +69 -0
  151. package/lib/util/utils.d.ts +118 -0
  152. package/lib/util/utils.helper.enum.d.ts +13 -0
  153. package/package.json +33 -0
@@ -0,0 +1,4775 @@
1
+ import * as i1$1 from '@ngx-translate/core';
2
+ import { TranslateModule, TranslateService, TranslateLoader, MissingTranslationHandler } from '@ngx-translate/core';
3
+ export { TranslateDirective, TranslateLoader, TranslateModule, TranslatePipe, TranslateService } from '@ngx-translate/core';
4
+ import * as i0 from '@angular/core';
5
+ import { NgModule, InjectionToken, Inject, Injectable, Optional, inject, APP_INITIALIZER, SkipSelf, Pipe } from '@angular/core';
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';
9
+ import * as i1 from 'angular-oauth2-oidc';
10
+ import { OAuthStorage, OAuthModule } from 'angular-oauth2-oidc';
11
+ import { __decorate, __param, __metadata } from 'tslib';
12
+ import { StorageMap } from '@ngx-pwa/local-storage';
13
+ import { toSignal } from '@angular/core/rxjs-interop';
14
+ import { DeviceDetectorService } from 'ngx-device-detector';
15
+ import { ToastService } from '@yuuvis/components/toast';
16
+ import { registerLocaleData, DecimalPipe, PercentPipe, CurrencyPipe } from '@angular/common';
17
+ import localeAr from '@angular/common/locales/ar';
18
+ import localeBn from '@angular/common/locales/bn';
19
+ import localeDe from '@angular/common/locales/de';
20
+ import localeDeCh from '@angular/common/locales/de-CH';
21
+ import localeEs from '@angular/common/locales/es';
22
+ import localeExtraAr from '@angular/common/locales/extra/ar';
23
+ import localeExtraBn from '@angular/common/locales/extra/bn';
24
+ import localeExtraDe from '@angular/common/locales/extra/de';
25
+ import localeExtraDeCh from '@angular/common/locales/extra/de-CH';
26
+ import localeExtraEs from '@angular/common/locales/extra/es';
27
+ import localeExtraFi from '@angular/common/locales/extra/fi';
28
+ import localeExtraFr from '@angular/common/locales/extra/fr';
29
+ import localeExtraHi from '@angular/common/locales/extra/hi';
30
+ import localeExtraIt from '@angular/common/locales/extra/it';
31
+ import localeExtraJa from '@angular/common/locales/extra/ja';
32
+ import localeExtraKo from '@angular/common/locales/extra/ko';
33
+ import localeExtraLv from '@angular/common/locales/extra/lv';
34
+ import localeExtraNb from '@angular/common/locales/extra/nb';
35
+ import localeExtraNl from '@angular/common/locales/extra/nl';
36
+ import localeExtraPl from '@angular/common/locales/extra/pl';
37
+ import localeExtraPt from '@angular/common/locales/extra/pt';
38
+ import localeExtraRu from '@angular/common/locales/extra/ru';
39
+ import localeExtraSk from '@angular/common/locales/extra/sk';
40
+ import localeExtraSv from '@angular/common/locales/extra/sv';
41
+ import localeExtraTh from '@angular/common/locales/extra/th';
42
+ import localeExtraTr from '@angular/common/locales/extra/tr';
43
+ import localeExtraUk from '@angular/common/locales/extra/uk';
44
+ import localeExtraVi from '@angular/common/locales/extra/vi';
45
+ import localeExtraZh from '@angular/common/locales/extra/zh';
46
+ import localeFi from '@angular/common/locales/fi';
47
+ import localeFr from '@angular/common/locales/fr';
48
+ import localeHi from '@angular/common/locales/hi';
49
+ import localeIt from '@angular/common/locales/it';
50
+ import localeJa from '@angular/common/locales/ja';
51
+ import localeKo from '@angular/common/locales/ko';
52
+ import localeLv from '@angular/common/locales/lv';
53
+ import localeNb from '@angular/common/locales/nb';
54
+ import localeNl from '@angular/common/locales/nl';
55
+ import localePl from '@angular/common/locales/pl';
56
+ import localePt from '@angular/common/locales/pt';
57
+ import localeRu from '@angular/common/locales/ru';
58
+ import localeSk from '@angular/common/locales/sk';
59
+ import localeSv from '@angular/common/locales/sv';
60
+ import localeTh from '@angular/common/locales/th';
61
+ import localeTr from '@angular/common/locales/tr';
62
+ import localeUk from '@angular/common/locales/uk';
63
+ import localeVi from '@angular/common/locales/vi';
64
+ import localeZh from '@angular/common/locales/zh';
65
+ import * as i1$2 from '@angular/platform-browser';
66
+
67
+ /**
68
+ * `YuvClientCoreSharedModule` sets up and re-exports the TranslateModule.
69
+ */
70
+ class YuvClientCoreSharedModule {
71
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: YuvClientCoreSharedModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
72
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: YuvClientCoreSharedModule, exports: [TranslateModule] }); }
73
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: YuvClientCoreSharedModule, imports: [TranslateModule] }); }
74
+ }
75
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: YuvClientCoreSharedModule, decorators: [{
76
+ type: NgModule,
77
+ args: [{
78
+ exports: [TranslateModule]
79
+ }]
80
+ }] });
81
+
82
+ const TENANT_HEADER = 'X-ID-TENANT-NAME';
83
+ var Situation;
84
+ (function (Situation) {
85
+ Situation["EDIT"] = "EDIT";
86
+ Situation["CREATE"] = "CREATE";
87
+ Situation["SEARCH"] = "SEARCH";
88
+ })(Situation || (Situation = {}));
89
+ const SystemType = {
90
+ OBJECT: 'system:object',
91
+ DOCUMENT: 'system:document',
92
+ FOLDER: 'system:folder',
93
+ AUDIT: 'system:audit',
94
+ SOT: 'system:secondray'
95
+ };
96
+ const SystemResult = {
97
+ DELETE: 'system:deletionResult',
98
+ };
99
+ const AdministrationRoles = {
100
+ ADMIN: 'YUUVIS_TENANT_ADMIN',
101
+ SYSTEM: 'YUUVIS_SYSTEM_INTEGRATOR',
102
+ MANAGE_SETTINGS: 'YUUVIS_MANAGE_SETTINGS'
103
+ };
104
+ const UserRoles = {
105
+ MULTI_TENANT: 'YUUVIS_MULTI_TENANT'
106
+ };
107
+ const SystemSOT = {
108
+ DESTRUCTION_RETENTION: 'system:rmDestructionRetention'
109
+ };
110
+ const RetentionField = {
111
+ RETENTION_END: 'system:rmExpirationDate',
112
+ RETENTION_START: 'system:rmStartOfRetention',
113
+ DESTRUCTION_DATE: 'system:rmDestructionDate'
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
+ const BaseObjectTypeField = {
127
+ OBJECT_TYPE_ID: 'system:objectTypeId',
128
+ VERSION_NUMBER: 'system:versionNumber',
129
+ CREATION_DATE: 'system:creationDate',
130
+ CREATED_BY: 'system:createdBy',
131
+ MODIFICATION_DATE: 'system:lastModificationDate',
132
+ MODIFIED_BY: 'system:lastModifiedBy',
133
+ ...RetentionField,
134
+ PARENT_ID: 'system:parentId',
135
+ PARENT_OBJECT_TYPE_ID: 'system:parentObjectTypeId',
136
+ PARENT_VERSION_NUMBER: 'system:parentVersionNumber',
137
+ TENANT: 'system:tenant',
138
+ ACL: 'system:acl',
139
+ TRACE_ID: 'system:traceId',
140
+ SECONDARY_OBJECT_TYPE_IDS: 'system:secondaryObjectTypeIds',
141
+ BASE_TYPE_ID: 'system:baseTypeId',
142
+ TAGS: 'system:tags',
143
+ OBJECT_ID: 'system:objectId'
144
+ };
145
+ // Fields provided by a special secondary object type that most of
146
+ // the object types should have applied to them
147
+ const ClientDefaultsObjectTypeField = {
148
+ TITLE: 'appClient:clienttitle',
149
+ DESCRIPTION: 'appClient:clientdescription'
150
+ };
151
+ const ContentStreamField = {
152
+ LENGTH: 'system:contentStreamLength',
153
+ MIME_TYPE: 'system:contentStreamMimeType',
154
+ FILENAME: 'system:contentStreamFileName',
155
+ ID: 'system:contentStreamId',
156
+ RANGE: 'system:contentStreamRange',
157
+ REPOSITORY_ID: 'system:contentStreamRepositoryId',
158
+ DIGEST: 'system:digest',
159
+ ARCHIVE_PATH: 'system:archivePath'
160
+ };
161
+ const AuditField = {
162
+ REFERRED_OBJECT_ID: 'system:referredObjectId',
163
+ CREATION_DATE: 'system:creationDate',
164
+ VERSION: 'system:versionNumber',
165
+ DETAIL: 'system:detail',
166
+ CREATED_BY: 'system:createdBy',
167
+ ACTION: 'system:action',
168
+ SUBACTION: 'system:subaction'
169
+ };
170
+ const ParentField = {
171
+ asvaktenzeichen: 'tenKolibri:asvaktenzeichen',
172
+ asvaktenzeichentext: 'tenKolibri:asvaktenzeichentext',
173
+ asvsichtrechte: 'tenKolibri:asvsichtrechte',
174
+ asvvorgangsname: 'tenKolibri:asvvorgangsname',
175
+ asvvorgangsnummer: 'tenKolibri:asvvorgangsnummer'
176
+ };
177
+ var ContentStreamAllowed;
178
+ (function (ContentStreamAllowed) {
179
+ ContentStreamAllowed["ALLOWED"] = "allowed";
180
+ ContentStreamAllowed["NOT_ALLOWED"] = "notallowed";
181
+ ContentStreamAllowed["REQUIRED"] = "required";
182
+ })(ContentStreamAllowed || (ContentStreamAllowed = {}));
183
+ // classifications applied to object type fields
184
+ var Classification;
185
+ (function (Classification) {
186
+ Classification["STRING_CATALOG_CUSTOM"] = "custom:catalog";
187
+ Classification["STRING_CATALOG_DYNAMIC"] = "dynamic:catalog";
188
+ Classification["STRING_CATALOG"] = "catalog";
189
+ Classification["STRING_ORGANIZATION"] = "id:organization";
190
+ Classification["STRING_ORGANIZATION_SET"] = "id:organization:set";
191
+ Classification["STRING_REFERENCE"] = "id:reference";
192
+ Classification["STRING_EMAIL"] = "email";
193
+ Classification["STRING_URL"] = "url";
194
+ Classification["STRING_PHONE"] = "phone";
195
+ Classification["NUMBER_FILESIZE"] = "filesize";
196
+ Classification["NUMBER_DIGIT"] = "digit";
197
+ Classification["BOOLEAN_SWITCH"] = "switch";
198
+ Classification["SYSTEM_SOT"] = "systemsot";
199
+ Classification["PREDICTION_CLASSIFY"] = "prediction:classify";
200
+ Classification["TABLE_SORTABLE"] = "sortable";
201
+ })(Classification || (Classification = {}));
202
+ // classifications applied to object types
203
+ var ObjectTypeClassification;
204
+ (function (ObjectTypeClassification) {
205
+ ObjectTypeClassification["SEARCH_FALSE"] = "appClient:search:false";
206
+ ObjectTypeClassification["CREATE_FALSE"] = "appClient:create:false";
207
+ ObjectTypeClassification["OBJECT_TYPE_ICON"] = "appClient:icon";
208
+ })(ObjectTypeClassification || (ObjectTypeClassification = {}));
209
+ // classifications applied to object types
210
+ var ObjectTypePropertyClassification;
211
+ (function (ObjectTypePropertyClassification) {
212
+ ObjectTypePropertyClassification["SUMMARY_HIDDEN"] = "appClient:summary:hidden";
213
+ })(ObjectTypePropertyClassification || (ObjectTypePropertyClassification = {}));
214
+ // classifications applied to secondary object types
215
+ var SecondaryObjectTypeClassification;
216
+ (function (SecondaryObjectTypeClassification) {
217
+ SecondaryObjectTypeClassification["REQUIRED"] = "appClient:required";
218
+ SecondaryObjectTypeClassification["PRIMARY"] = "appClient:primary";
219
+ SecondaryObjectTypeClassification["EXTENSION_ADD_FALSE"] = "appClient:extension:add:false";
220
+ SecondaryObjectTypeClassification["EXTENSION_REMOVE_FALSE"] = "appClient:extension:remove:false";
221
+ })(SecondaryObjectTypeClassification || (SecondaryObjectTypeClassification = {}));
222
+ // special internal types of object type fields
223
+ var InternalFieldType;
224
+ (function (InternalFieldType) {
225
+ InternalFieldType["STRING_ORGANIZATION_SET"] = "string:organization:set";
226
+ InternalFieldType["STRING_ORGANIZATION"] = "string:organization";
227
+ InternalFieldType["STRING_REFERENCE"] = "string:reference";
228
+ InternalFieldType["STRING_CATALOG"] = "string:catalog";
229
+ InternalFieldType["STRING_DYNAMIC_CATALOG"] = "string:catalog:dynamic";
230
+ InternalFieldType["BOOLEAN_SWITCH"] = "boolean:switch";
231
+ })(InternalFieldType || (InternalFieldType = {}));
232
+ ;
233
+ var ObjectTag;
234
+ (function (ObjectTag) {
235
+ ObjectTag["AFO"] = "appclient:dlm:prepare";
236
+ })(ObjectTag || (ObjectTag = {}));
237
+ // possible states of a DLM item
238
+ const AFO_STATE = {
239
+ // created but no FSOT assigned so far
240
+ IN_PROGRESS: 0,
241
+ // an FSOT has been assigned
242
+ READY: 1
243
+ };
244
+ const ColumnConfigSkipFields = [
245
+ BaseObjectTypeField.OBJECT_ID,
246
+ BaseObjectTypeField.OBJECT_TYPE_ID,
247
+ BaseObjectTypeField.PARENT_ID,
248
+ BaseObjectTypeField.PARENT_OBJECT_TYPE_ID,
249
+ BaseObjectTypeField.PARENT_VERSION_NUMBER,
250
+ BaseObjectTypeField.TENANT,
251
+ BaseObjectTypeField.TRACE_ID,
252
+ // BaseObjectTypeField.TAGS,
253
+ BaseObjectTypeField.BASE_TYPE_ID,
254
+ ContentStreamField.ID,
255
+ ContentStreamField.RANGE,
256
+ ContentStreamField.REPOSITORY_ID,
257
+ ContentStreamField.DIGEST,
258
+ ContentStreamField.ARCHIVE_PATH
259
+ ];
260
+
261
+ /**
262
+ * `DmsObject` is a business object of a type that generally contain a document file in addition to its metadata.
263
+ * Document file can be text documents, e-mails, image files, video, etc.
264
+ * Each object type classifies the object and defines the properties that the object must have or is allowed to have.
265
+ */
266
+ class DmsObject {
267
+ /**
268
+ * @ignore
269
+ */
270
+ constructor(searchResultItem) {
271
+ this.sots = [];
272
+ this.id = searchResultItem.fields.get(BaseObjectTypeField.OBJECT_ID);
273
+ this.version = searchResultItem.fields.get(BaseObjectTypeField.VERSION_NUMBER);
274
+ this.objectTypeId = searchResultItem.objectTypeId;
275
+ this.parentId = searchResultItem.fields.get(BaseObjectTypeField.PARENT_ID);
276
+ this.data = this.#generateData(searchResultItem.fields);
277
+ this.isFolder = searchResultItem.fields.get(BaseObjectTypeField.BASE_TYPE_ID) === SystemType.FOLDER;
278
+ // this.contentStreamAllowed = objectType.contentStreamAllowed;
279
+ this.created = {
280
+ on: searchResultItem.fields.get(BaseObjectTypeField.CREATION_DATE),
281
+ by: {
282
+ id: searchResultItem.fields.get(BaseObjectTypeField.CREATED_BY)
283
+ }
284
+ };
285
+ this.modified = {
286
+ on: searchResultItem.fields.get(BaseObjectTypeField.MODIFICATION_DATE),
287
+ by: {
288
+ id: searchResultItem.fields.get(BaseObjectTypeField.MODIFIED_BY)
289
+ }
290
+ };
291
+ if (searchResultItem.content) {
292
+ this.content = searchResultItem.content;
293
+ }
294
+ if (searchResultItem.permissions) {
295
+ this.permissions = {
296
+ readIndexData: searchResultItem.permissions.read && searchResultItem.permissions.read.includes('metadata'),
297
+ readContent: searchResultItem.permissions.read && searchResultItem.permissions.read.includes('content'),
298
+ writeIndexData: searchResultItem.permissions.write && searchResultItem.permissions.write.includes('metadata'),
299
+ writeContent: searchResultItem.permissions.write && searchResultItem.permissions.write.includes('content'),
300
+ deleteObject: searchResultItem.permissions.delete && searchResultItem.permissions.delete.includes('object'),
301
+ deleteContent: searchResultItem.permissions.delete && searchResultItem.permissions.delete.includes('content')
302
+ };
303
+ }
304
+ this.sots = searchResultItem.fields.get(BaseObjectTypeField.SECONDARY_OBJECT_TYPE_IDS) || [];
305
+ }
306
+ // /**
307
+ // * Get the value (state) of a certain tag
308
+ // * @param name The tags name
309
+ // * @returns The value of the tag or null if the tag does not exist
310
+ // */
311
+ // getTag(name: string): any {
312
+ // const tags: unknown[][] = this.data[BaseObjectTypeField.TAGS] as unknown[][];
313
+ // const tag: unknown[] | null = tags ? (tags.find((t: any) => t[0] === name) as unknown[]) : null;
314
+ // return tag ? tag[1] : null;
315
+ // }
316
+ // getRetentionState(): RetentionState {
317
+ // if (this.data[RetentionField.RETENTION_START]) {
318
+ // const retentionStart = new Date(this.data[RetentionField.RETENTION_START] as string);
319
+ // const retentionEnd = new Date(this.data[RetentionField.RETENTION_END] as string);
320
+ // const today = new Date();
321
+ // return retentionStart <= today && today <= retentionEnd
322
+ // ? RetentionState.ACTIVE
323
+ // : today < retentionStart
324
+ // ? RetentionState.INACTIVE
325
+ // : RetentionState.DESTRUCT;
326
+ // } else {
327
+ // return RetentionState.NONE;
328
+ // }
329
+ // }
330
+ #generateData(fields) {
331
+ const result = {};
332
+ for (const [key, val] of fields.entries()) {
333
+ result[key] = val;
334
+ }
335
+ return result;
336
+ }
337
+ }
338
+
339
+ /**
340
+ * @ignore
341
+ */
342
+ class YuvError {
343
+ get name() {
344
+ return this._name || this.originalError.name || '';
345
+ }
346
+ get message() {
347
+ return this._message || this.originalError.message || '';
348
+ }
349
+ get stack() {
350
+ return this.originalError.stack;
351
+ }
352
+ get status() {
353
+ return this.originalError.status;
354
+ }
355
+ get url() {
356
+ return this.originalError.url;
357
+ }
358
+ get skipNotification() {
359
+ return this._skipNotification === undefined ? !!this.originalError.skipNotification : this._skipNotification;
360
+ }
361
+ get isHttpErrorResponse() {
362
+ return this.originalError.isHttpErrorResponse || this.originalError instanceof HttpErrorResponse;
363
+ }
364
+ constructor(originalError, _name, _message, _skipNotification = false) {
365
+ this.originalError = originalError;
366
+ this._name = _name;
367
+ this._message = _message;
368
+ this._skipNotification = _skipNotification;
369
+ }
370
+ toString() {
371
+ return this.originalError.toString();
372
+ }
373
+ }
374
+
375
+ /**
376
+ * User account configuration
377
+ */
378
+ class YuvUser {
379
+ /**
380
+ * @ignore
381
+ */
382
+ constructor(json, userSettings) {
383
+ this.DEFAULT_USER_LOCALE = 'en';
384
+ this.id = json.id;
385
+ this.username = json.username;
386
+ this.firstname = json.firstname;
387
+ this.lastname = json.lastname;
388
+ this.email = json.email;
389
+ this.image = json.image;
390
+ this.tenant = json.tenant;
391
+ this.domain = json.domain;
392
+ this.authorities = json.authorities;
393
+ this.substituteOf = json.substituteOf;
394
+ this.enabled = json.enabled;
395
+ this.title = json.displayName || (this.firstname && this.lastname) ? `${this.lastname}, ${this.firstname} (${this.username})` : this.username;
396
+ this.userSettings = userSettings || { locale: this.DEFAULT_USER_LOCALE };
397
+ }
398
+ /**
399
+ * Gets the users configured client locale
400
+ * @returns locale string
401
+ */
402
+ getClientLocale(fallback) {
403
+ return this.userSettings?.locale || fallback || this.DEFAULT_USER_LOCALE;
404
+ }
405
+ getFullName() {
406
+ return `${this.lastname}, ${this.firstname}`;
407
+ }
408
+ getDisplayNameName() {
409
+ return `${this.lastname}, ${this.firstname} (${this.username})`;
410
+ }
411
+ }
412
+
413
+ var Sort;
414
+ (function (Sort) {
415
+ Sort["ASC"] = "asc";
416
+ Sort["DESC"] = "desc";
417
+ })(Sort || (Sort = {}));
418
+ var ClassificationPrefix;
419
+ (function (ClassificationPrefix) {
420
+ ClassificationPrefix["EMAIL"] = "mailto:";
421
+ ClassificationPrefix["EMAIL_ICON"] = "envelope";
422
+ ClassificationPrefix["PHONE"] = "tel:";
423
+ ClassificationPrefix["PHONE_ICON"] = "phone";
424
+ ClassificationPrefix["URL"] = "";
425
+ ClassificationPrefix["URL_ICON"] = "globe";
426
+ })(ClassificationPrefix || (ClassificationPrefix = {}));
427
+
428
+ class Utils {
429
+ static optionsToURLParams(options) {
430
+ if (options) {
431
+ const searchParams = new URLSearchParams();
432
+ Object.keys(options).map((k) => searchParams.append(k, options[k]));
433
+ return `?${searchParams.toString()}`;
434
+ }
435
+ return '';
436
+ }
437
+ /**
438
+ * Get all focusable child elements of a host element.
439
+ * @param host The host/parent element
440
+ * @returns Array of focusable child elements
441
+ */
442
+ static getFocusableChildren(host) {
443
+ return Array.from(host.querySelectorAll('a[href], button, input, textarea, select, details,[tabindex]:not([tabindex="-1"])')).filter((el) => !el.hasAttribute('disabled') && !el.getAttribute('aria-hidden'));
444
+ }
445
+ static hasProperty(o, property) {
446
+ if (typeof o !== 'object' || o === null) {
447
+ return false;
448
+ }
449
+ return Object.hasOwn(o, property);
450
+ }
451
+ static patternToRegExp(pattern) {
452
+ return new RegExp(pattern.replaceAll('*', '.*'));
453
+ }
454
+ /**
455
+ * Utility method for adding parameters to a given URI.
456
+ *
457
+ * @param uri The uri string to attach the parameters to
458
+ * @param params The object containing parameters to be appended
459
+ * @returns the given uri extended by the given parameters + remove empty parameters
460
+ */
461
+ static buildUri(uri, params) {
462
+ const q = Object.keys(params)
463
+ .filter((k) => !Utils.isEmptyOrFalse(params[k]))
464
+ .map((k) => k + '=' + encodeURIComponent(typeof params[k] === 'object' ? JSON.stringify(params[k]) : params[k]))
465
+ .join('&');
466
+ return uri + (q ? '?' + q : '');
467
+ }
468
+ static formatMailTo(value, isEmail) {
469
+ if (isEmail && !!value) {
470
+ if (Array.isArray(value)) {
471
+ return value.join().replace(/,/g, '; ');
472
+ }
473
+ else {
474
+ return value.replace(/,/g, '; ');
475
+ }
476
+ }
477
+ return value;
478
+ }
479
+ /**
480
+ * Creates a unique identifier.
481
+ * @returns A Universally Unique Identifier
482
+ */
483
+ static uuid() {
484
+ return Utils._p8() + Utils._p8(true) + Utils._p8(true) + Utils._p8();
485
+ }
486
+ /**
487
+ * Encode a filename safe for sending chars beyond ASCII-7bit using quoted printable encoding.
488
+ *
489
+ * @param filename The file name
490
+ * @returns The quoted printable filename
491
+ */
492
+ static encodeFileName(filename) {
493
+ const fileName = Utils.encodeToQuotedPrintable(Utils.encodeToUtf8(filename)).replace(/_/g, '=5F');
494
+ return `=?UTF-8?Q?${fileName}?=`;
495
+ }
496
+ /**
497
+ *
498
+ * @param boolean s
499
+ * @return string
500
+ */
501
+ static _p8(s) {
502
+ const p = (Math.random().toString(16) + '000000000').substr(2, 8);
503
+ return s ? `-${p.substr(0, 4)}-${p.substr(4, 4)}` : p;
504
+ }
505
+ /**
506
+ * Converts a javascript text to the utf-8 converted variant.
507
+ * See [unicode]{@link http://thlist.onlinehome.de/thomas_homepage/unicode/UTF-8%20Konvertierung%20mittels%20JavaScript.htm} for reference
508
+ *
509
+ * @param rawinput The input string
510
+ * @returns The utf-8 converted string
511
+ */
512
+ static encodeToUtf8(rawinput) {
513
+ /**
514
+ * Normalize line breaks
515
+ */
516
+ rawinput = rawinput.replace(/\r\n/g, '\n');
517
+ let utfreturn = '';
518
+ for (let n = 0; n < rawinput.length; n++) {
519
+ /**
520
+ * Unicode for current char
521
+ */
522
+ const c = rawinput.charCodeAt(n);
523
+ if (c < 128) {
524
+ /**
525
+ * All chars range 0-127 => 1byte
526
+ */
527
+ utfreturn += String.fromCharCode(c);
528
+ }
529
+ else if (c > 127 && c < 2048) {
530
+ /**
531
+ * All chars range from 127 to 2047 => 2byte
532
+ */
533
+ utfreturn += String.fromCharCode((c >> 6) | 192);
534
+ utfreturn += String.fromCharCode((c & 63) | 128);
535
+ }
536
+ else {
537
+ /**
538
+ * All chars range from 2048 to 66536 => 3byte
539
+ */
540
+ utfreturn += String.fromCharCode((c >> 12) | 224);
541
+ utfreturn += String.fromCharCode(((c >> 6) & 63) | 128);
542
+ utfreturn += String.fromCharCode((c & 63) | 128);
543
+ }
544
+ }
545
+ return utfreturn;
546
+ }
547
+ /**
548
+ * See [quoted-printable]{@link https://github.com/mathiasbynens/quoted-printable/blob/master/quoted-printable.js}
549
+ **/
550
+ static quotedPrintable(symbol) {
551
+ if (symbol > '\xFF') {
552
+ throw RangeError('`encodeToQuotedPrintable` expects extended ASCII input only. Missing prior UTF-8 encoding?');
553
+ }
554
+ const codePoint = symbol.charCodeAt(0);
555
+ const hexadecimal = codePoint.toString(16).toUpperCase();
556
+ return '=' + ('0' + hexadecimal).slice(-2);
557
+ }
558
+ /**
559
+ * Encode symbols that are definitely unsafe (i.e. unsafe in any context). The regular expression describes these unsafe symbols.
560
+ *
561
+ * @param rawinput Input string to be encoded
562
+ * @returns The encoded string
563
+ */
564
+ static encodeToQuotedPrintable(rawinput) {
565
+ const encoded = rawinput.replace(/[\0-\b\n-\x1F=\x7F-\uD7FF\uDC00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF]/g, this.quotedPrintable);
566
+ return encoded;
567
+ }
568
+ /**
569
+ * Sorts An Array of Object by given key
570
+ * See [ng-packagr issues 696]{@link https://github.com/dherges/ng-packagr/issues/696}
571
+ *
572
+ * @param key
573
+ * @param order
574
+ * @param locales
575
+ * @param options
576
+ * @returns (a: any, b: any) => number
577
+ */
578
+ static sortValues(key = '', order = Sort.ASC, locales, options) {
579
+ const f = (a, b) => {
580
+ let comparison;
581
+ const varA = Utils.getProperty(a, key);
582
+ const varB = Utils.getProperty(b, key);
583
+ if (typeof varA === 'number' && typeof varB === 'number') {
584
+ comparison = varA - varB;
585
+ }
586
+ else if (varA instanceof Date && varB instanceof Date) {
587
+ comparison = new Date(varA).getTime() - new Date(varB).getTime();
588
+ }
589
+ else {
590
+ const stringA = varA || varA === 0 ? varA.toString() : '';
591
+ const stringB = varB || varB === 0 ? varB.toString() : '';
592
+ comparison = stringA.localeCompare(stringB, locales, options);
593
+ }
594
+ return order === Sort.DESC ? comparison * -1 : comparison;
595
+ };
596
+ return f;
597
+ }
598
+ /**
599
+ * [ng-packagr issues 696]{@link https://github.com/dherges/ng-packagr/issues/696}
600
+ *
601
+ * @param object
602
+ * @param string key
603
+ * @returns any
604
+ */
605
+ static getProperty(object, key = '') {
606
+ const f = key ? key.split('.').reduce((o, k) => (o || {})[k], object) : object;
607
+ return f;
608
+ }
609
+ /**
610
+ * @param object
611
+ * @param key
612
+ * @param value
613
+ */
614
+ static setProperty(object, key = '', value) {
615
+ const [head, ...rest] = key.split('.');
616
+ !rest.length ? (object[head] = value) : Utils.setProperty(object[head] || (object[head] = {}), value, rest.join('.'));
617
+ }
618
+ /**
619
+ * Use on Observable.catch or Observable.subscribe to return empty value
620
+ * [ng-packagr issues 696]{@link https://github.com/dherges/ng-packagr/issues/696}
621
+ *
622
+ * @param (error) => any callback
623
+ * @returns (error) => Observable<never>
624
+ */
625
+ static empty(callback) {
626
+ const f = () => {
627
+ return EMPTY;
628
+ };
629
+ return f;
630
+ }
631
+ // /**
632
+ // * Use on Observable.catch with specific skipNotification function !!!
633
+ // * [ng-packagr issues 696]{@link https://github.com/dherges/ng-packagr/issues/696}
634
+ // *
635
+ // * @param skipNotification
636
+ // * @param callback
637
+ // * @param name
638
+ // * @param message
639
+ // */
640
+ // public static catchSkip(skipNotification?: (error: any) => any, callback?: (error: any) => any, name?: string, message?: string) {
641
+ // const f = (error: any) => {
642
+ // const _error = callback && callback(error);
643
+ // const _skipNotification = skipNotification && skipNotification(error);
644
+ // return throwError(() => new YuvError(_error instanceof Error ? _error : error, name, message, _skipNotification));
645
+ // };
646
+ // return f;
647
+ // }
648
+ // /**
649
+ // * Use on Observable.catch !!!
650
+ // * [ng-packagr issues]{@link https://github.com/dherges/ng-packagr/issues/696}
651
+ // *
652
+ // * @param callback
653
+ // * @param name
654
+ // * @param message
655
+ // * @param skipNotification
656
+ // * @return (error) => Observable<never>
657
+ // */
658
+ // public static catch(callback?: (error: any) => any, name?: string, message?: string, skipNotification?: boolean) {
659
+ // const f = (error: any) => {
660
+ // const _error = callback && callback(error);
661
+ // return throwError(() => new YuvError(_error instanceof Error ? _error : error, name, message, skipNotification));
662
+ // };
663
+ // return f;
664
+ // }
665
+ // /**
666
+ // * Use on Observable.subscribe !!!
667
+ // * [ng-packagr issues]{@link https://github.com/dherges/ng-packagr/issues/696}
668
+ // *
669
+ // * @param callback
670
+ // * @param name
671
+ // * @param message
672
+ // * @param skipNotification
673
+ // * @return (error) => void
674
+ // */
675
+ // public static throw(callback?: (error: any) => any, name?: string, message?: string, skipNotification?: boolean) {
676
+ // const f = (error: any) => {
677
+ // const _error = callback && callback(error);
678
+ // throw new YuvError(_error instanceof Error ? _error : error, name, message, skipNotification);
679
+ // };
680
+ // return f;
681
+ // }
682
+ // /**
683
+ // * Use on Observable.subscribe only if you want to skip notification / toast!!!
684
+ // *
685
+ // * @param callback
686
+ // * @param name
687
+ // * @param message
688
+ // * @param skipNotification
689
+ // * @return (error) => void
690
+ // */
691
+ // public static logError(callback?: (error: any) => any, name?: string, message?: string, skipNotification = true) {
692
+ // return Utils.throw(callback, name, message, skipNotification);
693
+ // }
694
+ // /**
695
+ // * Checks if element is visible
696
+ // *
697
+ // * @param elem
698
+ // * @return boolean
699
+ // */
700
+ // public static isVisible(elem: any): boolean {
701
+ // return !!(elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length);
702
+ // }
703
+ static getBaseHref(removeTrailingSlash) {
704
+ const baseEl = document.getElementsByTagName('base')[0];
705
+ const baseHref = baseEl ? baseEl.getAttribute('href') : undefined;
706
+ return baseHref ? (removeTrailingSlash ? baseHref.substr(0, baseHref.length - 1) : baseHref) : '';
707
+ }
708
+ /**
709
+ * Truncate a string (first argument) if it is longer than the given maximum string length (second argument).
710
+ * Return the truncated string with a ... ending or whats provided.
711
+ *
712
+ * @param string str
713
+ * @param number num
714
+ */
715
+ static truncateString(str, num, ending = '...') {
716
+ if (str.length > num) {
717
+ if (num > 3) {
718
+ num -= 3;
719
+ }
720
+ str = `${str.substring(0, num)}${ending}`;
721
+ }
722
+ return str;
723
+ }
724
+ /**
725
+ * Get the TimeZone Offsest as minutes
726
+ */
727
+ static getTimezoneOffset() {
728
+ return new Date().getTimezoneOffset();
729
+ }
730
+ /**
731
+ * Transform to date with yyyy-mm-dd format
732
+ */
733
+ static transformDate(v) {
734
+ return v && new Date(new Date(v).getTime() - new Date(v).getTimezoneOffset() * 60 * 1000).toISOString().slice(0, 10);
735
+ }
736
+ static isEdge() {
737
+ return new RegExp('Edge', 'i').test(navigator.userAgent);
738
+ }
739
+ static isFirefox() {
740
+ return new RegExp('firefox', 'i').test(navigator.userAgent);
741
+ }
742
+ static isSafari() {
743
+ return new RegExp('^((?!chrome|android|crios|fxios).)*safari', 'i').test(navigator.userAgent);
744
+ }
745
+ static isEmpty(obj) {
746
+ if (obj == null || obj === '') {
747
+ return true;
748
+ }
749
+ if (typeof obj === 'number') {
750
+ return isNaN(obj);
751
+ }
752
+ return typeof obj === 'boolean' ? false : !Object.keys(obj).length;
753
+ }
754
+ static isEmptyOrFalse(val) {
755
+ return typeof val === 'boolean' ? !val : Utils.isEmpty(val);
756
+ }
757
+ static escapeHtml(str) {
758
+ str = str ? str : '';
759
+ const entityMap = {
760
+ '&': '&amp;',
761
+ '<': '&lt;',
762
+ '>': '&gt;',
763
+ '"': '&quot;',
764
+ "'": '&#39;',
765
+ '/': '&#x2F;'
766
+ };
767
+ return String(str).replace(/[&<>"'\/]/g, (s) => entityMap[s]);
768
+ }
769
+ static arrayToObject(arr = [], keyProperty, valueProperty) {
770
+ const key = typeof keyProperty === 'string' ? (o) => o[keyProperty] : keyProperty;
771
+ const value = typeof valueProperty === 'string' ? (o) => o[valueProperty] : valueProperty;
772
+ return arr.reduce((acc, cur, i) => {
773
+ acc[key ? key(cur) : i] = value ? value(cur) : cur;
774
+ return acc;
775
+ }, {});
776
+ }
777
+ // public static navigate(newTab: boolean, router: Router, commands: any[], navigationExtras?: NavigationExtras): Promise<any> {
778
+ // if (newTab) {
779
+ // return new Promise(() => Utils.openWindow(router.serializeUrl(router.createUrlTree(commands, navigationExtras))));
780
+ // } else {
781
+ // return router.navigate(commands, navigationExtras);
782
+ // }
783
+ // }
784
+ // public static openWindow(url: string = '', target = '_blank', features?: string): Window | null {
785
+ // return window.open(url.match(new RegExp('^/.+')) ? url.replace(new RegExp('^/'), '') : url, target, features); // relative to host
786
+ // }
787
+ static downloadBlob(content, mimeType, filename) {
788
+ const bom = new Uint8Array([0xef, 0xbb, 0xbf]); // FORM BOM
789
+ const blob = new Blob([bom, content], { type: 'octet/stream' });
790
+ const a = document.createElement('a');
791
+ const url = window.URL.createObjectURL(blob);
792
+ a.setAttribute('href', url);
793
+ a.setAttribute('download', filename);
794
+ a.click();
795
+ URL.revokeObjectURL(url);
796
+ }
797
+ }
798
+
799
+ // enumeration of API endpoints provided by the backend
800
+ var ApiBase;
801
+ (function (ApiBase) {
802
+ ApiBase["core"] = "api";
803
+ ApiBase["apiWeb"] = "api-web/api";
804
+ ApiBase["predict"] = "predict-api/api";
805
+ // TODO: all custom services are deployed using this base
806
+ ApiBase["custom"] = "custom";
807
+ ApiBase["none"] = "";
808
+ })(ApiBase || (ApiBase = {}));
809
+
810
+ /**
811
+ * @ignore
812
+ */
813
+ const CUSTOM_CONFIG = new InjectionToken('CUSTOM_CONFIG', {
814
+ factory: () => ({ main: ['assets/_yuuvis/config/main.json'], translations: ['assets/_yuuvis/i18n/'] })
815
+ });
816
+ const CORE_CONFIG = new InjectionToken('CORE_CONFIG');
817
+
818
+ /**
819
+ * @ignore
820
+ */
821
+ let CoreConfig = class CoreConfig {
822
+ constructor(__config) {
823
+ this.main = ['assets/_yuuvis/config/main.json'];
824
+ this.translations = ['assets/_yuuvis/i18n/'];
825
+ this.environment = { production: true };
826
+ Object.assign(this, __config);
827
+ }
828
+ };
829
+ CoreConfig = __decorate([
830
+ __param(0, Inject(CUSTOM_CONFIG)),
831
+ __metadata("design:paramtypes", [CoreConfig])
832
+ ], CoreConfig);
833
+
834
+ class OidcService {
835
+ constructor(oAuthConfig, config, oauthService) {
836
+ this.oAuthConfig = oAuthConfig;
837
+ this.config = config;
838
+ this.oauthService = oauthService;
839
+ }
840
+ initOpenIdConnect(oidc) {
841
+ oidc = this.config.oidc = oidc || this.config.oidc;
842
+ if (oidc?.host) {
843
+ oidc.host = oidc.host.endsWith('/') ? oidc.host.substring(0, -1) : oidc.host;
844
+ }
845
+ else
846
+ return of(undefined);
847
+ this.oAuthConfig.resourceServer = {
848
+ sendAccessToken: true,
849
+ allowedUrls: [oidc.host]
850
+ };
851
+ const authConfig = {
852
+ strictDiscoveryDocumentValidation: false,
853
+ issuer: oidc.issuer,
854
+ redirectUri: oidc.redirectUri || window.location.origin + '/',
855
+ postLogoutRedirectUri: oidc.postLogoutRedirectUri || window.location.origin + '/',
856
+ clientId: oidc.clientId,
857
+ responseType: 'code',
858
+ scope: 'openid profile email offline_access',
859
+ showDebugInformation: false,
860
+ requireHttps: false,
861
+ disableAtHashCheck: true,
862
+ sessionCheckIntervall: 60000,
863
+ sessionChecksEnabled: true,
864
+ clearHashAfterLogin: false,
865
+ silentRefreshTimeout: 5000 // For faster testing
866
+ };
867
+ this.oauthService.configure(authConfig);
868
+ this.oauthService.setupAutomaticSilentRefresh();
869
+ return from(this.oauthService.loadDiscoveryDocumentAndLogin()).pipe(map(() => this.config.oidc));
870
+ }
871
+ logout() {
872
+ this.oauthService.logOut();
873
+ }
874
+ setupCookie(viewer, path, headers) {
875
+ return new Observable((subscriber) => {
876
+ let iframe = document.querySelector('body > iframe#__oidc');
877
+ if (!iframe) {
878
+ iframe = document.createElement('iframe');
879
+ iframe.style.display = 'none';
880
+ iframe.id = '__oidc';
881
+ iframe.onload = () => {
882
+ iframe.subscriber.next({});
883
+ iframe.subscriber.complete();
884
+ };
885
+ }
886
+ iframe.subscriber = subscriber;
887
+ iframe.setAttribute('src', `${viewer}/download?setCookie=/&path=${encodeURIComponent(path)}&headers=${encodeURIComponent(JSON.stringify(headers))}`);
888
+ document.body.appendChild(iframe);
889
+ });
890
+ }
891
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OidcService, deps: [{ token: i1.OAuthModuleConfig, optional: true }, { token: CORE_CONFIG }, { token: i1.OAuthService }], target: i0.ɵɵFactoryTarget.Injectable }); }
892
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OidcService, providedIn: 'root' }); }
893
+ }
894
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OidcService, decorators: [{
895
+ type: Injectable,
896
+ args: [{
897
+ providedIn: 'root'
898
+ }]
899
+ }], ctorParameters: () => [{ type: i1.OAuthModuleConfig, decorators: [{
900
+ type: Optional
901
+ }] }, { type: CoreConfig, decorators: [{
902
+ type: Inject,
903
+ args: [CORE_CONFIG]
904
+ }] }, { type: i1.OAuthService }] });
905
+
906
+ /**
907
+ * Load and provide configuration for hole apllication while application is inizialized.
908
+ */
909
+ class ConfigService {
910
+ constructor() {
911
+ this.translate = inject(TranslateService);
912
+ this.oidcService = inject(OidcService);
913
+ }
914
+ static { this.GLOBAL_RESOURCES = '/resources/config/'; }
915
+ static PARSER(c) {
916
+ return c?.resolved || c?.tenant || c?.global || c || {};
917
+ }
918
+ static GLOBAL_MAIN_CONFIG(prefix = '') {
919
+ return ConfigService.GLOBAL_RESOURCES_PATH('main-config', prefix);
920
+ }
921
+ static GLOBAL_MAIN_CONFIG_LANG(iso = 'en', prefix = '') {
922
+ return ConfigService.GLOBAL_RESOURCES_PATH('main-config-language-' + iso, prefix);
923
+ }
924
+ static GLOBAL_RESOURCES_PATH(section = '', prefix = '') {
925
+ return (prefix ? `/${prefix}` : '') + ConfigService.GLOBAL_RESOURCES + encodeURIComponent(section) + '?filter=resolved';
926
+ }
927
+ get oidc() {
928
+ return this.oidcService.config?.oidc;
929
+ }
930
+ /**
931
+ * Set during app init (see CoreInit)
932
+ * @ignore
933
+ */
934
+ set(cfg) {
935
+ this.cfg = cfg;
936
+ const languages = this.getClientLocales().map((lang) => lang.iso);
937
+ this.translate.addLangs(languages);
938
+ const browserLang = this.translate.getBrowserLang();
939
+ const defaultLang = browserLang && languages.includes(browserLang) ? browserLang : this.getDefaultClientLocale();
940
+ this.translate.setDefaultLang(defaultLang);
941
+ this.translate.use(defaultLang);
942
+ this.extendTranslations(defaultLang);
943
+ }
944
+ get(configKey) {
945
+ return configKey ? Utils.getProperty(this.cfg, configKey) : null;
946
+ }
947
+ extendTranslations(translations, lang = this.translate.currentLang) {
948
+ const allKeys = translations && Object.keys(this.translate.store?.translations[lang] || {});
949
+ if (translations && !Object.keys(translations).every((k) => allKeys.includes(k))) {
950
+ this.translate.setTranslation(lang, translations, true);
951
+ }
952
+ }
953
+ extendConfig(configs) {
954
+ this.set(this._mergeConfigs(configs || []));
955
+ }
956
+ _mergeConfigs(configs) {
957
+ return configs.reduce((acc, x) => {
958
+ // merge object values on 2nd level
959
+ Object.keys(x).forEach((k) => (!acc[k] || Array.isArray(x[k]) || typeof x[k] !== 'object' ? (acc[k] = x[k]) : Object.assign(acc[k], x[k])));
960
+ return acc;
961
+ }, {});
962
+ }
963
+ authUsesOpenIdConnect() {
964
+ return !!this.oidc?.host && !!this.oidc?.tenant;
965
+ }
966
+ /**
967
+ * OpenIdConnect authorization headers
968
+ */
969
+ getAuthHeaders(authorization = false) {
970
+ if (this.authUsesOpenIdConnect()) {
971
+ let headers = new HttpHeaders().set(TENANT_HEADER, this.oidc.tenant);
972
+ if (authorization) {
973
+ headers = headers.set('authorization', 'Bearer ' + localStorage.getItem('access_token'));
974
+ }
975
+ return headers;
976
+ }
977
+ return new HttpHeaders();
978
+ }
979
+ /**
980
+ * Getter for the available client locales
981
+ * @returns available client locales
982
+ */
983
+ getClientLocales() {
984
+ return this._getCoreConfig('languages');
985
+ }
986
+ getApiBase(api = ApiBase.apiWeb, origin = false) {
987
+ api = api || ApiBase.none;
988
+ const href = api === ApiBase.none ? api : `/${api}`;
989
+ const host = this.oidc?.host || (origin && location.origin) || '';
990
+ return href.startsWith('http') ? href : host + href;
991
+ }
992
+ /**
993
+ * Get the default client locale
994
+ * @returns ISO string of the locale
995
+ */
996
+ getDefaultClientLocale() {
997
+ const lang = this.getClientLocales().find((_) => _.fallback);
998
+ return lang ? lang.iso : 'en';
999
+ }
1000
+ _getCoreConfig(key) {
1001
+ return this.cfg ? this.cfg.core[key] : undefined;
1002
+ }
1003
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1004
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ConfigService, providedIn: 'root' }); }
1005
+ }
1006
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ConfigService, decorators: [{
1007
+ type: Injectable,
1008
+ args: [{
1009
+ providedIn: 'root'
1010
+ }]
1011
+ }] });
1012
+
1013
+ /**
1014
+ * Set up the default logger.
1015
+ * The default logger doesn't actually log anything;
1016
+ * but, it provides the Dependency-Injection (DI) token that the rest of the
1017
+ * application can use for dependency resolution. Each platform can then override
1018
+ * this with a platform-specific logger implementation.
1019
+ *
1020
+ * @ignore
1021
+ */
1022
+ class Logger {
1023
+ error(...args) {
1024
+ // ... the default logger does no work.
1025
+ }
1026
+ debug(...args) {
1027
+ // ... the default logger does no work.
1028
+ }
1029
+ info(...args) {
1030
+ // ... the default logger does no work.
1031
+ }
1032
+ log(...args) {
1033
+ // ... the default logger does no work.
1034
+ }
1035
+ warn(...args) {
1036
+ // ... the default logger does no work.
1037
+ }
1038
+ }
1039
+
1040
+ /**
1041
+ * Service for providing an yuuvis Backend
1042
+ */
1043
+ class BackendService {
1044
+ constructor() {
1045
+ this.#http = inject(HttpClient);
1046
+ this.#logger = inject(Logger);
1047
+ this.configService = inject(ConfigService);
1048
+ this.#cache = new Map();
1049
+ this.#temp = new Map();
1050
+ this.#headers = new HttpHeaders({
1051
+ 'Content-Type': 'application/json'
1052
+ });
1053
+ }
1054
+ #http;
1055
+ #logger;
1056
+ #cache;
1057
+ #temp;
1058
+ #headers;
1059
+ authUsesOpenIdConnect() {
1060
+ return this.configService.authUsesOpenIdConnect();
1061
+ }
1062
+ /**
1063
+ * OpenIdConnect authorization headers
1064
+ */
1065
+ getAuthHeaders() {
1066
+ return this.configService.getAuthHeaders();
1067
+ }
1068
+ /**
1069
+ * Add a new header.
1070
+ * @param key The headers name
1071
+ * @param value The value to be added to the headers. Setting this to null
1072
+ * will remove the header
1073
+ */
1074
+ setHeader(key, value) {
1075
+ if (value && value.length) {
1076
+ this.#headers = this.#headers.set(key, value);
1077
+ }
1078
+ else {
1079
+ this.#headers = this.#headers.delete(key);
1080
+ }
1081
+ }
1082
+ /**
1083
+ * Wrapped HTTP GET method
1084
+ * @param uri The REST URI to be queried
1085
+ * @param base The Base URI (backend service) to be used
1086
+ * @param requestOptions Additional request options
1087
+ * @returns The data retrieved from the given endpoint
1088
+ */
1089
+ get(uri, base, requestOptions) {
1090
+ return this.#http.get(this.getApiBase(base) + uri, this.getHttpOptions(requestOptions));
1091
+ }
1092
+ /**
1093
+ * Wrapped HTTP POST method
1094
+ * @param uri The target REST URI
1095
+ * @param data Data to be 'posted'
1096
+ * @param base The Base URI (backend service) to be used
1097
+ * @param requestOptions Additional request options
1098
+ * @returns The return value of the target POST endpoint
1099
+ */
1100
+ post(uri, data, base, requestOptions) {
1101
+ const baseUri = this.getApiBase(base);
1102
+ const payload = data && typeof data === 'object' ? JSON.stringify(data) : data || '';
1103
+ return this.#http.post(`${baseUri}${uri}`, payload, this.getHttpOptions(requestOptions));
1104
+ }
1105
+ /**
1106
+ * Performs a multipart form data POST request.
1107
+ * @param uri The target REST URI
1108
+ * @param formData FormData to be 'posted'
1109
+ * @param base The Base URI (backend service) to be used
1110
+ * @param requestOptions Additional request options
1111
+ * @returns The return value of the target POST endpoint
1112
+ */
1113
+ postMultiPart(uri, formData, base, requestOptions) {
1114
+ return this.#http.post(`${this.getApiBase(base)}${uri}`, formData, this.getHttpOptions(requestOptions));
1115
+ }
1116
+ /**
1117
+ * Wrapped HTTP PATCH method
1118
+ * @param uri The target REST URI
1119
+ * @param data Data to be 'patched'
1120
+ * @param base The Base URI (backend service) to be used
1121
+ * @param requestOptions Additional request options
1122
+ * @returns The return value of the target PATCH endpoint
1123
+ */
1124
+ patch(uri, data, base, requestOptions) {
1125
+ const baseUri = this.getApiBase(base);
1126
+ const payload = data ? JSON.stringify(data) : '';
1127
+ return this.#http.patch(`${baseUri}${uri}`, payload, this.getHttpOptions(requestOptions));
1128
+ }
1129
+ /**
1130
+ * Wrapped HTTP PUT method
1131
+ * @param uri The target REST URI
1132
+ * @param data Data to be 'posted'
1133
+ * @param base The Base URI (backend service) to be used
1134
+ * @param requestOptions Additional request options
1135
+ * @returns The return value of the target PUT endpoint
1136
+ */
1137
+ put(uri, data, base, requestOptions) {
1138
+ return this.#http.put(this.getApiBase(base) + uri, data, this.getHttpOptions(requestOptions));
1139
+ }
1140
+ /**
1141
+ * Wrapped HTTP DELETE method
1142
+ * @param uri The target REST URI
1143
+ * @param base The Base URI (backend service) to be used
1144
+ * @param requestOptions Additional request options
1145
+ * @returns The return value of the target DELETE endpoint
1146
+ */
1147
+ delete(uri, base, requestOptions) {
1148
+ return this.#http.delete(this.getApiBase(base) + uri, this.getHttpOptions(requestOptions));
1149
+ }
1150
+ /**
1151
+ * @ignore
1152
+ * Cache for small requests like icons and configs
1153
+ *
1154
+ * @param string uri
1155
+ * @returns Observable<any>
1156
+ */
1157
+ getViaCache(uri) {
1158
+ if (this.#cache.has(uri)) {
1159
+ return of(this.#cache.get(uri));
1160
+ }
1161
+ else {
1162
+ const requestOptions = {
1163
+ responseType: 'text',
1164
+ headers: this.getAuthHeaders()
1165
+ };
1166
+ return this.getViaTempCache(uri, () => this.#http.get(uri, requestOptions).pipe(tap((text) => this.#cache.set(uri, text))));
1167
+ }
1168
+ }
1169
+ /**
1170
+ * @ignore
1171
+ * Temporary Cache for multiple identical requests
1172
+ *
1173
+ * @param string id
1174
+ * @param Function request
1175
+ * @returns Observable<any>
1176
+ */
1177
+ getViaTempCache(id, request) {
1178
+ if (this.#temp.has(id)) {
1179
+ return this.#temp.get(id);
1180
+ }
1181
+ else {
1182
+ const resp = (request ? request() : this.get(id)).pipe(finalize(() => this.#temp.delete(id)), shareReplay(1));
1183
+ this.#temp.set(id, resp);
1184
+ return resp;
1185
+ }
1186
+ }
1187
+ download(uri, filename) {
1188
+ if (document && document.body) {
1189
+ const a = document.createElement('a');
1190
+ a.setAttribute('href', uri);
1191
+ a.style.display = 'none';
1192
+ a.setAttribute('download', filename || 'download');
1193
+ document.body.appendChild(a);
1194
+ a.click();
1195
+ document.body.removeChild(a);
1196
+ }
1197
+ else {
1198
+ this.#logger.error('Environment not supported. Downloading contents relies on a DOM being available.');
1199
+ }
1200
+ }
1201
+ /**
1202
+ * Gets the base URI for an API endpoint
1203
+ * @param api The API to get the base URI for. Leaving this blank will return
1204
+ * base URI for the web API
1205
+ * @param origin The flag to include location origin
1206
+ * @returns Base URI for the given API.
1207
+ */
1208
+ getApiBase(api = ApiBase.apiWeb, origin = false) {
1209
+ return this.configService.getApiBase(api, origin);
1210
+ }
1211
+ /**
1212
+ * @ignore
1213
+ */
1214
+ getHttpOptions(requestOptions) {
1215
+ // Object.entries(this.getAuthHeaders()).forEach(([h, v]) => this.setHeader(h, v as string));
1216
+ this.getAuthHeaders()
1217
+ .keys()
1218
+ .forEach((k) => this.setHeader(k, this.getAuthHeaders().get(k)));
1219
+ return Object.assign({ headers: this.#headers }, requestOptions);
1220
+ }
1221
+ /**
1222
+ * Batch service
1223
+ */
1224
+ batch(requests) {
1225
+ const httpRequests = requests.map((r) => this[(r.method || 'get').toLowerCase()]
1226
+ .apply(this, [r.uri, r.body, r.base, r.requestOptions].filter((a) => a))
1227
+ .pipe(catchError((err) => of({ _error: err }))));
1228
+ return forkJoin(httpRequests);
1229
+ }
1230
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BackendService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1231
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BackendService, providedIn: 'root' }); }
1232
+ }
1233
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BackendService, decorators: [{
1234
+ type: Injectable,
1235
+ args: [{ providedIn: 'root' }]
1236
+ }] });
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
+ var Operator;
1412
+ (function (Operator) {
1413
+ Operator["EQUAL"] = "eq";
1414
+ Operator["EEQUAL"] = "eeq";
1415
+ Operator["IN"] = "in";
1416
+ Operator["GREATER_THAN"] = "gt";
1417
+ Operator["GREATER_OR_EQUAL"] = "gte";
1418
+ Operator["LESS_THAN"] = "lt";
1419
+ Operator["LESS_OR_EQUAL"] = "lte";
1420
+ Operator["INTERVAL"] = "gtlt";
1421
+ Operator["INTERVAL_INCLUDE_BOTH"] = "gtelte";
1422
+ Operator["INTERVAL_INCLUDE_TO"] = "gtlte";
1423
+ Operator["INTERVAL_INCLUDE_FROM"] = "gtelt";
1424
+ Operator["RANGE"] = "rg";
1425
+ Operator["LIKE"] = "like";
1426
+ Operator["CONTAINS"] = "contains"; // contains
1427
+ })(Operator || (Operator = {}));
1428
+ const OperatorLabel = {
1429
+ /** equal */
1430
+ EQUAL: '=',
1431
+ /** exact equal */
1432
+ EEQUAL: '==',
1433
+ /** match at least one of the provided values (value has to be an array) */
1434
+ IN: '~',
1435
+ /** greater than */
1436
+ GREATER_THAN: '>',
1437
+ /** greater than or equal */
1438
+ GREATER_OR_EQUAL: '≽', //
1439
+ LESS_THAN: '<', // less than
1440
+ LESS_OR_EQUAL: '≼', // less than or equal
1441
+ INTERVAL: '<>', // interval
1442
+ INTERVAL_INCLUDE_BOTH: '-', // interval include left and right
1443
+ INTERVAL_INCLUDE_TO: '>-', // interval include right
1444
+ INTERVAL_INCLUDE_FROM: '-<', // interval include left
1445
+ RANGE: '=', // aggegation ranges
1446
+ LIKE: '~', // like
1447
+ CONTAINS: '~' // contains
1448
+ };
1449
+
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
+ /**
1505
+ * Service for saving or caching data on the users device. It uses the most efficient storage
1506
+ * available (IndexDB, localstorage, ...) on the device. Depending on the type of storage used,
1507
+ * its limitations apply.
1508
+ */
1509
+ class AppCacheService {
1510
+ #storage = inject(StorageMap);
1511
+ setItem(key, value) {
1512
+ return this.#storage.set(key, value).pipe(map(() => true));
1513
+ }
1514
+ getItem(key) {
1515
+ return this.#storage.get(key);
1516
+ }
1517
+ removeItem(key) {
1518
+ return this.#storage.delete(key).pipe(map(() => true));
1519
+ }
1520
+ clear(filter) {
1521
+ return filter
1522
+ ? this.getStorageKeys().pipe(switchMap((keys) => {
1523
+ const list = keys.filter((k) => filter(k)).map((k) => this.removeItem(k));
1524
+ return list.length ? forkJoin(list).pipe(map(() => true)) : of(true);
1525
+ }))
1526
+ : this.#storage.clear().pipe(map(() => true));
1527
+ }
1528
+ getStorageKeys() {
1529
+ return new Observable((observer) => {
1530
+ const keys = [];
1531
+ this.#storage.keys().subscribe({
1532
+ next: (key) => keys.push(key),
1533
+ complete: () => observer.next(keys)
1534
+ });
1535
+ }).pipe(first());
1536
+ }
1537
+ setStorage(options) {
1538
+ return forkJoin(Object.keys(options || {}).map((k) => this.setItem(k, options[k])));
1539
+ }
1540
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AppCacheService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1541
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AppCacheService, providedIn: 'root' }); }
1542
+ }
1543
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AppCacheService, decorators: [{
1544
+ type: Injectable,
1545
+ args: [{
1546
+ providedIn: 'root'
1547
+ }]
1548
+ }] });
1549
+
1550
+ /**
1551
+ * Providing system definitions.
1552
+ */
1553
+ class SystemService {
1554
+ constructor() {
1555
+ this.#backend = inject(BackendService);
1556
+ this.#appCache = inject(AppCacheService);
1557
+ this.#logger = inject(Logger);
1558
+ this.#STORAGE_KEY = 'yuv.core.system.definition';
1559
+ this.#STORAGE_KEY_AUTH_DATA = 'yuv.core.auth.data';
1560
+ // cached icons to avoid backend calls (session cache)
1561
+ this.#iconCache = {};
1562
+ this.#resolvedClassificationsCache = {};
1563
+ this.#systemSource = new ReplaySubject();
1564
+ this.system$ = this.#systemSource.asObservable();
1565
+ // cache for resolved visible tags because they are used in lists and therefore should not be re-evaluated all the time
1566
+ this.#visibleTagsCache = {};
1567
+ }
1568
+ #backend;
1569
+ #appCache;
1570
+ #logger;
1571
+ #STORAGE_KEY;
1572
+ #STORAGE_KEY_AUTH_DATA;
1573
+ // cached icons to avoid backend calls (session cache)
1574
+ #iconCache;
1575
+ #resolvedClassificationsCache;
1576
+ #systemSource;
1577
+ // cache for resolved visible tags because they are used in lists and therefore should not be re-evaluated all the time
1578
+ #visibleTagsCache;
1579
+ #permissions;
1580
+ /**
1581
+ * Get all object types
1582
+ * @param withLabels Whether or not to also add the types labels
1583
+ */
1584
+ getObjectTypes(withLabels, situation) {
1585
+ // Filter by user permissions based on situation
1586
+ const objectTypes = this.#filterByPermissions([...this.system.objectTypes, ...this.system.secondaryObjectTypes.map((sot) => this.#sotToGenericType(sot))], situation);
1587
+ return withLabels ? objectTypes.map((t) => ({ ...t, label: this.getLocalizedResource(`${t.id}_label`) })) : objectTypes;
1588
+ }
1589
+ #sotToGenericType(sot) {
1590
+ return {
1591
+ ...sot,
1592
+ isFolder: false,
1593
+ creatable: true,
1594
+ secondaryObjectTypes: [],
1595
+ isSot: true
1596
+ };
1597
+ }
1598
+ /**
1599
+ * Get all secondary object types
1600
+ * @param withLabels Whether or not to also add the types labels
1601
+ */
1602
+ getSecondaryObjectTypes(withLabels, situation) {
1603
+ const sots = this.#filterByPermissions(this.system.secondaryObjectTypes.map((sot) => this.#sotToGenericType(sot)), situation);
1604
+ return ((withLabels ? sots.map((t) => ({ ...t, label: this.getLocalizedResource(`${t.id}_label`) })) : sots)
1605
+ // ignore
1606
+ .filter((t) => t.id !== t.baseId && !t.id.startsWith('system:') && t.id !== 'appClientsystem:leadingType'));
1607
+ }
1608
+ #filterByPermissions(types, situation) {
1609
+ if (!situation)
1610
+ return types;
1611
+ const allowedTypes = situation === 'search' ? this.#permissions.searchableObjectTypes : this.#permissions.createableObjectTypes;
1612
+ return types.filter((t) => allowedTypes.includes(t.id));
1613
+ }
1614
+ /**
1615
+ * Get a particular object type
1616
+ * @param objectTypeId ID of the object type
1617
+ * @param withLabel Whether or not to also add the types label
1618
+ */
1619
+ getObjectType(objectTypeId, withLabel) {
1620
+ let objectType = objectTypeId === SystemType.OBJECT ? this.getBaseType() : this.system.objectTypes.find((ot) => ot.id === objectTypeId);
1621
+ if (objectType && withLabel) {
1622
+ objectType.label = this.getLocalizedResource(`${objectType.id}_label`) || objectTypeId;
1623
+ }
1624
+ if (!objectType) {
1625
+ // no 'real' object type found. Try to find a matching SOT and treat it like a real type
1626
+ // by filling up the missing properties
1627
+ const sot = this.getSecondaryObjectType(objectTypeId, withLabel);
1628
+ if (sot) {
1629
+ objectType = this.#sotToGenericType(sot);
1630
+ }
1631
+ }
1632
+ return objectType;
1633
+ }
1634
+ /**
1635
+ * Get a particular secondary object type
1636
+ * @param objectTypeId ID of the object type
1637
+ * @param withLabel Whether or not to also add the types label
1638
+ */
1639
+ getSecondaryObjectType(objectTypeId, withLabel) {
1640
+ const objectType = this.system.secondaryObjectTypes.find((ot) => ot.id === objectTypeId);
1641
+ if (objectType && withLabel) {
1642
+ objectType.label = this.getLocalizedResource(`${objectType.id}_label`) || objectType.id;
1643
+ }
1644
+ return objectType;
1645
+ }
1646
+ /**
1647
+ * Get the base document type all documents belong to
1648
+ * @param withLabel Whether or not to also add the types label
1649
+ */
1650
+ getBaseDocumentType(withLabel) {
1651
+ return this.getObjectType(SystemType.DOCUMENT, withLabel);
1652
+ }
1653
+ /**
1654
+ * Get the base folder type all folders belong to
1655
+ * @param withLabel Whether or not to also add the types label
1656
+ */
1657
+ getBaseFolderType(withLabel) {
1658
+ return this.getObjectType(SystemType.FOLDER, withLabel);
1659
+ }
1660
+ /**
1661
+ * Get the base object type all dms objects belong to
1662
+ */
1663
+ getBaseType() {
1664
+ const sysFolder = this.getBaseFolderType();
1665
+ const sysDocument = this.getBaseDocumentType();
1666
+ // base type contains only fields that are shared by base document and base folder ...
1667
+ const folderTypeFieldIDs = sysFolder.fields.map((f) => f.id);
1668
+ const baseTypeFields = sysDocument.fields.filter((f) => folderTypeFieldIDs.includes(f.id));
1669
+ return {
1670
+ id: SystemType.OBJECT,
1671
+ creatable: false,
1672
+ isFolder: false,
1673
+ secondaryObjectTypes: [],
1674
+ fields: baseTypeFields
1675
+ // rawFields: baseTypeFields
1676
+ };
1677
+ }
1678
+ /**
1679
+ * Get the resolved object type with all fields ( including fields from related secondary types )
1680
+ */
1681
+ getResolvedType(objectTypeId) {
1682
+ const abstractTypes = Object.values(SystemType);
1683
+ if (!objectTypeId || abstractTypes.includes(objectTypeId)) {
1684
+ const baseType = this.getBaseType();
1685
+ return { id: baseType.id, fields: baseType.fields };
1686
+ }
1687
+ const ot = this.getObjectType(objectTypeId);
1688
+ if (!ot) {
1689
+ const sot = this.getSecondaryObjectType(objectTypeId) || { id: objectTypeId, fields: [] };
1690
+ const baseType = this.getBaseType();
1691
+ return {
1692
+ id: sot.id,
1693
+ fields: [...sot.fields, ...baseType.fields]
1694
+ };
1695
+ }
1696
+ return {
1697
+ id: ot.id,
1698
+ fields: ot.fields
1699
+ };
1700
+ }
1701
+ /**
1702
+ * Get the resolved object tags
1703
+ */
1704
+ getResolvedTags(objectTypeId) {
1705
+ const vTags = this.getVisibleTags(objectTypeId);
1706
+ return Object.keys(vTags).map((k) => ({
1707
+ id: objectTypeId,
1708
+ tagName: k,
1709
+ tagValues: vTags[k],
1710
+ fields: this.getBaseType().fields.filter((f) => f.id === BaseObjectTypeField.TAGS)
1711
+ }));
1712
+ }
1713
+ /**
1714
+ * Get a list of classifications for a given object type including the
1715
+ * classifications of its static secondary object types
1716
+ * @param objectTypeId ID of the object type
1717
+ */
1718
+ getResolvedClassifications(objectTypeId) {
1719
+ return this.#resolvedClassificationsCache[objectTypeId] || this.#resolveClassifications(objectTypeId);
1720
+ }
1721
+ #resolveClassifications(objectTypeId) {
1722
+ let classifications = [];
1723
+ const ot = this.getObjectType(objectTypeId);
1724
+ if (ot) {
1725
+ classifications = ot.classification || [];
1726
+ const staticSOTs = ot.secondaryObjectTypes ? ot.secondaryObjectTypes.filter((sot) => sot.static).map((sot) => sot.id) : [];
1727
+ staticSOTs.forEach((id) => {
1728
+ const sot = this.getSecondaryObjectType(id);
1729
+ classifications = sot?.classification
1730
+ ? [
1731
+ ...classifications,
1732
+ ...sot.classification.filter((c) => {
1733
+ // also filter classifications that should not be inherited
1734
+ return c !== ObjectTypeClassification.CREATE_FALSE && c !== ObjectTypeClassification.SEARCH_FALSE;
1735
+ })
1736
+ ]
1737
+ : classifications;
1738
+ });
1739
+ this.#resolvedClassificationsCache[objectTypeId] = classifications;
1740
+ }
1741
+ return classifications;
1742
+ }
1743
+ /**
1744
+ * Visible tags are defined by a classification on the object type (e.g. 'tag[tenkolibri:process,1,2,3]').
1745
+ *
1746
+ * The example will only return tags with the name 'tenkolibri:process'
1747
+ * and values of either 1, 2 or 3. All other tags will be ignored.
1748
+ *
1749
+ * @param objectTypeId ID of the object type to get the visible tags for
1750
+ * @returns object where the property name is the name of the tag and its value are the visible values
1751
+ * for that tag (if values is emoty all values are allowed)
1752
+ */
1753
+ getVisibleTags(objectTypeId) {
1754
+ return this.#visibleTagsCache[objectTypeId] || this.fetchVisibleTags(objectTypeId);
1755
+ }
1756
+ fetchVisibleTags(objectTypeId) {
1757
+ const ot = this.getObjectType(objectTypeId) || this.getSecondaryObjectType(objectTypeId);
1758
+ const tagClassifications = this.getResolvedClassifications(objectTypeId).filter((t) => t.startsWith('tag['));
1759
+ const parentType = ot && ot.id;
1760
+ const to = {};
1761
+ (tagClassifications || []).forEach((tag) => {
1762
+ const m = tag.match(/\[(.*)\]/i)[1].split(',');
1763
+ const tagName = m.splice(0, 1)[0];
1764
+ const tagValues = m.map((v) => parseInt(v.trim()));
1765
+ to[tagName] = tagValues;
1766
+ });
1767
+ this.#visibleTagsCache[objectTypeId] = parentType ? { ...this.getVisibleTags(parentType), ...to } : to;
1768
+ return this.#visibleTagsCache[objectTypeId];
1769
+ }
1770
+ filterVisibleTags(objectTypeId, tagsValue) {
1771
+ if (!tagsValue)
1772
+ return [];
1773
+ const vTags = this.getVisibleTags(objectTypeId);
1774
+ // Tag value looks like this: [tagName: string, state: number, date: Date, traceId: string]
1775
+ return tagsValue.filter((v) => !!vTags[v[0]] && vTags[v[0]].includes(v[1]));
1776
+ }
1777
+ /**
1778
+ * Get the icon for an object type. This will return an SVG as a string.
1779
+ * @param objectTypeId ID of the object type
1780
+ * @param fallback ID of a fallback icon that should be used if the given object type has no icon yet
1781
+ */
1782
+ getObjectTypeIcon(objectTypeId, fallback) {
1783
+ if (this.#iconCache[objectTypeId] && this.#iconCache[objectTypeId].icon) {
1784
+ return of(this.#iconCache[objectTypeId].icon);
1785
+ }
1786
+ else {
1787
+ const iconUri = this.getObjectTypeIconUri(objectTypeId, fallback);
1788
+ return this.#backend.get(iconUri).pipe(tap((icon) => (this.#iconCache[objectTypeId] = { uri: iconUri, icon })));
1789
+ }
1790
+ }
1791
+ /**
1792
+ * Get the URI of an object type icon.
1793
+ * @param objectTypeId ID of the object type
1794
+ * @param fallback ID of a fallback icon that should be used if the given object type has no icon yet
1795
+ */
1796
+ getObjectTypeIconUri(objectTypeId, fallback) {
1797
+ if (this.#iconCache[objectTypeId]) {
1798
+ return this.#iconCache[objectTypeId].uri;
1799
+ }
1800
+ else {
1801
+ const ci = this.#getIconFromClassification(objectTypeId);
1802
+ const fb = this.getFallbackIcon(objectTypeId, fallback);
1803
+ const uri = `/resources/icons/${encodeURIComponent(ci || objectTypeId)}${fb ? `?fallback=${encodeURIComponent(fb)}` : ''}`;
1804
+ this.#iconCache[objectTypeId] = { uri: `${this.#backend.getApiBase(ApiBase.apiWeb)}${uri}` };
1805
+ return this.#iconCache[objectTypeId].uri;
1806
+ }
1807
+ }
1808
+ getFallbackIcon(objectTypeId, fallback) {
1809
+ const ot = this.getObjectType(objectTypeId);
1810
+ if (ot && !fallback) {
1811
+ // add default fallbacks for system:document and system:folder if now other fallback has been provided
1812
+ fallback = ot.isFolder ? 'system:folder' : 'system:document';
1813
+ // if (this.isFloatingObjectType(ot)) {
1814
+ // // types that do not have no object type assigned to them (primary FSOTs)
1815
+ // fallback = 'system:dlm';
1816
+ // }
1817
+ }
1818
+ return fallback;
1819
+ }
1820
+ #getIconFromClassification(objectTypeId) {
1821
+ const ce = this.getClassifications(this.getResolvedClassifications(objectTypeId));
1822
+ return ce.has(ObjectTypeClassification.OBJECT_TYPE_ICON) ? ce.get(ObjectTypeClassification.OBJECT_TYPE_ICON).options[0] : null;
1823
+ }
1824
+ getLocalizedResource(key) {
1825
+ return this.system.i18n[key];
1826
+ }
1827
+ getLocalizedLabel(id) {
1828
+ return this.getLocalizedResource(`${id}_label`);
1829
+ }
1830
+ getLocalizedDescription(id) {
1831
+ return this.getLocalizedResource(`${id}_description`);
1832
+ }
1833
+ /**
1834
+ * Determine whether or not the given object type field is a system field
1835
+ * @param field Object type field to be checked
1836
+ */
1837
+ isSystemProperty(field) {
1838
+ return field.id.startsWith('system:');
1839
+ }
1840
+ /**
1841
+ * Fetches the backends system definition and updates system$ Observable.
1842
+ * Subscribe to the system$ observable instead of calling this function, otherwise you'll trigger fetching the
1843
+ * system definition every time.
1844
+ *
1845
+ * @param user The user to load the system definition for
1846
+ */
1847
+ getSystemDefinition(authData) {
1848
+ // TODO: Supposed to return 304 if nothing changes
1849
+ return this.#fetchSystemDefinition(authData);
1850
+ // TODO: remove when 304 is there???
1851
+ // // try to fetch system definition from cache first
1852
+ // return this.appCache.getItem(this.STORAGE_KEY).pipe(
1853
+ // switchMap(res => {
1854
+ // if (res) {
1855
+ // // check if the system definition from the cache is up to date
1856
+ // this.system = res;
1857
+ // this.systemSource.next(this.system);
1858
+ // return of(true);
1859
+ // } else {
1860
+ // // nothing cached so far
1861
+ // return this.fetchSystemDefinition();
1862
+ // }
1863
+ // })
1864
+ // );
1865
+ }
1866
+ /**
1867
+ * Actually fetch the system definition from the backend.
1868
+ * @param user User to fetch definition for
1869
+ */
1870
+ #fetchSystemDefinition(authData) {
1871
+ return (authData ? of(authData) : this.#appCache.getItem(this.#STORAGE_KEY_AUTH_DATA)).pipe(switchMap((data) => {
1872
+ this.updateAuthData(data).subscribe();
1873
+ const fetchTasks = [this.#backend.get('/dms/schema/native.json', ApiBase.core), this.#fetchLocalizations()];
1874
+ return forkJoin(fetchTasks);
1875
+ }), catchError((error) => {
1876
+ this.#logger.error('Error fetching recent version of system definition from server.', error);
1877
+ this.#systemSource.error('Error fetching recent version of system definition from server.');
1878
+ return of(null);
1879
+ }), map((data) => {
1880
+ if (data?.length) {
1881
+ this.setSchema(data[0], data[1]);
1882
+ }
1883
+ return !!data;
1884
+ }));
1885
+ }
1886
+ setPermissions(p) {
1887
+ this.#permissions = p;
1888
+ }
1889
+ /**
1890
+ * Create the schema from the servers schema response
1891
+ * @param schemaResponse Response from the backend
1892
+ */
1893
+ setSchema(schemaResponse, localizedResource = {}) {
1894
+ // prepare a quick access object for the fields
1895
+ const propertiesQA = {};
1896
+ const orgTypeFields = [BaseObjectTypeField.MODIFIED_BY, BaseObjectTypeField.CREATED_BY];
1897
+ schemaResponse.propertyDefinition.forEach((p) => {
1898
+ p.classifications = p.classification;
1899
+ // TODO: Remove once schema supports organization classification for base params
1900
+ // map certain fields to organization type (fake it until you make it ;-)
1901
+ if (orgTypeFields.includes(p.id)) {
1902
+ p.classifications = [Classification.STRING_ORGANIZATION];
1903
+ }
1904
+ propertiesQA[p.id] = p;
1905
+ });
1906
+ // prepare a quick access object for object types (including secondary objects)
1907
+ const objectTypesQA = {};
1908
+ schemaResponse.typeFolderDefinition.forEach((ot) => {
1909
+ objectTypesQA[ot.id] = ot;
1910
+ });
1911
+ schemaResponse.typeDocumentDefinition.forEach((ot) => {
1912
+ objectTypesQA[ot.id] = ot;
1913
+ });
1914
+ schemaResponse.typeSecondaryDefinition.forEach((sot) => {
1915
+ objectTypesQA[sot.id] = sot;
1916
+ });
1917
+ const objectTypes = [
1918
+ // folder types
1919
+ ...schemaResponse.typeFolderDefinition.map((fd) => ({
1920
+ id: fd.id,
1921
+ description: fd.description,
1922
+ classification: fd.classification,
1923
+ baseId: fd.baseId,
1924
+ creatable: this.#isCreatable(fd.id),
1925
+ contentStreamAllowed: ContentStreamAllowed.NOT_ALLOWED,
1926
+ isFolder: true,
1927
+ secondaryObjectTypes: fd.secondaryObjectTypeId ? fd.secondaryObjectTypeId.map((t) => ({ id: t.value, static: t.static })) : [],
1928
+ fields: this.#resolveObjectTypeFields(fd, propertiesQA, objectTypesQA)
1929
+ // rawFields: this.resolveObjectTypeFields(fd, propertiesQA, objectTypesQA, true),
1930
+ })),
1931
+ // document types
1932
+ ...schemaResponse.typeDocumentDefinition.map((dd) => ({
1933
+ id: dd.id,
1934
+ description: dd.description,
1935
+ classification: dd.classification,
1936
+ baseId: dd.baseId,
1937
+ creatable: this.#isCreatable(dd.id),
1938
+ contentStreamAllowed: dd.contentStreamAllowed,
1939
+ isFolder: false,
1940
+ secondaryObjectTypes: dd.secondaryObjectTypeId ? dd.secondaryObjectTypeId.map((t) => ({ id: t.value, static: t.static })) : [],
1941
+ fields: this.#resolveObjectTypeFields(dd, propertiesQA, objectTypesQA)
1942
+ // rawFields: this.resolveObjectTypeFields(dd, propertiesQA, objectTypesQA, true),
1943
+ }))
1944
+ ];
1945
+ const secondaryObjectTypes = schemaResponse.typeSecondaryDefinition.map((std) => ({
1946
+ id: std.id,
1947
+ description: std.description,
1948
+ classification: std.classification,
1949
+ contentStreamAllowed: std.contentStreamAllowed,
1950
+ baseId: std.baseId,
1951
+ // TODO: Could a SOT be a folder too?
1952
+ isFolder: false,
1953
+ fields: this.#resolveObjectTypeFields(std, propertiesQA, objectTypesQA)
1954
+ }));
1955
+ this.system = {
1956
+ version: schemaResponse.version,
1957
+ lastModificationDate: schemaResponse.lastModificationDate,
1958
+ objectTypes,
1959
+ secondaryObjectTypes,
1960
+ i18n: localizedResource,
1961
+ allFields: propertiesQA
1962
+ };
1963
+ this.#appCache.setItem(this.#STORAGE_KEY, this.system).subscribe();
1964
+ this.#systemSource.next(this.system);
1965
+ }
1966
+ /**
1967
+ * Resolve all the fields for an object type. This also includes secondary object types and the fields inherited from
1968
+ * the base type (... and of course the base type (and its secondary object types) of the base type and so on)
1969
+ * @param schemaTypeDefinition object type definition from the native schema
1970
+ * @param propertiesQA Quick access object of all properties
1971
+ * @param objectTypesQA Quick access object of all object types
1972
+ * @param raw If set to 'true' only the properties of the object type itself will be returned (without SOTs)
1973
+ */
1974
+ #resolveObjectTypeFields(schemaTypeDefinition, propertiesQA, objectTypesQA) {
1975
+ const objectTypeFieldIDs = schemaTypeDefinition.propertyReference.map((pr) => pr.value);
1976
+ if (schemaTypeDefinition.secondaryObjectTypeId) {
1977
+ schemaTypeDefinition.secondaryObjectTypeId
1978
+ .filter((sot) => sot.static)
1979
+ .map((sot) => sot.value)
1980
+ .forEach((sotID) => objectTypesQA[sotID].propertyReference.forEach((pr) => objectTypeFieldIDs.push(pr.value)));
1981
+ }
1982
+ let fields = objectTypeFieldIDs.map((id) => ({
1983
+ ...propertiesQA[id],
1984
+ _internalType: this.getInternalFormElementType(propertiesQA[id].propertyType, propertiesQA[id].classifications)
1985
+ }));
1986
+ // also resolve properties of the base type
1987
+ if (schemaTypeDefinition.baseId !== schemaTypeDefinition.id && !!objectTypesQA[schemaTypeDefinition.baseId]) {
1988
+ fields = fields.concat(this.#resolveObjectTypeFields(objectTypesQA[schemaTypeDefinition.baseId], propertiesQA, objectTypesQA));
1989
+ }
1990
+ return fields;
1991
+ }
1992
+ #isCreatable(objectTypeId) {
1993
+ return ![SystemType.FOLDER, SystemType.DOCUMENT].includes(objectTypeId);
1994
+ }
1995
+ /**
1996
+ * Fetch a collection of form models.
1997
+ * @param objectTypeIDs Object type IDs to fetch form model for
1998
+ * @param situation Form situation
1999
+ * @returns Object where the object type id is key and the form model is the value
2000
+ */
2001
+ getObjectTypeForms(objectTypeIDs, situation) {
2002
+ return forkJoin(objectTypeIDs.map((o) => this.getObjectTypeForm(o, situation).pipe(catchError((e) => of(null)), map((res) => ({
2003
+ id: o,
2004
+ formModel: res
2005
+ }))))).pipe(map((res) => {
2006
+ const resMap = {};
2007
+ res.filter((r) => this.#formHasElements(r.formModel)).forEach((r) => (resMap[r.id] = r.formModel));
2008
+ return resMap;
2009
+ }));
2010
+ }
2011
+ /**
2012
+ * Get the form model of an object type.
2013
+ *
2014
+ * @param objectTypeId ID of the object type to fetch the form for
2015
+ * @param situation The form situation to be fetched
2016
+ * @returns Form model
2017
+ */
2018
+ getObjectTypeForm(objectTypeId, situation) {
2019
+ return this.#backend.get(Utils.buildUri(`/dms/forms/${objectTypeId}`, { situation }));
2020
+ }
2021
+ /**
2022
+ * Check whether or not the model has at least one form element. Recursive.
2023
+ * @param element Form element to check child elements for
2024
+ */
2025
+ #formHasElements(element) {
2026
+ let hasElement = false;
2027
+ element.elements?.forEach((e) => {
2028
+ if (!['o2mGroup', 'o2mGroupStack'].includes(e.type)) {
2029
+ hasElement = true;
2030
+ }
2031
+ else if (!hasElement) {
2032
+ hasElement = this.#formHasElements(e);
2033
+ }
2034
+ });
2035
+ return hasElement;
2036
+ }
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;
2069
+ }
2070
+ }
2071
+ getObjectTypeField(id) {
2072
+ const f = this.system?.allFields[id];
2073
+ return f ? { ...f, _internalType: this.getInternalFormElementType(f.propertyType, f.classifications) } : undefined;
2074
+ }
2075
+ /**
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)
2085
+ */
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');
2118
+ }
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 })));
2126
+ }
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' }); }
2129
+ }
2130
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SystemService, decorators: [{
2131
+ type: Injectable,
2132
+ args: [{
2133
+ providedIn: 'root'
2134
+ }]
2135
+ }] });
2136
+
2137
+ /**
2138
+ * Service providing user account configurations.
2139
+ */
2140
+ class UserService {
2141
+ // #GLOBAL_SETTINGS = '/users/globalsettings/';
2142
+ #USERS_SETTINGS;
2143
+ #DEFAULT_SETTINGS;
2144
+ #SETTINGS_SECTION_OBJECTCONFIG;
2145
+ #user;
2146
+ #userSource;
2147
+ /**
2148
+ * @ignore
2149
+ */
2150
+ constructor(backend, translate, logger, system, oidc, eventService, config) {
2151
+ this.backend = backend;
2152
+ this.translate = translate;
2153
+ this.logger = logger;
2154
+ this.system = system;
2155
+ this.oidc = oidc;
2156
+ this.eventService = eventService;
2157
+ this.config = config;
2158
+ // #GLOBAL_SETTINGS = '/users/globalsettings/';
2159
+ this.#USERS_SETTINGS = '/users/settings/';
2160
+ this.#DEFAULT_SETTINGS = '/users/settings';
2161
+ this.#SETTINGS_SECTION_OBJECTCONFIG = 'object-config';
2162
+ this.#userSource = new BehaviorSubject(this.#user);
2163
+ this.user$ = this.#userSource.asObservable();
2164
+ this.globalSettings = new Map();
2165
+ this.canCreateObjects = false;
2166
+ }
2167
+ getUiDirection(iso) {
2168
+ // languages that are read right to left
2169
+ const rtlLanguages = ['ar', 'arc', 'dv', 'fa', 'ha', 'he', 'khw', 'ks', 'ku', 'ps', 'ur', 'yi'];
2170
+ return rtlLanguages.indexOf(iso) === -1 ? Direction.LTR : Direction.RTL;
2171
+ }
2172
+ /**
2173
+ * Set a new current user
2174
+ * @param user The user to be set as current user
2175
+ */
2176
+ setCurrentUser(user) {
2177
+ this.#user = user;
2178
+ this.changeClientLocale('', false);
2179
+ this.#userSource.next(this.#user);
2180
+ }
2181
+ getCurrentUser() {
2182
+ return this.#user;
2183
+ }
2184
+ get hasAdminRole() {
2185
+ return this.#user?.authorities?.includes(AdministrationRoles.ADMIN) || false;
2186
+ }
2187
+ get hasSystemRole() {
2188
+ return this.#user?.authorities?.includes(AdministrationRoles.SYSTEM) || false;
2189
+ }
2190
+ get hasAdministrationRoles() {
2191
+ return this.hasAdminRole || this.hasSystemRole;
2192
+ }
2193
+ get hasManageSettingsRole() {
2194
+ const customRole = this.config.get('core.permissions.manageSettingsRole');
2195
+ const manageSettingsRole = customRole || AdministrationRoles.MANAGE_SETTINGS;
2196
+ return this.#user?.authorities?.includes(manageSettingsRole) || false;
2197
+ }
2198
+ get isAdvancedUser() {
2199
+ const customRole = this.config.get('core.permissions.advancedUserRole');
2200
+ const advancedUserRole = customRole || AdministrationRoles.MANAGE_SETTINGS;
2201
+ return this.#user?.authorities?.includes(advancedUserRole) || false;
2202
+ }
2203
+ get isRetentionManager() {
2204
+ const customRole = this.config.get('core.permissions.retentionManagerRole');
2205
+ const retenetionManagerRole = customRole || AdministrationRoles.MANAGE_SETTINGS;
2206
+ return this.#user?.authorities?.includes(retenetionManagerRole) || false;
2207
+ }
2208
+ /**
2209
+ * Change the users client locale
2210
+ * @param iso ISO locale string to be set as new client locale
2211
+ */
2212
+ changeClientLocale(iso, persist = true) {
2213
+ if (this.#user) {
2214
+ const languages = this.config.getClientLocales().map((lang) => lang.iso);
2215
+ iso = iso || this.#user.getClientLocale(this.config.getDefaultClientLocale());
2216
+ if (!languages.includes(iso)) {
2217
+ iso = this.config.getDefaultClientLocale();
2218
+ }
2219
+ this.logger.debug("Changed client locale to '" + iso + "'");
2220
+ this.backend.setHeader('Accept-Language', iso);
2221
+ this.#user.uiDirection = this.getUiDirection(iso);
2222
+ this.#user.userSettings.locale = iso;
2223
+ if (this.translate.currentLang !== iso || this.system.authData?.language !== iso) {
2224
+ const ob = persist
2225
+ ? forkJoin([
2226
+ this.translate.use(iso),
2227
+ this.system.updateLocalizations(iso),
2228
+ this.saveUserSettings(this.#user.userSettings).pipe(tap(() => {
2229
+ // this.#userSource.next(this.#user);
2230
+ this.logger.debug('Loading system definitions i18n resources for new locale.');
2231
+ }))
2232
+ ])
2233
+ : this.translate.use(iso);
2234
+ ob.subscribe(() => this.eventService.trigger(YuvEventType.CLIENT_LOCALE_CHANGED, iso));
2235
+ }
2236
+ }
2237
+ }
2238
+ saveUserSettings(settings) {
2239
+ if (this.#user) {
2240
+ console.log(this.#user.userSettings);
2241
+ this.#user.userSettings = { ...this.#user.userSettings, ...settings };
2242
+ return this.backend.post(this.#DEFAULT_SETTINGS, this.#user.userSettings).pipe(tap(() => this.#userSource.next(this.#user)));
2243
+ }
2244
+ else
2245
+ return of(null);
2246
+ }
2247
+ fetchUserSettings() {
2248
+ return this.backend.get('/dms/permissions').pipe(catchError((e) => of(undefined)), switchMap((res) => {
2249
+ this.setUserPermissions(res);
2250
+ return this.backend.get(this.#DEFAULT_SETTINGS);
2251
+ }));
2252
+ }
2253
+ setUserPermissions(res) {
2254
+ this.userPermissions = {
2255
+ create: this.mapPermissions('CREATE', res),
2256
+ write: this.mapPermissions('WRITE', res),
2257
+ read: this.mapPermissions('READ', res),
2258
+ delete: this.mapPermissions('DELETE', res)
2259
+ };
2260
+ const sp = {
2261
+ createableObjectTypes: [
2262
+ ...this.userPermissions.create.folderTypes,
2263
+ ...this.userPermissions.create.objectTypes,
2264
+ ...this.userPermissions.create.secondaryObjectTypes
2265
+ ],
2266
+ searchableObjectTypes: [
2267
+ ...this.userPermissions.read.folderTypes,
2268
+ ...this.userPermissions.read.objectTypes,
2269
+ ...this.userPermissions.read.secondaryObjectTypes
2270
+ ]
2271
+ };
2272
+ this.system.setPermissions(sp);
2273
+ this.canCreateObjects = sp.createableObjectTypes.length > 0;
2274
+ }
2275
+ mapPermissions(section, apiResponse) {
2276
+ const res = apiResponse[section] || {};
2277
+ return {
2278
+ folderTypes: res['folderTypeIds'] || [],
2279
+ objectTypes: res['objectTypeIds'] || [],
2280
+ secondaryObjectTypes: res['secondaryObjectTypeIds'] || []
2281
+ };
2282
+ }
2283
+ /**
2284
+ * Search for a user based on a search term
2285
+ * @param term Search term
2286
+ * @param excludeMe whether or not to exclude myself from the result list
2287
+ * @param roles narrow down the search results by certain roles
2288
+ */
2289
+ queryUser(term, excludeMe, roles) {
2290
+ let params = new HttpParams().set('search', term).set('excludeMe', `${!!excludeMe}`);
2291
+ roles?.length && roles.map((r) => (params = params.append(`roles`, r)));
2292
+ return this.backend.get(`/idm/users?${params}`).pipe(map((users) => (!users ? [] : users.map((u) => new YuvUser(u)))));
2293
+ }
2294
+ getUserById(id) {
2295
+ return this.backend.get(`/idm/users/${id}`).pipe(map((user) => new YuvUser(user, this.#user.userSettings)));
2296
+ }
2297
+ logout(redirRoute) {
2298
+ if (this.backend.authUsesOpenIdConnect()) {
2299
+ this.oidc.logout();
2300
+ }
2301
+ else {
2302
+ const redir = redirRoute ? `?redir=${redirRoute}` : '';
2303
+ window.location.href = `${this.backend.getApiBase('logout')}${redir}`;
2304
+ }
2305
+ }
2306
+ getSettings(section) {
2307
+ return this.#user ? this.backend.get(this.#USERS_SETTINGS + encodeURIComponent(section)) : of(null);
2308
+ }
2309
+ saveObjectConfig(objectConfigs) {
2310
+ return this.backend.post(this.#USERS_SETTINGS + encodeURIComponent(this.#SETTINGS_SECTION_OBJECTCONFIG), objectConfigs);
2311
+ }
2312
+ loadObjectConfig() {
2313
+ return this.getSettings(this.#SETTINGS_SECTION_OBJECTCONFIG).pipe(catchError(() => of(undefined)));
2314
+ }
2315
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: UserService, deps: [{ token: BackendService }, { token: i1$1.TranslateService }, { token: Logger }, { token: SystemService }, { token: OidcService }, { token: EventService }, { token: ConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
2316
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: UserService, providedIn: 'root' }); }
2317
+ }
2318
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: UserService, decorators: [{
2319
+ type: Injectable,
2320
+ args: [{
2321
+ providedIn: 'root'
2322
+ }]
2323
+ }], ctorParameters: () => [{ type: BackendService }, { type: i1$1.TranslateService }, { type: Logger }, { type: SystemService }, { type: OidcService }, { type: EventService }, { type: ConfigService }] });
2324
+
2325
+ /**
2326
+ * Service providing access to the systems audit entries. Audits can be seen as the history of
2327
+ * an object. Actions perormed on an object (eg. read, write, delete, ...) will be recorded during
2328
+ * the objects lifecycle. Audits are provided based on a users permissions. Beside the audit entries
2329
+ * visible to regular users there are more technical ones that will only be shown to users that
2330
+ * have administrative role.
2331
+ */
2332
+ class AuditService {
2333
+ constructor() {
2334
+ this.#searchService = inject(SearchService);
2335
+ this.#userService = inject(UserService);
2336
+ // default number of items to be fetched
2337
+ this.DEFAULT_RES_SIZE = 20;
2338
+ // audit action codes that should be visible to regular users
2339
+ this.userAuditActions = [
2340
+ 100, // metadata created
2341
+ 101, // metadata created (with content)
2342
+ 110, // tag created
2343
+ 201, // content deleted
2344
+ 210, // tag deleted
2345
+ 300, // metadata updated
2346
+ 301, // content updated
2347
+ 302, // metadata and content updated
2348
+ 303, // content moved
2349
+ 310, // tag updated
2350
+ 325, // object restored form version
2351
+ 340, // object moved
2352
+ 10000 // custom audit entries
2353
+ ];
2354
+ // audit action codes that should be visible to admin users
2355
+ this.adminAuditActions = [
2356
+ 202, // marked for delete
2357
+ 220, // version deleted
2358
+ 400, // content read
2359
+ 401, // metadata read
2360
+ 402, // rendition read (text)
2361
+ 403, // rendition read (pdf)
2362
+ 404 // rendition read (thumbnail)
2363
+ ];
2364
+ }
2365
+ #searchService;
2366
+ #userService;
2367
+ /**
2368
+ * Get audit entries of a dms object
2369
+ */
2370
+ getAuditEntries(id, options = {}) {
2371
+ const auditActions = this.getAuditActions(!!options.allActions, options?.skipActions);
2372
+ const q = {
2373
+ size: this.DEFAULT_RES_SIZE,
2374
+ types: [SystemType.AUDIT],
2375
+ filters: [
2376
+ {
2377
+ f: AuditField.REFERRED_OBJECT_ID,
2378
+ o: Operator.EQUAL,
2379
+ v1: id
2380
+ },
2381
+ {
2382
+ f: AuditField.ACTION,
2383
+ o: Operator.IN,
2384
+ v1: auditActions
2385
+ }
2386
+ ],
2387
+ sort: [
2388
+ {
2389
+ field: AuditField.CREATION_DATE,
2390
+ order: 'desc'
2391
+ }
2392
+ ]
2393
+ };
2394
+ return this.#fetchAudits(q);
2395
+ }
2396
+ /**
2397
+ * Get an array of action codes that are provided by the service. Based on
2398
+ * whether or not the user has admin permissions you'll get a different
2399
+ * set of actions.
2400
+ * @param skipActions codes of actions that should not be fetched
2401
+ */
2402
+ getAuditActions(allActions, skipActions) {
2403
+ const actions = allActions || this.#userService.isAdvancedUser ? [...this.userAuditActions, ...this.adminAuditActions] : this.userAuditActions;
2404
+ return actions.filter((a) => !skipActions || !skipActions.includes(a));
2405
+ }
2406
+ /**
2407
+ * Get a certain page for a former audits query.
2408
+ * @param auditsResult The result object of a former audits query
2409
+ * @param page The page to load
2410
+ */
2411
+ getPage(auditsResult, page) {
2412
+ const q = auditsResult.query;
2413
+ q.from = (page - 1) * (q.size || this.DEFAULT_RES_SIZE);
2414
+ return this.#fetchAudits(q);
2415
+ }
2416
+ #fetchAudits(q) {
2417
+ return this.#searchService.searchRaw(q).pipe(map((res) => ({
2418
+ query: q,
2419
+ items: res.objects.map((o) => ({
2420
+ action: o.properties[AuditField.ACTION].value,
2421
+ actionGroup: this.#getActionGroup(o.properties[AuditField.ACTION].value),
2422
+ detail: o.properties[AuditField.DETAIL].value,
2423
+ subaction: o.properties[AuditField.SUBACTION] ? o.properties[AuditField.SUBACTION].value : null,
2424
+ version: o.properties[AuditField.VERSION].value,
2425
+ creationDate: o.properties[AuditField.CREATION_DATE].value,
2426
+ createdBy: {
2427
+ id: o.properties[AuditField.CREATED_BY].value,
2428
+ title: o.properties[AuditField.CREATED_BY].title
2429
+ }
2430
+ })),
2431
+ hasMoreItems: res.hasMoreItems,
2432
+ page: !q.from ? 1 : q.from / q.size + 1
2433
+ })));
2434
+ }
2435
+ #getActionGroup(action) {
2436
+ try {
2437
+ return parseInt(`${action}`.substr(0, 1));
2438
+ }
2439
+ catch {
2440
+ return -1;
2441
+ }
2442
+ }
2443
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AuditService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2444
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AuditService, providedIn: 'root' }); }
2445
+ }
2446
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AuditService, decorators: [{
2447
+ type: Injectable,
2448
+ args: [{
2449
+ providedIn: 'root'
2450
+ }]
2451
+ }] });
2452
+
2453
+ var LoginStateName;
2454
+ (function (LoginStateName) {
2455
+ LoginStateName["STATE_LOGIN_URI"] = "login.uri";
2456
+ LoginStateName["STATE_DONE"] = "login.done";
2457
+ LoginStateName["STATE_CANCELED"] = "login.canceled";
2458
+ })(LoginStateName || (LoginStateName = {}));
2459
+
2460
+ /**
2461
+ * Service managing the configuarions for object types.
2462
+ * Configuration means that you can pick certain fields
2463
+ * of an object type and assign them to a config object.
2464
+ */
2465
+ class ObjectConfigService {
2466
+ constructor() {
2467
+ this.#system = inject(SystemService);
2468
+ this.#user = inject(UserService);
2469
+ this.OBJECT_CONFIG_STORAGE_KEY = 'yuv.framework.object-config';
2470
+ this.#objectConfigsSource = new ReplaySubject();
2471
+ this.#objectConfigs$ = this.#objectConfigsSource.asObservable();
2472
+ this.#defaultObjectConfigs = {};
2473
+ this.#registeredDefaultObjectConfigs = {
2474
+ main: {},
2475
+ buckets: []
2476
+ };
2477
+ this.#objectConfigs = {
2478
+ main: {},
2479
+ buckets: []
2480
+ };
2481
+ }
2482
+ #system;
2483
+ #user;
2484
+ #objectConfigsSource;
2485
+ #objectConfigs$;
2486
+ #defaultObjectConfigs;
2487
+ #registeredDefaultObjectConfigs;
2488
+ #objectConfigs;
2489
+ // called on core init (auth.service -> initApp)
2490
+ init() {
2491
+ console.log('ObjectConfigService.init', this.#user.getCurrentUser().userSettings);
2492
+ return this.#user.loadObjectConfig().pipe(tap$1((res) => {
2493
+ this.#getDefaultObjectConfig();
2494
+ this.#objectConfigs = res || {
2495
+ main: {},
2496
+ buckets: []
2497
+ };
2498
+ this.#objectConfigsSource.next(this.#objectConfigs);
2499
+ }));
2500
+ }
2501
+ getObjectConfigs$(bucket, includeDefaults) {
2502
+ return this.#objectConfigs$.pipe(map$1((soc) => {
2503
+ let ocr = soc.main;
2504
+ const defaults = { ...this.#defaultObjectConfigs, ...this.#getRegisteredDefaults(bucket) };
2505
+ if (bucket) {
2506
+ const tileBucket = soc.buckets.find((b) => b.id === bucket);
2507
+ if (tileBucket)
2508
+ ocr = tileBucket.configs;
2509
+ }
2510
+ return includeDefaults
2511
+ ? {
2512
+ ...defaults,
2513
+ ...ocr
2514
+ }
2515
+ : { ...ocr };
2516
+ }));
2517
+ }
2518
+ /**
2519
+ * Register default object configs. Apps can pre-define how their
2520
+ * objects should be rendered.
2521
+ * @param bucket Name of a bucket to bind configs to (usually the ID of the app) to
2522
+ * separate the configs from other apps. If not provided configs will be saved for
2523
+ * the global scope
2524
+ */
2525
+ registerDefaults(configs, bucket) {
2526
+ if (bucket) {
2527
+ // does bucket exist?
2528
+ const tileBucketIdx = this.#registeredDefaultObjectConfigs.buckets.findIndex((b) => b.id === bucket);
2529
+ if (tileBucketIdx !== -1) {
2530
+ this.#registeredDefaultObjectConfigs.buckets[tileBucketIdx].configs = {
2531
+ ...this.#registeredDefaultObjectConfigs.buckets[tileBucketIdx].configs,
2532
+ ...configs
2533
+ };
2534
+ }
2535
+ else {
2536
+ this.#registeredDefaultObjectConfigs.buckets.push({
2537
+ id: bucket,
2538
+ configs
2539
+ });
2540
+ }
2541
+ }
2542
+ else
2543
+ this.#registeredDefaultObjectConfigs.main = { ...this.#registeredDefaultObjectConfigs.main, ...configs };
2544
+ }
2545
+ unregisterDefaults(configs, bucket) {
2546
+ if (bucket) {
2547
+ // does bucket exist?
2548
+ const tileBucketIdx = this.#registeredDefaultObjectConfigs.buckets.findIndex((b) => b.id === bucket);
2549
+ if (tileBucketIdx !== -1) {
2550
+ this.#registeredDefaultObjectConfigs.buckets.splice(tileBucketIdx, 1);
2551
+ }
2552
+ }
2553
+ else {
2554
+ Object.keys(configs).forEach((key) => {
2555
+ delete this.#registeredDefaultObjectConfigs.main[key];
2556
+ });
2557
+ }
2558
+ }
2559
+ #getRegisteredDefaults(bucket) {
2560
+ if (bucket) {
2561
+ const defaultTileBucket = this.#registeredDefaultObjectConfigs.buckets.find((b) => b.id === bucket);
2562
+ return defaultTileBucket?.configs || {};
2563
+ }
2564
+ else
2565
+ return this.#registeredDefaultObjectConfigs.main;
2566
+ }
2567
+ /**
2568
+ * Get object config for an object type.
2569
+ * @param objectTypeId ID of the object type to get the config for
2570
+ * @param bucket Optional bucket ID to fetch the config from. Buckets
2571
+ * define separated areas to store/receive those configs. This way
2572
+ * components/apps can store different object configs than the ones
2573
+ * used accross the whole client application.
2574
+ */
2575
+ getObjectConfig(type, bucket) {
2576
+ const b = bucket ? this.#objectConfigs.buckets.find((b) => b.id === bucket) : undefined;
2577
+ const otr = b ? b.configs : this.#objectConfigs.main;
2578
+ const oc = otr[type.id];
2579
+ return oc || this.#getRegisteredDefaults(bucket)[type.id];
2580
+ }
2581
+ saveObjectConfig(type, config, bucket) {
2582
+ if (!this.#objectConfigs)
2583
+ this.#objectConfigs = {
2584
+ main: {},
2585
+ buckets: []
2586
+ };
2587
+ if (bucket) {
2588
+ // does bucket exist?
2589
+ const tileBucketIdx = this.#objectConfigs.buckets.findIndex((b) => b.id === bucket);
2590
+ if (tileBucketIdx !== -1) {
2591
+ this.#objectConfigs.buckets[tileBucketIdx].configs[type.id] = config;
2592
+ }
2593
+ else {
2594
+ const configs = {};
2595
+ configs[type.id] = config;
2596
+ this.#objectConfigs.buckets.push({
2597
+ id: bucket,
2598
+ configs
2599
+ });
2600
+ }
2601
+ }
2602
+ else {
2603
+ this.#objectConfigs.main[type.id] = config;
2604
+ }
2605
+ this.#objectConfigsSource.next(this.#objectConfigs);
2606
+ return this.#user.saveObjectConfig(this.#objectConfigs);
2607
+ }
2608
+ getDefaultConfig(objectTypeID) {
2609
+ return this.#defaultObjectConfigs[objectTypeID];
2610
+ }
2611
+ getResolvedObjectConfig(data, type, bucket, includeDefaults) {
2612
+ const defaultCfg = this.#defaultObjectConfigs[data[BaseObjectTypeField.OBJECT_TYPE_ID]];
2613
+ let oc = this.getObjectConfig(type, bucket) || defaultCfg;
2614
+ if (includeDefaults)
2615
+ oc = { ...defaultCfg, ...oc };
2616
+ const res = {
2617
+ id: data[BaseObjectTypeField.OBJECT_ID],
2618
+ objectTypeId: data[BaseObjectTypeField.OBJECT_TYPE_ID],
2619
+ actions: oc.actions,
2620
+ badges: oc.badges,
2621
+ instanceData: data
2622
+ };
2623
+ if (oc.title)
2624
+ res.title = {
2625
+ propertyName: oc.title.propertyName,
2626
+ value: data[oc.title.propertyName]
2627
+ };
2628
+ if (oc.description)
2629
+ res.description = {
2630
+ propertyName: oc.description.propertyName,
2631
+ value: data[oc.description.propertyName]
2632
+ };
2633
+ if (oc.icon)
2634
+ res.icon = {
2635
+ propertyName: 'custom',
2636
+ value: oc.icon.svg
2637
+ };
2638
+ if (oc.meta)
2639
+ res.meta = {
2640
+ propertyName: oc.meta.propertyName,
2641
+ value: data[oc.meta.propertyName]
2642
+ };
2643
+ if (oc.aside)
2644
+ res.aside = {
2645
+ propertyName: oc.aside.propertyName,
2646
+ value: data[oc.aside.propertyName]
2647
+ };
2648
+ return res;
2649
+ }
2650
+ /**
2651
+ * Load default/fallbac configs based on the object types and
2652
+ * their first properties
2653
+ */
2654
+ #getDefaultObjectConfig() {
2655
+ this.#system.getObjectTypes(true).forEach((ot) => {
2656
+ this.#defaultObjectConfigs[ot.id] = {
2657
+ objectTypeId: ot.id,
2658
+ title: this.#toObjectProperty(ot.fields[0]),
2659
+ description: this.#toObjectProperty(ot.fields[1]),
2660
+ meta: this.#toObjectProperty(ot.fields[2]),
2661
+ aside: this.#toObjectProperty(ot.fields[3])
2662
+ };
2663
+ });
2664
+ }
2665
+ #toObjectProperty(field) {
2666
+ return field
2667
+ ? {
2668
+ label: this.#system.getLocalizedLabel(field.id),
2669
+ propertyName: field.id
2670
+ }
2671
+ : undefined;
2672
+ }
2673
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ObjectConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2674
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ObjectConfigService, providedIn: 'root' }); }
2675
+ }
2676
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ObjectConfigService, decorators: [{
2677
+ type: Injectable,
2678
+ args: [{
2679
+ providedIn: 'root'
2680
+ }]
2681
+ }] });
2682
+
2683
+ /**
2684
+ * Service handling authentication related issues.
2685
+ */
2686
+ class AuthService {
2687
+ #eventService;
2688
+ #userService;
2689
+ #objectConfigService;
2690
+ #appCache;
2691
+ #systemService;
2692
+ #backend;
2693
+ #INITAL_REQUEST_STORAGE_KEY;
2694
+ #authenticated;
2695
+ #authSource;
2696
+ #authData;
2697
+ constructor(coreConfig) {
2698
+ this.coreConfig = coreConfig;
2699
+ this.#eventService = inject(EventService);
2700
+ this.#userService = inject(UserService);
2701
+ this.#objectConfigService = inject(ObjectConfigService);
2702
+ this.#appCache = inject(AppCacheService);
2703
+ this.#systemService = inject(SystemService);
2704
+ this.#backend = inject(BackendService);
2705
+ this.#INITAL_REQUEST_STORAGE_KEY = 'yuv.core.auth.initialrequest';
2706
+ this.USER_FETCH_URI = '/idm/whoami';
2707
+ this.#authenticated = false;
2708
+ this.#authSource = new BehaviorSubject(false);
2709
+ this.authenticated$ = this.#authSource.asObservable();
2710
+ }
2711
+ isLoggedIn() {
2712
+ return this.#authenticated;
2713
+ }
2714
+ /**
2715
+ * Called while app/core is initialized (APP_INITIALIZER)
2716
+ * @ignore
2717
+ */
2718
+ initUser() {
2719
+ return this.fetchUser();
2720
+ }
2721
+ /**
2722
+ * Get the current tenant or the previous one persisted locally
2723
+ */
2724
+ getTenant() {
2725
+ return this.#authData?.tenant;
2726
+ }
2727
+ /**
2728
+ * Fetch information about the user currently logged in
2729
+ */
2730
+ fetchUser() {
2731
+ return this.#backend.get(this.USER_FETCH_URI).pipe(tap(() => {
2732
+ this.#authenticated = true;
2733
+ this.#authSource.next(this.#authenticated);
2734
+ }), switchMap((userJson) => this.#initApp(userJson)));
2735
+ }
2736
+ /**
2737
+ * Logs out the current user.
2738
+ */
2739
+ logout() {
2740
+ this.#authenticated = false;
2741
+ this.#authSource.next(this.#authenticated);
2742
+ this.#eventService.trigger(YuvEventType.LOGOUT);
2743
+ }
2744
+ // called on core init
2745
+ setInitialRequestUri() {
2746
+ const ignore = ['/', '/index.html'];
2747
+ let uri = `${location.pathname}${location.search}`.replace(Utils.getBaseHref(), '');
2748
+ uri = !uri.startsWith('/') ? `/${uri}` : uri;
2749
+ if (!ignore.includes(uri)) {
2750
+ this.#appCache
2751
+ .setItem(this.#INITAL_REQUEST_STORAGE_KEY, {
2752
+ uri: uri,
2753
+ timestamp: Date.now()
2754
+ })
2755
+ .subscribe();
2756
+ }
2757
+ }
2758
+ /**
2759
+ * Get the URL that entered the app. May be a deep link that could then be
2760
+ * picked up again after user has been authenticated.
2761
+ */
2762
+ getInitialRequestUri() {
2763
+ return this.#appCache.getItem(this.#INITAL_REQUEST_STORAGE_KEY);
2764
+ }
2765
+ resetInitialRequestUri() {
2766
+ return this.#appCache.removeItem(this.#INITAL_REQUEST_STORAGE_KEY);
2767
+ }
2768
+ /**
2769
+ * Initialize/setup the application for a given user. This involves fetching
2770
+ * settings and schema information.
2771
+ * @param userJson Data retrieved from the backend
2772
+ */
2773
+ #initApp(userJson) {
2774
+ return this.#userService.fetchUserSettings().pipe(switchMap((userSettings) => {
2775
+ const currentUser = new YuvUser(userJson, userSettings);
2776
+ this.#userService.setCurrentUser(currentUser);
2777
+ this.#authData = {
2778
+ tenant: currentUser.tenant,
2779
+ language: currentUser.getClientLocale()
2780
+ };
2781
+ return this.#systemService.getSystemDefinition(this.#authData).pipe(switchMap(() => this.#objectConfigService.init()), map(() => currentUser));
2782
+ }));
2783
+ }
2784
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AuthService, deps: [{ token: CORE_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable }); }
2785
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AuthService, providedIn: 'root' }); }
2786
+ }
2787
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AuthService, decorators: [{
2788
+ type: Injectable,
2789
+ args: [{
2790
+ providedIn: 'root'
2791
+ }]
2792
+ }], ctorParameters: () => [{ type: CoreConfig, decorators: [{
2793
+ type: Inject,
2794
+ args: [CORE_CONFIG]
2795
+ }] }] });
2796
+
2797
+ const ProcessAction = {
2798
+ complete: 'complete',
2799
+ claim: 'claim',
2800
+ delegate: 'delegate',
2801
+ resolve: 'resolve',
2802
+ save: 'save'
2803
+ };
2804
+
2805
+ class BpmService {
2806
+ #backend = inject(BackendService);
2807
+ startProcess(payload) {
2808
+ return this.#backend.post('/bpm/processes', payload, ApiBase.apiWeb);
2809
+ }
2810
+ /**
2811
+ * Finsihes a task.
2812
+ * @param taskId ID of the taks to finish
2813
+ * @param payload Data to be send with the complete request (may contain attachments, a new subject or variables)
2814
+ */
2815
+ completeTask(taskId, payload) {
2816
+ return this.#putTask(taskId, ProcessAction.complete, payload || {});
2817
+ }
2818
+ updateTask(taskId, payload) {
2819
+ return this.#putTask(taskId, ProcessAction.save, payload || {});
2820
+ }
2821
+ //TODO: replace with propper service call
2822
+ getProcessPoll() {
2823
+ const random = Math.random();
2824
+ console.log('getProcessPoll: ', { random });
2825
+ return of([{ title: `task title ${random}`, duedate: new Date() }]);
2826
+ }
2827
+ getProcessInstance(processDefinitionKey, options) {
2828
+ return this.#backend
2829
+ .get(`/bpm/processes${Utils.optionsToURLParams({ ...options, processDefinitionKey })}`, ApiBase.apiWeb)
2830
+ .pipe(map$1(({ objects }) => objects[0]));
2831
+ }
2832
+ deleteProcess(processInstanceId) {
2833
+ return this.#backend.delete(`/bpm/processes/${processInstanceId}`, ApiBase.apiWeb);
2834
+ }
2835
+ #putTask(taskId, action, payload) {
2836
+ const pl = { ...payload, action: action };
2837
+ return this.#backend.put(`/bpm/tasks/${taskId}`, pl, ApiBase.apiWeb);
2838
+ }
2839
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BpmService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2840
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BpmService, providedIn: 'root' }); }
2841
+ }
2842
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BpmService, decorators: [{
2843
+ type: Injectable,
2844
+ args: [{
2845
+ providedIn: 'root'
2846
+ }]
2847
+ }] });
2848
+
2849
+ class CatalogService {
2850
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CatalogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2851
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CatalogService, providedIn: 'root' }); }
2852
+ }
2853
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CatalogService, decorators: [{
2854
+ type: Injectable,
2855
+ args: [{
2856
+ providedIn: 'root'
2857
+ }]
2858
+ }] });
2859
+
2860
+ class ClipboardService {
2861
+ #emptyClipboard = {
2862
+ buckets: undefined,
2863
+ main: undefined
2864
+ };
2865
+ #clipboard = structuredClone(this.#emptyClipboard);
2866
+ #clipboardSource = new ReplaySubject();
2867
+ #clipboard$ = this.#clipboardSource.asObservable();
2868
+ #pasteEvents = merge(fromEvent(window, 'keydown').pipe(filter$1((event) => event.ctrlKey && event.code === 'KeyV')), fromEvent(window, 'paste').pipe(filter$1((event) => !!event.clipboardData && event.clipboardData.files.length > 0)));
2869
+ clipboard(bucket) {
2870
+ return toSignal(this.clipboard$(bucket));
2871
+ }
2872
+ clipboard$(bucket) {
2873
+ return this.#clipboard$.pipe(map$1((cs) => {
2874
+ if (bucket) {
2875
+ return cs.buckets ? cs.buckets[bucket] : undefined;
2876
+ }
2877
+ else
2878
+ return cs.main;
2879
+ }));
2880
+ }
2881
+ paste$(bucket) {
2882
+ return this.#pasteEvents.pipe(map$1((e) => {
2883
+ let cd;
2884
+ if (e instanceof ClipboardEvent) {
2885
+ const fileList = e.clipboardData.files;
2886
+ const files = [];
2887
+ for (let i = 0; i < fileList.length; i++) {
2888
+ files.push(fileList.item(i));
2889
+ }
2890
+ cd = files.length
2891
+ ? {
2892
+ files
2893
+ }
2894
+ : undefined;
2895
+ }
2896
+ else {
2897
+ cd = bucket ? (this.#clipboard.buckets ? this.#clipboard.buckets[bucket] : undefined) : this.#clipboard.main;
2898
+ }
2899
+ return cd;
2900
+ }), filter$1((cd) => cd !== undefined && (cd.files || cd.objects)), map$1((cd) => cd));
2901
+ }
2902
+ getClipboardData(bucket) {
2903
+ if (bucket) {
2904
+ return this.#clipboard.buckets ? this.#clipboard.buckets[bucket] : undefined;
2905
+ }
2906
+ else
2907
+ return this.#clipboard.main;
2908
+ }
2909
+ /**
2910
+ * Add objects to the clipboard
2911
+ * @param bucket Buckets are ways to separate data from the global scope.
2912
+ * If you have an app that would like to have a separate section in the clipboard
2913
+ * you'll use a unique bucket to store your stuff. When observing chages to the
2914
+ * clipboard you couls as well provide the bucket and you will only get
2915
+ */
2916
+ addObjects(objects, mode, bucket) {
2917
+ const cd = { mode, objects };
2918
+ if (bucket) {
2919
+ if (!this.#clipboard.buckets)
2920
+ this.#clipboard.buckets = {};
2921
+ this.#clipboard.buckets[bucket] = cd;
2922
+ }
2923
+ else
2924
+ this.#clipboard.main = cd;
2925
+ this.#clipboardSource.next(this.#clipboard);
2926
+ }
2927
+ clear(bucket) {
2928
+ if (bucket && this.#clipboard.buckets) {
2929
+ delete this.#clipboard.buckets[bucket];
2930
+ }
2931
+ else {
2932
+ this.#clipboard = structuredClone(this.#emptyClipboard);
2933
+ }
2934
+ this.#clipboardSource.next(this.#clipboard);
2935
+ }
2936
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ClipboardService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2937
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ClipboardService, providedIn: 'root' }); }
2938
+ }
2939
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ClipboardService, decorators: [{
2940
+ type: Injectable,
2941
+ args: [{
2942
+ providedIn: 'root'
2943
+ }]
2944
+ }] });
2945
+
2946
+ /**
2947
+ * This service is used for connecting and initializing in the client
2948
+ */
2949
+ class ConnectionService {
2950
+ /**
2951
+ * @ignore
2952
+ */
2953
+ constructor() {
2954
+ this.currentState = {
2955
+ isOnline: window.navigator.onLine
2956
+ };
2957
+ this.connectionStateSource = new ReplaySubject();
2958
+ this.connection$ = this.connectionStateSource.asObservable();
2959
+ this.connectionStateSource.next(this.currentState);
2960
+ fromEvent(window, 'online').subscribe(() => {
2961
+ this.currentState.isOnline = true;
2962
+ this.connectionStateSource.next(this.currentState);
2963
+ });
2964
+ fromEvent(window, 'offline').subscribe(() => {
2965
+ this.currentState.isOnline = false;
2966
+ this.connectionStateSource.next(this.currentState);
2967
+ });
2968
+ }
2969
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ConnectionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2970
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ConnectionService, providedIn: 'root' }); }
2971
+ }
2972
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ConnectionService, decorators: [{
2973
+ type: Injectable,
2974
+ args: [{
2975
+ providedIn: 'root'
2976
+ }]
2977
+ }], ctorParameters: () => [] });
2978
+
2979
+ /**
2980
+ * Providing functions,that are are injected at application startup and executed during app initialization.
2981
+ */
2982
+ function init_moduleFnc(coreConfig, deviceService, logger, http, configService, authService) {
2983
+ return () => {
2984
+ authService.setInitialRequestUri();
2985
+ deviceService.init();
2986
+ return coreConfig.main
2987
+ ? !Array.isArray(coreConfig.main)
2988
+ ? of([coreConfig.main])
2989
+ : forkJoin([...coreConfig.main].map((uri) => http.get(`${Utils.getBaseHref()}${uri}`).pipe(catchError((e) => {
2990
+ logger.error('failed to catch config file', e);
2991
+ return of({});
2992
+ }), map((res) => res)))).pipe(
2993
+ // switchMap((configs: YuvConfig[]) => configService.extendConfig(configs)),
2994
+ tap((configs) => configService.extendConfig(configs)), switchMap(() => authService.initUser().pipe(catchError((e) => {
2995
+ authService.initError = {
2996
+ status: e.status,
2997
+ key: e.error.error
2998
+ };
2999
+ return of(true);
3000
+ }))))
3001
+ : of(false);
3002
+ };
3003
+ }
3004
+
3005
+ var DeviceScreenOrientation;
3006
+ (function (DeviceScreenOrientation) {
3007
+ DeviceScreenOrientation["PORTRAIT"] = "portrait";
3008
+ DeviceScreenOrientation["LANDSCAPE"] = "landscape";
3009
+ })(DeviceScreenOrientation || (DeviceScreenOrientation = {}));
3010
+
3011
+ /**
3012
+ * This service is used to adapt styles and designs of the client to
3013
+ * different devices and screen sizes.
3014
+ *
3015
+ * Using `screenChange$` observable you are able to monitor changes to
3016
+ * the screen size and act upon it.
3017
+ *
3018
+ * This service will also adds attributes to the body tag that reflect the
3019
+ * current screen/device state. This way you can apply secific styles in your
3020
+ * css files for different screen resolutions and orientations.
3021
+ *
3022
+ * Attributes applied to the body tag are:
3023
+ *
3024
+ * - `data-screen` - [s, m, l, xl] - for different screen sizes
3025
+ * (s: for mobile phone like screen sizes, m: for tablet like screen
3026
+ * sizes, 'l': for desktop like screen sizes, 'xl': for screen sizes exceeding
3027
+ * the desktop screen size).
3028
+ *
3029
+ * - `data-orientation` - [portrait, landscape] - for the current screen orientation
3030
+ *
3031
+ * - `data-touch-enabled` - [true] - if the device has touch capabilities (won't be added if the device doesn't have touch capabilities)
3032
+ *
3033
+ * ```html
3034
+ * <body data-screen-size="s" data-screen-orientation="portrait" data-touch-enabled="true">
3035
+ * ...
3036
+ * </body>
3037
+ * ```
3038
+ */
3039
+ class DeviceService {
3040
+ #deviceDetectorService;
3041
+ #upperScreenBoundary;
3042
+ #resize$;
3043
+ #screen;
3044
+ #screenSource;
3045
+ constructor() {
3046
+ this.#deviceDetectorService = inject(DeviceDetectorService);
3047
+ this.#upperScreenBoundary = {
3048
+ small: 600,
3049
+ mediumPortrait: 900,
3050
+ mediumLandscape: 1200,
3051
+ large: 1800
3052
+ };
3053
+ this.#resize$ = fromEvent(window, 'resize').pipe(debounceTime(this.#getDebounceTime()));
3054
+ this.#screenSource = new ReplaySubject(1);
3055
+ this.screenChange$ = this.#screenSource.asObservable();
3056
+ /**
3057
+ * if the device is a mobile device (android / iPhone / windows-phone etc)
3058
+ */
3059
+ this.isMobile = this.#deviceDetectorService.isMobile();
3060
+ /**
3061
+ * if the device us a tablet (iPad etc)
3062
+ */
3063
+ this.isTablet = this.#deviceDetectorService.isTablet();
3064
+ /**
3065
+ * if the app is running on a Desktop browser
3066
+ */
3067
+ this.isDesktop = this.#deviceDetectorService.isDesktop();
3068
+ this.info = this.#deviceDetectorService.getDeviceInfo();
3069
+ this.isTouchEnabled = this.#isTouchEnabled();
3070
+ this.#resize$.subscribe((e) => {
3071
+ this.#setScreen();
3072
+ });
3073
+ }
3074
+ init() {
3075
+ this.#setScreen();
3076
+ }
3077
+ #isTouchEnabled() {
3078
+ return 'ontouchstart' in window || navigator.maxTouchPoints > 0;
3079
+ }
3080
+ #setScreen() {
3081
+ const bounds = {
3082
+ width: window.innerWidth,
3083
+ height: window.innerHeight
3084
+ };
3085
+ let orientation = bounds.width >= bounds.height ? DeviceScreenOrientation.LANDSCAPE : DeviceScreenOrientation.PORTRAIT;
3086
+ if (this.isMobile && window.screen['orientation']) {
3087
+ const screenOrientation = window.screen['orientation'].type;
3088
+ if (screenOrientation === 'landscape-primary' || screenOrientation === 'landscape-secondary') {
3089
+ orientation = DeviceScreenOrientation.LANDSCAPE;
3090
+ }
3091
+ else if (screenOrientation === 'portrait-primary' || screenOrientation === 'portrait-secondary') {
3092
+ orientation = DeviceScreenOrientation.PORTRAIT;
3093
+ }
3094
+ }
3095
+ this.#screen = {
3096
+ size: this.#getScreenSize(bounds, orientation),
3097
+ orientation,
3098
+ width: bounds.width,
3099
+ height: bounds.height
3100
+ };
3101
+ this.#screenSource.next(this.#screen);
3102
+ this.#setupDOM(this.#screen);
3103
+ // force change detection because resize will not be recognized by Angular in some cases
3104
+ // TODO: check: causes recursive ticks in some cases ...
3105
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
3106
+ setTimeout(() => { }, 0);
3107
+ }
3108
+ #setupDOM(screen) {
3109
+ const body = document.querySelector('body');
3110
+ body.setAttribute('data-screen-size', screen.size);
3111
+ body.setAttribute('data-screen-orientation', screen.orientation);
3112
+ if (this.isTouchEnabled)
3113
+ body.setAttribute('data-touch-enabled', 'true');
3114
+ else
3115
+ body.removeAttribute('data-touch-enabled');
3116
+ }
3117
+ #getScreenSize(bounds, orientation) {
3118
+ if (this.#isBelow(this.#upperScreenBoundary.small, bounds)) {
3119
+ return 's';
3120
+ }
3121
+ else if (this.#isBelow(orientation === 'landscape' ? this.#upperScreenBoundary.mediumLandscape : this.#upperScreenBoundary.mediumPortrait, bounds)) {
3122
+ return 'm';
3123
+ }
3124
+ else if (this.#isBelow(this.#upperScreenBoundary.large, bounds)) {
3125
+ return 'l';
3126
+ }
3127
+ else {
3128
+ return 'xl';
3129
+ }
3130
+ }
3131
+ #isBelow(size, bounds) {
3132
+ const landscape = bounds.width < this.#upperScreenBoundary.large ? bounds.width >= bounds.height : false;
3133
+ return (landscape && bounds.height < size) || (!landscape && bounds.width < size);
3134
+ }
3135
+ #getDebounceTime() {
3136
+ // on mobile devices resize only happens when rotating the device or when
3137
+ // keyboard appears, so we dont't need to debounce
3138
+ return this.isMobile ? 0 : 500;
3139
+ }
3140
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DeviceService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3141
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DeviceService, providedIn: 'root' }); }
3142
+ }
3143
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DeviceService, decorators: [{
3144
+ type: Injectable,
3145
+ args: [{
3146
+ providedIn: 'root'
3147
+ }]
3148
+ }], ctorParameters: () => [] });
3149
+
3150
+ const transformResponse = () => map((res) => (res && res.body ? res.body.objects.map((val) => val) : null));
3151
+ /**
3152
+ * Service for providing upload of different object types into a client.
3153
+ */
3154
+ class UploadService {
3155
+ constructor() {
3156
+ this.#backend = inject(BackendService);
3157
+ this.#http = inject(HttpClient);
3158
+ this.#logger = inject(Logger);
3159
+ this.#status = { err: 0, items: [] };
3160
+ this.#statusSource = new ReplaySubject();
3161
+ this.status$ = this.#statusSource.pipe(scan((acc, newVal) => ({ ...acc, ...newVal }), this.#status));
3162
+ this.#uploadStatus = new BehaviorSubject(null);
3163
+ this.uploadStatus$ = this.#uploadStatus.asObservable();
3164
+ }
3165
+ #backend;
3166
+ #http;
3167
+ #logger;
3168
+ #status;
3169
+ #statusSource;
3170
+ #uploadStatus;
3171
+ /**
3172
+ * Upload a file.
3173
+ * @param url The URL to upload the file to
3174
+ * @param file The file to be uploaded
3175
+ * @param label A label that will show up in the upload overlay dialog while uploading
3176
+ */
3177
+ upload(url, file, label, silent) {
3178
+ return this.#executeUpload(url, file, label || file.name, silent);
3179
+ }
3180
+ /**
3181
+ * Upload files using multipart upload.
3182
+ * @param url The URL to upload the files to
3183
+ * @param files The files to be uploaded
3184
+ * @param data Data to be send along with the files
3185
+ * @param label A label that will show up in the upload overlay dialog while uploading
3186
+ */
3187
+ uploadMultipart(url, files, data, label, silent) {
3188
+ return this.#executeMultipartUpload(url, files, label || 'Upload', data, silent);
3189
+ }
3190
+ createDocument(url, data) {
3191
+ const formData = this.#createFormData({ data });
3192
+ const request = this.#createHttpRequest(url, { formData }, false);
3193
+ return this.#http.request(request).pipe(filter((obj) => obj && obj.body), transformResponse(), catchError((err) => throwError(() => err)));
3194
+ }
3195
+ /**
3196
+ * Cancels an upload request and removes it from the list of files being uploaded.
3197
+ * @param id ID of the UploadItem to be canceled
3198
+ */
3199
+ cancelItem(id) {
3200
+ if (id) {
3201
+ const match = this.#status.items.find((i) => i.id === id);
3202
+ if (match) {
3203
+ match.subscription.unsubscribe();
3204
+ this.#status.items = this.#status.items.filter((i) => i.id !== id);
3205
+ }
3206
+ }
3207
+ else {
3208
+ this.#status.items.forEach((element) => element.subscription.unsubscribe());
3209
+ this.#status.items = [];
3210
+ }
3211
+ this.#status.err = this.#status.items.filter((i) => i.err).length;
3212
+ this.#statusSource.next(this.#status);
3213
+ }
3214
+ /**
3215
+ * Prepares Formdata for multipart upload.
3216
+ * @param from contains form and or file
3217
+ */
3218
+ #createFormData({ file, data }) {
3219
+ const formData = new FormData();
3220
+ (file || []).forEach((f) => formData.append('files', f, f.name));
3221
+ data ? formData.append('data', new Blob([JSON.stringify(data)], { type: 'application/json' })) : null;
3222
+ return formData;
3223
+ }
3224
+ /**
3225
+ * Prepares Http Request.
3226
+ * @param url The URL to upload the file to
3227
+ * @param content formdata or single file
3228
+ * @param reportProgress Request should report upload progress
3229
+ * @param method Request method
3230
+ */
3231
+ #createHttpRequest(url, content, reportProgress, method = 'POST') {
3232
+ const { formData, file } = content;
3233
+ // add request param to bypass the serviceworker
3234
+ url += `${url.indexOf('?') === -1 ? '?' : '&'}ngsw-bypass=1`;
3235
+ let headers = this.#backend.getAuthHeaders();
3236
+ if (file) {
3237
+ headers = headers.set('Content-Disposition', `attachment; filename*=utf-8''${encodeURIComponent(file.name)}`);
3238
+ }
3239
+ return new HttpRequest(method, url, file || formData, { headers, reportProgress });
3240
+ }
3241
+ /**
3242
+ * Prepares single file POST upload.
3243
+ * @param url The URL to upload the file to
3244
+ * @param file The file to be uploaded
3245
+ * @param label A label that will show up in the upload overlay dialog while uploading
3246
+ */
3247
+ #executeUpload(url, file, label, silent = false) {
3248
+ const request = this.#createHttpRequest(url, { file }, true);
3249
+ return silent ? this.#http.request(request) : this.#startUploadWithFile(request, label).pipe(transformResponse());
3250
+ }
3251
+ /**
3252
+ * Prepare multipart upload.
3253
+ * @param url The URL to upload the file to
3254
+ * @param file Array of files to be uploaded
3255
+ * @param label A label that will show up in the upload overlay dialog while uploading
3256
+ * @param data Data to be send along with the files
3257
+ */
3258
+ #executeMultipartUpload(url, file, label, data, silent = false) {
3259
+ const formData = this.#createFormData({ file, data });
3260
+ const request = this.#createHttpRequest(url, { formData }, true);
3261
+ return silent ? this.#http.request(request) : this.#startUploadWithFile(request, label).pipe(transformResponse());
3262
+ }
3263
+ #generateResult(result) {
3264
+ const objects = result.body?.objects;
3265
+ if (objects && objects.length > 1) {
3266
+ const data = objects[0];
3267
+ // const bp = this.#system.getBaseProperties();
3268
+ // const label = data.properties[bp.title] ? data.properties[bp.title].value : '...';
3269
+ // TODO: Get the label from somewhere
3270
+ const label = '...';
3271
+ return [
3272
+ {
3273
+ objectId: objects.map((val) => val.properties[BaseObjectTypeField.OBJECT_ID].value),
3274
+ contentStreamId: data.contentStreams[0]?.contentStreamId,
3275
+ filename: data.contentStreams[0]?.fileName,
3276
+ label: `(${objects.length}) ${label}`
3277
+ }
3278
+ ];
3279
+ }
3280
+ else {
3281
+ return result.body.objects.map((o) => ({
3282
+ objectId: o.properties[BaseObjectTypeField.OBJECT_ID].value,
3283
+ contentStreamId: o.contentStreams[0]?.contentStreamId,
3284
+ filename: o.contentStreams[0]?.fileName,
3285
+ // label: o.properties[bp.title] ? o.properties[bp.title].value : o.contentStreams![0]?.fileName
3286
+ // TODO: Get the label from somewhere
3287
+ label: o.contentStreams[0]?.fileName
3288
+ }));
3289
+ }
3290
+ }
3291
+ #createProgressStatus(event, progress, id) {
3292
+ if (event.type === HttpEventType.UploadProgress) {
3293
+ const percentDone = Math.round((100 * event.loaded) / event.total);
3294
+ progress.next(percentDone);
3295
+ }
3296
+ else if (event instanceof HttpResponse) {
3297
+ progress.complete();
3298
+ // add upload response
3299
+ // this.status.items = this.status.items.filter(s => s.id !== id);
3300
+ const idx = this.#status.items.findIndex((s) => s.id === id);
3301
+ if (idx !== -1) {
3302
+ this.#status.items[idx].result = this.#generateResult(event);
3303
+ this.#statusSource.next(this.#status);
3304
+ }
3305
+ }
3306
+ }
3307
+ #createUploadError(err, progress, id) {
3308
+ const statusItem = this.#status.items.find((s) => s.id === id);
3309
+ statusItem.err = {
3310
+ code: err.status,
3311
+ message: err.error ? err.error.errorMessage : err.message
3312
+ };
3313
+ this.#logger.error('upload failed', statusItem);
3314
+ this.#status.err++;
3315
+ this.#statusSource.next(this.#status);
3316
+ progress.next(0);
3317
+ return throwError(() => new Error(err.message));
3318
+ }
3319
+ /**
3320
+ * Actually starts the upload process.
3321
+ * @param request Request to be executed
3322
+ * @param label A label that will show up in the upload overlay dialog while uploading
3323
+ */
3324
+ #startUploadWithFile(request, label) {
3325
+ return new Observable((o) => {
3326
+ const id = Utils.uuid();
3327
+ const progress = new Subject();
3328
+ let result;
3329
+ // Create a subscription from the http request that will be applied to the upload
3330
+ // status item in order to be able to cancel the request later on.
3331
+ this.#uploadStatus.next(false);
3332
+ const subscription = this.#http
3333
+ .request(request)
3334
+ .pipe(catchError((err) => this.#createUploadError(err, progress, id)), tap((event) => this.#createProgressStatus(event, progress, id)))
3335
+ // actual return value of this function
3336
+ .subscribe({
3337
+ next: (res) => (res.status ? (result = res) : null),
3338
+ error: (err) => {
3339
+ o.error(err);
3340
+ this.#uploadStatus.next(true);
3341
+ o.complete();
3342
+ },
3343
+ complete: () => {
3344
+ o.next(result);
3345
+ this.#uploadStatus.next(true);
3346
+ o.complete();
3347
+ }
3348
+ });
3349
+ this.#status.items.push({
3350
+ id,
3351
+ filename: label,
3352
+ progress: progress.asObservable(),
3353
+ subscription,
3354
+ err: undefined
3355
+ });
3356
+ this.#statusSource.next(this.#status);
3357
+ });
3358
+ }
3359
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: UploadService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3360
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: UploadService, providedIn: 'root' }); }
3361
+ }
3362
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: UploadService, decorators: [{
3363
+ type: Injectable,
3364
+ args: [{
3365
+ providedIn: 'root'
3366
+ }]
3367
+ }] });
3368
+
3369
+ /**
3370
+ * Service for working with dms objects: create them, delete, etc.
3371
+ */
3372
+ class DmsService {
3373
+ #searchService = inject(SearchService);
3374
+ #backend = inject(BackendService);
3375
+ #eventService = inject(EventService);
3376
+ #uploadService = inject(UploadService);
3377
+ // general trigger operator to handle all dms events
3378
+ triggerEvent(event, id, silent = false) {
3379
+ return (stream) => stream.pipe(
3380
+ // update does not return permissions, so we need to re-load the whole dms object
3381
+ // TODO: Remove once permissions are provided
3382
+ switchMap((res) => (!id ? of(res) : this.getDmsObject(id))),
3383
+ // TODO: enable once permissions are provided
3384
+ // map((res) => this.searchResultToDmsObject(this.searchService.toSearchResult(res).items[0])),
3385
+ tap((res) => !silent && this.#eventService.trigger(event, res)));
3386
+ }
3387
+ // general trigger operator to handle all dms events
3388
+ #triggerEvents(event, ids, silent = false) {
3389
+ return (stream) => stream.pipe(
3390
+ // update does not return permissions, so we need to re-load the whole dms object
3391
+ // TODO: Remove once permissions are provided
3392
+ switchMap((res) => (!ids ? of(res) : this.getDmsObjects(ids))),
3393
+ // TODO: enable once permissions are provided
3394
+ // map((_res: any[]) => _res.map((res, i) => res?._error ? { ...res, id: ids?[i] } : this.searchResultToDmsObject(this.searchService.toSearchResult(res).items[0]))),
3395
+ map((_res) => _res.map((res, i) => (res?._error && ids ? { ...res, id: ids[i] } : res))), tap((res) => !silent && res.forEach((o) => o && this.#eventService.trigger(event, o))));
3396
+ }
3397
+ /**
3398
+ * Create new dms object(s). Providing an array of files here instead of one will create
3399
+ * a new dms object for every file. In this case indexdata will shared across all files.
3400
+ * @param objectTypeId The ID of the object type to be created
3401
+ * @param indexdata Indexdata for the new object(s)
3402
+ * @param files File(s) to create dms objects content(s) with
3403
+ * @param label A label that will show up in the upload overlay dialog while uploading
3404
+ *
3405
+ * @returns Array of IDs of the objects that have been created
3406
+ */
3407
+ createDmsObject(objectTypeId, indexdata, files, label, silent = false) {
3408
+ const url = `${this.#backend.getApiBase(ApiBase.apiWeb)}/dms/objects`;
3409
+ const data = indexdata;
3410
+ data[BaseObjectTypeField.OBJECT_TYPE_ID] = objectTypeId;
3411
+ const upload = files.length ? this.#uploadService.uploadMultipart(url, files, data, label, silent) : this.#uploadService.createDocument(url, data);
3412
+ return upload
3413
+ .pipe(map((res) => res.map((r) => r.properties[BaseObjectTypeField.OBJECT_ID].value)),
3414
+ // TODO: Replace by proper solution
3415
+ // Right now there is a gap between when the object was
3416
+ // created and when it is indexed. So delaying here will
3417
+ // give backend time to get its stuff together.
3418
+ delay(1000))
3419
+ .pipe(this.triggerEvent(YuvEventType.DMS_OBJECT_CREATED, '', silent));
3420
+ }
3421
+ /**
3422
+ * Delete a dms object.
3423
+ * @param id ID of the object to be deleted
3424
+ */
3425
+ deleteDmsObject(id, silent = false) {
3426
+ const url = `/dms/objects/${id}`;
3427
+ return this.#backend
3428
+ .delete(url, ApiBase.apiWeb)
3429
+ .pipe(map(() => ({ id })))
3430
+ .pipe(this.triggerEvent(YuvEventType.DMS_OBJECT_DELETED, '', silent));
3431
+ }
3432
+ /**
3433
+ * Restore older version of a dms object.
3434
+ * @param id ID of the object to be restored
3435
+ * @param version version of the object to be restored
3436
+ */
3437
+ restoreDmsObject(id, version, silent = false) {
3438
+ const url = `/dms/objects/${id}/versions/${version}/actions/restore?waitForSearchConsistency=true&restoreParentId=false`;
3439
+ return this.#backend.post(url, {}, ApiBase.apiWeb).pipe(this.triggerEvent(YuvEventType.DMS_OBJECT_UPDATED, id, silent));
3440
+ }
3441
+ /**
3442
+ * Upload (add/replace) content to a dms object.
3443
+ * @param objectId ID of the dms object to upload the file to
3444
+ * @param file The file to be uploaded
3445
+ */
3446
+ uploadContent(objectId, file) {
3447
+ return this.#uploadService.upload(this.getContentPath(objectId), file).pipe(this.triggerEvent(YuvEventType.DMS_OBJECT_UPDATED, objectId));
3448
+ }
3449
+ /**
3450
+ * Path of dms object content file.
3451
+ * @param objectId ID of the dms object
3452
+ * @param version version number of the dms object
3453
+ */
3454
+ getContentPath(objectId, version) {
3455
+ return `${this.#backend.getApiBase(ApiBase.apiWeb)}/dms/objects/${objectId}/contents/file${version ? '?version=' + version : ''}`;
3456
+ }
3457
+ /**
3458
+ * Original API Path of dms object content file.
3459
+ * @param objectId ID of the dms object
3460
+ * @param version version number of the dms object
3461
+ * @param rendition should return rendition path of the dms object
3462
+ */
3463
+ getFullContentPath(objectId, version, rendition = false) {
3464
+ return `${this.#backend.getApiBase(ApiBase.core, true)}/dms/objects/${objectId}${version ? '/versions/' + version : ''}/contents/${rendition ? 'renditions/pdf' : 'file'}`;
3465
+ }
3466
+ getSlideURI(objectId, mimeType) {
3467
+ const supportedMimeTypes = ['*/*'];
3468
+ let supported = false;
3469
+ if (mimeType) {
3470
+ // check if mime type supports slides
3471
+ supportedMimeTypes.forEach((p) => (supported = supported || Utils.patternToRegExp(p).test(mimeType)));
3472
+ }
3473
+ return !mimeType || supported ? `${this.#backend.getApiBase(ApiBase.core, true)}/dms/objects/${objectId}/contents/renditions/slide` : undefined;
3474
+ }
3475
+ /**
3476
+ * Downloads the content of dms objects.
3477
+ *
3478
+ * @param DmsObject[] dmsObjects Array of dms objects to be downloaded
3479
+ * @param withVersion should download specific version of the object
3480
+ */
3481
+ downloadContent(objects, withVersion) {
3482
+ objects.forEach((object, i) => setTimeout(() => {
3483
+ const uri = `${this.getContentPath(object?.id, withVersion ? object?.version : undefined)}`;
3484
+ this.#backend.download(uri);
3485
+ }, Utils.isSafari() ? i * 1000 : 0 // Safari does not allow multi download
3486
+ ));
3487
+ }
3488
+ /**
3489
+ * Fetch a dms object.
3490
+ * @param id ID of the object to be retrieved
3491
+ * @param version Desired version of the object
3492
+ */
3493
+ getDmsObject(id, version, silent = false, requestOptions) {
3494
+ return this.#backend
3495
+ .get(`/dms/objects/${id}${version ? '/versions/' + version : ''}`, undefined, requestOptions)
3496
+ .pipe(map((res) => {
3497
+ const item = this.#searchService.toSearchResult(res).items[0];
3498
+ return this.#searchResultToDmsObject(item);
3499
+ }))
3500
+ .pipe(this.triggerEvent(YuvEventType.DMS_OBJECT_LOADED, '', silent));
3501
+ }
3502
+ /**
3503
+ * Updates a tag on a dms object.
3504
+ * @param id The ID of the object
3505
+ * @param tag The tag to be updated
3506
+ * @param value The tags new value
3507
+ */
3508
+ setDmsObjectTag(id, tag, value, silent = false) {
3509
+ return this.#backend
3510
+ .post(`/dms/objects/tags/${tag}/state/${value}?query=SELECT * FROM system:object WHERE system:objectId='${id}'`, {}, ApiBase.core)
3511
+ .pipe(this.triggerEvent(YuvEventType.DMS_OBJECT_UPDATED, id, silent));
3512
+ }
3513
+ /**
3514
+ * Deletes a tag from a dms object.
3515
+ * @param id The ID of the object
3516
+ * @param tag The tag to be deleted
3517
+ */
3518
+ deleteDmsObjectTag(id, tag, silent = false) {
3519
+ return this.#backend.delete(`/dms/objects/${id}/tags/${tag}`, ApiBase.core).pipe(this.triggerEvent(YuvEventType.DMS_OBJECT_UPDATED, id, silent));
3520
+ }
3521
+ /**
3522
+ * Update indexdata of a dms object.
3523
+ * @param id ID of the object to apply the data to
3524
+ * @param data Indexdata to be applied
3525
+ * @param silent flag to trigger DMS_OBJECT_UPDATED event
3526
+ */
3527
+ updateDmsObject(id, data, silent = false) {
3528
+ return this.#backend.patch(`/dms/objects/${id}`, data).pipe(this.triggerEvent(YuvEventType.DMS_OBJECT_UPDATED, id, silent));
3529
+ }
3530
+ /**
3531
+ * Updates given objects.
3532
+ * @param objects the objects to updated
3533
+ */
3534
+ updateDmsObjects(objects, silent = false) {
3535
+ return this.#backend
3536
+ .patch(`/dms/objects`, {
3537
+ patches: objects.map((o) => ({
3538
+ id: o.id,
3539
+ data: o.data
3540
+ }))
3541
+ })
3542
+ .pipe(this.#triggerEvents(YuvEventType.DMS_OBJECT_UPDATED, objects.map((o) => o.id), silent));
3543
+ }
3544
+ /**
3545
+ * Updates a tag on a dms object.
3546
+ * @param ids List of IDs of objects
3547
+ * @param tag The tag to be updated
3548
+ * @param value The tags new value
3549
+ */
3550
+ updateDmsObjectsTag(ids, tag, value, silent = false) {
3551
+ return this.batchUpdateTag(ids, tag, value).pipe(this.#triggerEvents(YuvEventType.DMS_OBJECT_UPDATED, ids, silent));
3552
+ }
3553
+ /**
3554
+ * Moves given objects to a different folder.
3555
+ * @param folderId the id of the new parent folder
3556
+ * @param objects objects to be moved
3557
+ * @param options options for the move operation
3558
+ */
3559
+ moveDmsObjects(targetFolderId, objects, options) {
3560
+ return this.updateDmsObjects(objects.map((o) => ({ id: o.id, data: { [BaseObjectTypeField.PARENT_ID]: targetFolderId } }), true)).pipe(tap((res) => !options?.silent && this.#eventService.trigger(YuvEventType.DMS_OBJECTS_MOVED, res)));
3561
+ }
3562
+ /**
3563
+ * Copy given objects to a different folder. The objects will be copied with their indexdata referencing
3564
+ * the existing content of the source object.
3565
+ * @param targetFolderId The ID of the target folder
3566
+ * @param objects The objects to be copied
3567
+ * @param options options for the copy operation
3568
+ */
3569
+ copyDmsObjects(targetFolderId, objects, options) {
3570
+ const excludeProperties = [
3571
+ BaseObjectTypeField.OBJECT_ID,
3572
+ BaseObjectTypeField.CREATED_BY,
3573
+ BaseObjectTypeField.CREATION_DATE,
3574
+ BaseObjectTypeField.MODIFIED_BY,
3575
+ BaseObjectTypeField.MODIFICATION_DATE,
3576
+ BaseObjectTypeField.VERSION_NUMBER,
3577
+ BaseObjectTypeField.TRACE_ID,
3578
+ BaseObjectTypeField.PARENT_OBJECT_TYPE_ID,
3579
+ BaseObjectTypeField.PARENT_VERSION_NUMBER
3580
+ ];
3581
+ const mappedObjects = objects.map((o) => {
3582
+ o.data[BaseObjectTypeField.PARENT_ID] = targetFolderId;
3583
+ // Remove properties that are not allowed to be copied.
3584
+ // This also includes content stream fields bundled into the objects data field.
3585
+ // Properties ending with '_title' are also excluded as they are enrichment values
3586
+ // provided by API-Web.
3587
+ Object.keys(o.data)
3588
+ .filter((key) => key.endsWith('_title') || excludeProperties.includes(key) || Object.values(ContentStreamField).includes(key))
3589
+ .forEach((key) => Reflect.deleteProperty(o.data, key));
3590
+ // map filtered data field to data format required by the Core-API
3591
+ const properties = Object.keys(o.data).reduce((acc, key) => {
3592
+ acc[key] = { value: o.data[key] };
3593
+ return acc;
3594
+ }, {});
3595
+ return {
3596
+ properties: properties,
3597
+ objectTypeId: o.objectTypeId,
3598
+ ...(o.content
3599
+ ? {
3600
+ contentStreams: [o.content]
3601
+ }
3602
+ : {})
3603
+ };
3604
+ });
3605
+ const query = options
3606
+ ? Object.keys(options)
3607
+ .map((key) => `${key}=${options[key]}`)
3608
+ .join('&')
3609
+ : '';
3610
+ return this.#backend.post(`/dms/objects?${query}}`, { objects: mappedObjects }, ApiBase.core);
3611
+ }
3612
+ /**
3613
+ * Get a bunch of dms objects.
3614
+ * @param ids List of IDs of objects to be retrieved
3615
+ */
3616
+ getDmsObjects(ids, silent = false) {
3617
+ return this.batchGet(ids)
3618
+ .pipe(map((_res) => _res.map((res, i) => (res?._error ? { ...res, id: ids[i] } : this.#searchResultToDmsObject(this.#searchService.toSearchResult(res).items[0])))))
3619
+ .pipe(this.#triggerEvents(YuvEventType.DMS_OBJECT_LOADED, undefined, silent));
3620
+ }
3621
+ /**
3622
+ * Delete a bunch of dms objects.
3623
+ * @param ids List of IDs of objects to be deleted
3624
+ * @param options Options for the delete operation
3625
+ * @returns Array of delete results.
3626
+ */
3627
+ deleteDmsObjects(objects, options) {
3628
+ const queryParams = options
3629
+ ? `?${Object.keys(options)
3630
+ .filter((k) => ['waitForSearchConsistency', 'greedy'].includes(k))
3631
+ .map((k) => `${k}=${options[k]}`)
3632
+ .join('&')}`
3633
+ : '';
3634
+ return this.#backend
3635
+ .delete(`/dms/objects${queryParams}`, ApiBase.core, {
3636
+ body: {
3637
+ objects: objects.map((o) => ({
3638
+ properties: typeof o === 'string'
3639
+ ? {
3640
+ 'system:objectId': {
3641
+ value: o
3642
+ }
3643
+ }
3644
+ : {
3645
+ 'system:objectId': { value: o.id },
3646
+ subject: { value: o.subject }
3647
+ }
3648
+ }))
3649
+ }
3650
+ })
3651
+ .pipe(map((res) => res?.objects?.map((r) => {
3652
+ const v = r.options?.[SystemResult.DELETE];
3653
+ return {
3654
+ id: r.properties?.[BaseObjectTypeField.OBJECT_ID]?.value,
3655
+ properties: r.properties,
3656
+ ...(v?.httpStatusCode >= 400 ? { _error: { status: v.httpStatusCode, message: v.message } } : {})
3657
+ };
3658
+ })))
3659
+ .pipe(this.#triggerEvents(YuvEventType.DMS_OBJECT_DELETED, undefined, options?.silent));
3660
+ }
3661
+ /**
3662
+ * Fetch a dms object versions.
3663
+ * @param id ID of the object to be retrieved
3664
+ */
3665
+ getDmsObjectVersions(id) {
3666
+ return this.#backend.get('/dms/objects/' + id + '/versions').pipe(map((res) => {
3667
+ const items = this.#searchService.toSearchResult(res).items || [];
3668
+ return items.map((item) => this.#searchResultToDmsObject(item));
3669
+ }), map((res) => res.sort(Utils.sortValues('version', Sort.DESC))));
3670
+ }
3671
+ getDmsObjectVersion(id, version) {
3672
+ return this.#backend
3673
+ .get(`/dms/objects/${id}/versions/${version}`)
3674
+ .pipe(map((res) => this.#searchResultToDmsObject(this.#searchService.toSearchResult(res).items[0])));
3675
+ }
3676
+ coreApiResponseToDmsObject(res) {
3677
+ return this.#searchResultToDmsObject({
3678
+ objectTypeId: res.properties[BaseObjectTypeField.OBJECT_TYPE_ID].value,
3679
+ fields: new Map(Object.entries(res.properties)),
3680
+ content: res.contentStreams?.[0]
3681
+ });
3682
+ }
3683
+ #searchResultToDmsObject(resItem) {
3684
+ return new DmsObject(resItem);
3685
+ }
3686
+ batchUpdateTag(ids, tag, value) {
3687
+ return this.#backend.batch(ids.map((id) => ({
3688
+ method: 'POST',
3689
+ uri: `/dms/objects/tags/${tag}/state/${value}?query=SELECT * FROM system:object WHERE system:objectId='${id}'`,
3690
+ base: ApiBase.core,
3691
+ body: {}
3692
+ })));
3693
+ }
3694
+ batchDeleteTag(ids, tag) {
3695
+ return this.#backend.batch(ids.map((id) => ({
3696
+ method: 'DELETE',
3697
+ uri: `/dms/objects/${id}/tags/${tag}`,
3698
+ base: ApiBase.core
3699
+ })));
3700
+ }
3701
+ batchDelete(ids) {
3702
+ return this.#backend.batch(ids.map((id) => ({ method: 'DELETE', uri: `/dms/objects/${id}` })));
3703
+ }
3704
+ batchGet(ids) {
3705
+ return this.#backend.batch(ids.map((id) => ({ method: 'GET', uri: `/dms/objects/${id}` })));
3706
+ }
3707
+ /**
3708
+ * Map search result from the backend to applications SearchResult object
3709
+ * @param searchResponse The backend response
3710
+ */
3711
+ toSearchResult(searchResponse) {
3712
+ const resultListItems = [];
3713
+ const objectTypes = [];
3714
+ searchResponse.objects.forEach((o) => {
3715
+ const fields = new Map();
3716
+ // process properties section of result
3717
+ Object.keys(o.properties).forEach((key) => {
3718
+ let value = o.properties[key].value;
3719
+ if (o.properties[key].clvalue) {
3720
+ // table fields will have a clientValue too ...
3721
+ value = o.properties[key].clvalue;
3722
+ // ... and also may contain values that need to be resolved
3723
+ if (o.properties[key].resolvedValues) {
3724
+ value.forEach((v) => {
3725
+ Object.keys(v).forEach((k) => {
3726
+ const resValue = Array.isArray(v[k]) ? v[k].map((i) => o.properties[key].resolvedValues[i]) : o.properties[key].resolvedValues[v[k]];
3727
+ if (resValue) {
3728
+ v[`${k}_title`] = resValue;
3729
+ }
3730
+ });
3731
+ });
3732
+ }
3733
+ }
3734
+ fields.set(key, value);
3735
+ if (o.properties[key].title) {
3736
+ fields.set(key + '_title', o.properties[key].title);
3737
+ }
3738
+ });
3739
+ // process contentStreams section of result if available.
3740
+ // Objects that don't have files attached won't have this section
3741
+ let content;
3742
+ if (o.contentStreams && o.contentStreams.length > 0) {
3743
+ // we assume that each result object only has ONE file attached, altough
3744
+ // this is an array and there may be more
3745
+ const contentStream = o.contentStreams[0];
3746
+ // also add contentstream related fields to the result fields
3747
+ fields.set(ContentStreamField.LENGTH, contentStream.length);
3748
+ fields.set(ContentStreamField.MIME_TYPE, contentStream.mimeType);
3749
+ fields.set(ContentStreamField.FILENAME, contentStream.fileName);
3750
+ fields.set(ContentStreamField.ID, contentStream.contentStreamId);
3751
+ fields.set(ContentStreamField.RANGE, contentStream.contentStreamRange);
3752
+ fields.set(ContentStreamField.REPOSITORY_ID, contentStream.repositoryId);
3753
+ fields.set(ContentStreamField.DIGEST, contentStream.digest);
3754
+ fields.set(ContentStreamField.ARCHIVE_PATH, contentStream.archivePath);
3755
+ content = {
3756
+ contentStreamId: contentStream.contentStreamId,
3757
+ repositoryId: contentStream.repositoryId,
3758
+ range: contentStream.range,
3759
+ digest: contentStream.digest,
3760
+ archivePath: contentStream.archivePath,
3761
+ fileName: contentStream.fileName,
3762
+ mimeType: contentStream.mimeType,
3763
+ size: contentStream.length
3764
+ };
3765
+ }
3766
+ const objectTypeId = o.properties[BaseObjectTypeField.OBJECT_TYPE_ID] ? o.properties[BaseObjectTypeField.OBJECT_TYPE_ID].value : null;
3767
+ if (objectTypes.indexOf(objectTypeId) === -1) {
3768
+ objectTypes.push(objectTypeId);
3769
+ }
3770
+ resultListItems.push({
3771
+ objectTypeId,
3772
+ content,
3773
+ fields,
3774
+ permissions: o.permissions
3775
+ });
3776
+ });
3777
+ const result = {
3778
+ hasMoreItems: searchResponse.hasMoreItems,
3779
+ totalNumItems: searchResponse.totalNumItems,
3780
+ items: resultListItems,
3781
+ objectTypes
3782
+ };
3783
+ return result;
3784
+ }
3785
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DmsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3786
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DmsService, providedIn: 'root' }); }
3787
+ }
3788
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DmsService, decorators: [{
3789
+ type: Injectable,
3790
+ args: [{
3791
+ providedIn: 'root'
3792
+ }]
3793
+ }] });
3794
+
3795
+ class IdmService {
3796
+ #backend = inject(BackendService);
3797
+ queryOrganizationEntity(term, targetTypes, size) {
3798
+ return this.#backend.get(`/idm/search?search=${term}${size ? `&size=${size}` : ''}`).pipe(map$1((res) => [
3799
+ ...(targetTypes.includes('user')
3800
+ ? res.users.map((u) => ({
3801
+ id: u.id,
3802
+ title: `${u.lastname}, ${u.firstname} (${u.username})`, // TODO: u.title,
3803
+ type: 'user'
3804
+ }))
3805
+ : []),
3806
+ ...(targetTypes.includes('role')
3807
+ ? res.roles.map((u) => ({
3808
+ id: u.name,
3809
+ title: u.name,
3810
+ type: 'role'
3811
+ }))
3812
+ : [])
3813
+ ]));
3814
+ }
3815
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: IdmService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3816
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: IdmService, providedIn: 'root' }); }
3817
+ }
3818
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: IdmService, decorators: [{
3819
+ type: Injectable,
3820
+ args: [{
3821
+ providedIn: 'root'
3822
+ }]
3823
+ }] });
3824
+
3825
+ /**
3826
+ * Shows a message after completing each action.
3827
+ */
3828
+ class NotificationService {
3829
+ #toastService;
3830
+ #authService;
3831
+ #eventService;
3832
+ constructor() {
3833
+ this.#toastService = inject(ToastService);
3834
+ this.#authService = inject(AuthService);
3835
+ this.#eventService = inject(EventService);
3836
+ /**
3837
+ * Set to true to suppress any notifications
3838
+ */
3839
+ this.silent = false;
3840
+ /**
3841
+ * Default Notofication Options
3842
+ *
3843
+ */
3844
+ this.options = {
3845
+ position: 'bottom-end'
3846
+ };
3847
+ this.#authService.authenticated$.subscribe((a) => (this.silent = !a));
3848
+ this.#eventService.on(YuvEventType.LOGOUT).subscribe(() => (this.silent = true));
3849
+ }
3850
+ /**
3851
+ * Show info colored massage (blue)
3852
+ *
3853
+ * @param string title
3854
+ * @param string msg
3855
+ */
3856
+ info(title, msg) {
3857
+ this.toast(title, msg);
3858
+ }
3859
+ /**
3860
+ * Show success colored massage (green)
3861
+ * @param string title
3862
+ * @param string msg
3863
+ */
3864
+ success(title, msg) {
3865
+ this.toast(title, msg, 'success');
3866
+ }
3867
+ /**
3868
+ * can not be in use
3869
+ *
3870
+ * @param string title
3871
+ * @param string msg
3872
+ */
3873
+ wait(title, msg) {
3874
+ this.toast(title, msg, 'wait');
3875
+ }
3876
+ /**
3877
+ * Show error colored massage (red)
3878
+ *
3879
+ * @param string title
3880
+ * @param string msg
3881
+ */
3882
+ error(title, msg) {
3883
+ this.toast(title, msg, 'error', {
3884
+ duration: 5
3885
+ });
3886
+ }
3887
+ /**
3888
+ * Show warning colored massage (yellow)
3889
+ *
3890
+ * @param string title
3891
+ * @param string msg
3892
+ */
3893
+ warning(title, msg) {
3894
+ this.toast(title, msg, 'warning');
3895
+ }
3896
+ /**
3897
+ * Public wrapper for accessing the Toastr
3898
+ *
3899
+ * @param string title
3900
+ * @param string msg
3901
+ * @param string mode
3902
+ * @param _options
3903
+ */
3904
+ toast(title, msg, mode, _options) {
3905
+ this.doToast(title, msg, { ...this.options, ..._options }, mode);
3906
+ }
3907
+ /**
3908
+ * Accessing the toastr service
3909
+ *
3910
+ * @param string msg
3911
+ * @param string title
3912
+ * @param options
3913
+ * @param string mode
3914
+ */
3915
+ doToast(title, msg, options, mode) {
3916
+ if (this.silent)
3917
+ return;
3918
+ switch (mode) {
3919
+ case 'success': {
3920
+ this.#toastService.success(title, msg, options);
3921
+ break;
3922
+ }
3923
+ case 'error': {
3924
+ this.#toastService.error(title, msg, options);
3925
+ break;
3926
+ }
3927
+ case 'warning': {
3928
+ this.#toastService.warning(title, msg, options);
3929
+ break;
3930
+ }
3931
+ case 'confirm': {
3932
+ this.#toastService.info(title, msg, options);
3933
+ break;
3934
+ }
3935
+ default: {
3936
+ this.#toastService.info(title, msg, options);
3937
+ }
3938
+ }
3939
+ }
3940
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NotificationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3941
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NotificationService, providedIn: 'root' }); }
3942
+ }
3943
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NotificationService, decorators: [{
3944
+ type: Injectable,
3945
+ args: [{
3946
+ providedIn: 'root'
3947
+ }]
3948
+ }], ctorParameters: () => [] });
3949
+
3950
+ /**
3951
+ * EditingObserver service is used to track changes made inside the application, that should prevent
3952
+ * doing something or going somewhere before the changes are persisted or ignored. For example when
3953
+ * the user starts editing form data and tries to navigate away before saving the changes, this service
3954
+ * will take care of notifying the user.
3955
+ *
3956
+ * It is working kind of like a registry for ongoing tasks that need to be monitored. Every component
3957
+ * that needs to be aware of changes to be persisted can start a task and finish it when everything is done.
3958
+ *
3959
+ * Other components can ask the service for pending tasks to know whether or not to execute an action
3960
+ * (e.g. list component will subscribe and prevent selecting another list item, if changes to the previous one haven't be finished)
3961
+ *
3962
+ * app.component will prevent relevant route changes while tasks are pending.
3963
+ */
3964
+ class PendingChangesService {
3965
+ constructor() {
3966
+ this.#logger = inject(Logger);
3967
+ this.#tasks = [];
3968
+ this.#tasksSource = new ReplaySubject();
3969
+ this.tasks$ = this.#tasksSource.asObservable();
3970
+ // private customMsg = '';
3971
+ this.#defaultMsg = 'You are currently editing the index data of a form that has not been saved. Unsaved data will be lost.';
3972
+ }
3973
+ #logger;
3974
+ #tasks;
3975
+ #tasksSource;
3976
+ // private customMsg = '';
3977
+ #defaultMsg;
3978
+ /**
3979
+ * Registers a task to be pending.
3980
+ * @param message alert message
3981
+ * @returns Unique id to be used for finishing this task
3982
+ */
3983
+ startTask(message) {
3984
+ const taskId = Utils.uuid();
3985
+ this.#tasks.push({ id: taskId, message: message });
3986
+ this.#logger.debug('started pending task: ' + taskId);
3987
+ this.#tasksSource.next(this.#tasks);
3988
+ return taskId;
3989
+ }
3990
+ /**
3991
+ * Finishes a task
3992
+ * @param id The id of the task to be finished. This is the one the component got from startTask()
3993
+ */
3994
+ finishTask(id) {
3995
+ if (id) {
3996
+ this.#tasks = this.#tasks.filter((t) => t.id !== id);
3997
+ this.#tasksSource.next(this.#tasks);
3998
+ this.#logger.debug('finished pending task: ' + id);
3999
+ }
4000
+ }
4001
+ /**
4002
+ * Returns whether or not the service has pending tasks.
4003
+ * If an id is provided, the method will check existence of one specific task.
4004
+ *
4005
+ * @param id The id of the task to be checked
4006
+ * @returns
4007
+ */
4008
+ hasPendingTask(id) {
4009
+ return !id ? !!this.#tasks.length : Array.isArray(id) ? this.#tasks.some((value) => id.includes(value.id)) : this.#tasks.map((t) => t.id).includes(id);
4010
+ }
4011
+ /**
4012
+ * Returns whether or not the component|service has pending tasks.
4013
+ * Checks via confirm dialog
4014
+ * @param component
4015
+ * @returns
4016
+ */
4017
+ check(component) {
4018
+ if (component && component.hasPendingChanges ? !component.hasPendingChanges() : !this.hasPendingTask()) {
4019
+ return false;
4020
+ }
4021
+ else {
4022
+ const confirmed = confirm(this.#getConfirmMessage());
4023
+ if (confirmed) {
4024
+ this.clear();
4025
+ }
4026
+ return !confirmed;
4027
+ }
4028
+ }
4029
+ checkForPendingTasks(taskIds) {
4030
+ if (this.hasPendingTask(taskIds)) {
4031
+ const confirmed = confirm(this.#getConfirmMessage());
4032
+ if (confirmed) {
4033
+ this.clear();
4034
+ }
4035
+ return !confirmed;
4036
+ }
4037
+ else {
4038
+ return false;
4039
+ }
4040
+ }
4041
+ #getConfirmMessage() {
4042
+ let msg = '';
4043
+ this.#tasks.forEach((t) => {
4044
+ // do not apply messages twice
4045
+ if (msg.indexOf(t.message || this.#defaultMsg) === -1) {
4046
+ msg = `${msg}${msg.length > 0 ? '\n---\n' : ''}${t.message || this.#defaultMsg}`;
4047
+ }
4048
+ });
4049
+ return msg;
4050
+ }
4051
+ /**
4052
+ * Clear list of pending tasks
4053
+ */
4054
+ clear() {
4055
+ this.#tasks = [];
4056
+ this.#tasksSource.next(this.#tasks);
4057
+ }
4058
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PendingChangesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4059
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PendingChangesService, providedIn: 'root' }); }
4060
+ }
4061
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PendingChangesService, decorators: [{
4062
+ type: Injectable,
4063
+ args: [{
4064
+ providedIn: 'root'
4065
+ }]
4066
+ }] });
4067
+
4068
+ /**
4069
+ * Providing a `PendingChangesComponent`.
4070
+ */
4071
+ class PendingChangesGuard {
4072
+ constructor(pendingChanges) {
4073
+ this.pendingChanges = pendingChanges;
4074
+ }
4075
+ canDeactivate(component) {
4076
+ // if there are no pending changes, just allow deactivation; else confirm first
4077
+ return !this.pendingChanges.check(component);
4078
+ }
4079
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PendingChangesGuard, deps: [{ token: PendingChangesService }], target: i0.ɵɵFactoryTarget.Injectable }); }
4080
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PendingChangesGuard, providedIn: 'root' }); }
4081
+ }
4082
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PendingChangesGuard, decorators: [{
4083
+ type: Injectable,
4084
+ args: [{
4085
+ providedIn: 'root'
4086
+ }]
4087
+ }], ctorParameters: () => [{ type: PendingChangesService }] });
4088
+
4089
+ class PredictionService {
4090
+ #backend = inject(BackendService);
4091
+ classify(objectIDs, schemaObjectTypeId = 'CLASSIFICATION') {
4092
+ const objects = objectIDs.map((objectID) => ({
4093
+ properties: {
4094
+ [BaseObjectTypeField.OBJECT_ID]: {
4095
+ value: objectID
4096
+ }
4097
+ }
4098
+ }));
4099
+ return this.#backend.post(`/classification?schemaObjectTypeId=${schemaObjectTypeId}`, { objects }, ApiBase.predict).pipe(map((res) => res.predictions.reduce((acc, curr) => ({
4100
+ ...acc,
4101
+ [curr[BaseObjectTypeField.OBJECT_ID].value]: {
4102
+ objectId: curr[BaseObjectTypeField.OBJECT_ID].value,
4103
+ properties: Object.keys(curr.properties).map((type) => ({
4104
+ type,
4105
+ probability: curr.properties[type].probability
4106
+ }))
4107
+ }
4108
+ }), {})));
4109
+ }
4110
+ /**
4111
+ * @param schemaObjectTypeId
4112
+ * @param objectIDs
4113
+ * @returns Observable<Record<string, PredictionClassifyResult>> string is objectID
4114
+ */
4115
+ extract(schemaObjectTypeId, objectIDs) {
4116
+ const searchParams = new URLSearchParams();
4117
+ searchParams.append('schemaObjectTypeId', schemaObjectTypeId);
4118
+ const objects = objectIDs.map((objectID) => ({
4119
+ properties: {
4120
+ [BaseObjectTypeField.OBJECT_ID]: {
4121
+ value: objectID
4122
+ }
4123
+ }
4124
+ }));
4125
+ return this.#backend.post(`/extraction?${searchParams.toString()}`, { objects }, ApiBase.predict).pipe(map((res) => res.predictions.reduce((acc, curr) => ({
4126
+ ...acc,
4127
+ [curr[BaseObjectTypeField.OBJECT_ID].value]: {
4128
+ objectId: curr[BaseObjectTypeField.OBJECT_ID].value,
4129
+ properties: curr.properties
4130
+ }
4131
+ }), {})));
4132
+ }
4133
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PredictionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4134
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PredictionService, providedIn: 'root' }); }
4135
+ }
4136
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PredictionService, decorators: [{
4137
+ type: Injectable,
4138
+ args: [{
4139
+ providedIn: 'root'
4140
+ }]
4141
+ }] });
4142
+
4143
+ class SessionStorageService {
4144
+ #TEMP_STORAGE_ENTRIES_KEY = 'yuv.core.sessionstorage.entries';
4145
+ constructor() {
4146
+ this.#clearTemporaryStorageEntries();
4147
+ }
4148
+ /**
4149
+ * Add a reference to a temporary localstorage entry that should be cleared when a
4150
+ * new browser session starts. In context of forms this will be used to cleanup the
4151
+ * layout state of forms (selected tabs etc.) that are stored locally but should only
4152
+ * be pesisted for one browser session.
4153
+ * @param storageKey Key of the localstorage item
4154
+ */
4155
+ addTemporaryStorageEntry(storageKey) {
4156
+ // entries will themselves be stored in localstorage so we can check for entries
4157
+ // to be removed once the application starts
4158
+ const current = this.#getTemporaryStorageEntries();
4159
+ if (!current.includes(storageKey))
4160
+ localStorage.setItem(this.#TEMP_STORAGE_ENTRIES_KEY, JSON.stringify([...current, storageKey]));
4161
+ }
4162
+ #clearTemporaryStorageEntries() {
4163
+ this.#getTemporaryStorageEntries().forEach((e) => localStorage.removeItem(e));
4164
+ localStorage.removeItem(this.#TEMP_STORAGE_ENTRIES_KEY);
4165
+ }
4166
+ #getTemporaryStorageEntries() {
4167
+ let res = [];
4168
+ const i = localStorage.getItem(this.#TEMP_STORAGE_ENTRIES_KEY);
4169
+ if (i) {
4170
+ try {
4171
+ const entries = JSON.parse(i);
4172
+ if (Array.isArray(entries))
4173
+ res = entries;
4174
+ }
4175
+ catch (e) {
4176
+ console.error(e);
4177
+ }
4178
+ }
4179
+ return res;
4180
+ }
4181
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SessionStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4182
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SessionStorageService, providedIn: 'root' }); }
4183
+ }
4184
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SessionStorageService, decorators: [{
4185
+ type: Injectable,
4186
+ args: [{
4187
+ providedIn: 'root'
4188
+ }]
4189
+ }], ctorParameters: () => [] });
4190
+
4191
+ /**
4192
+ * Prevent app from running into 401 issues related to gateway timeouts.
4193
+ */
4194
+ class AuthInterceptor {
4195
+ /**
4196
+ * @ignore
4197
+ */
4198
+ #userService = inject(UserService);
4199
+ #auth = inject(AuthService);
4200
+ #backend = inject(BackendService);
4201
+ // readonly #oauthService = inject(OAuthService);
4202
+ intercept(request, next) {
4203
+ return next.handle(request).pipe(tap({
4204
+ next: (event) => {
4205
+ if (event instanceof HttpResponse) {
4206
+ // do stuff with response if you want
4207
+ }
4208
+ },
4209
+ error: (error) => {
4210
+ if (error instanceof HttpErrorResponse || error.isHttpErrorResponse) {
4211
+ if (error.status === 401) {
4212
+ if (this.#backend.authUsesOpenIdConnect()) {
4213
+ // this.#oauthService.initLoginFlow();
4214
+ }
4215
+ else {
4216
+ this.#auth.logout();
4217
+ this.#userService.logout();
4218
+ }
4219
+ }
4220
+ }
4221
+ }
4222
+ }));
4223
+ }
4224
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AuthInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4225
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AuthInterceptor, providedIn: 'root' }); }
4226
+ }
4227
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AuthInterceptor, decorators: [{
4228
+ type: Injectable,
4229
+ args: [{
4230
+ providedIn: 'root'
4231
+ }]
4232
+ }] });
4233
+
4234
+ /**
4235
+ * Http Offline interceptor trys to serving offline content for method/url
4236
+ */
4237
+ class OfflineInterceptor {
4238
+ constructor(connectionService) {
4239
+ this.connectionService = connectionService;
4240
+ this.offline = false;
4241
+ this.connectionService.connection$.subscribe((connectionState) => {
4242
+ this.offline = !connectionState.isOnline;
4243
+ });
4244
+ }
4245
+ intercept(request, next) {
4246
+ return next.handle(request);
4247
+ }
4248
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OfflineInterceptor, deps: [{ token: ConnectionService }], target: i0.ɵɵFactoryTarget.Injectable }); }
4249
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OfflineInterceptor, providedIn: 'root' }); }
4250
+ }
4251
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OfflineInterceptor, decorators: [{
4252
+ type: Injectable,
4253
+ args: [{
4254
+ providedIn: 'root'
4255
+ }]
4256
+ }], ctorParameters: () => [{ type: ConnectionService }] });
4257
+
4258
+ /**
4259
+ * Handles missing translations
4260
+ * @ignore
4261
+ */
4262
+ class EoxMissingTranslationHandler {
4263
+ handle(params) {
4264
+ return '!missing key: ' + params.key;
4265
+ }
4266
+ }
4267
+
4268
+ /**
4269
+ * Loader that fetches translations based on the configured locations
4270
+ * @ignore
4271
+ */
4272
+ let EoxTranslateJsonLoader = class EoxTranslateJsonLoader {
4273
+ constructor(http, config) {
4274
+ this.http = http;
4275
+ this.config = config;
4276
+ registerLocaleData(localeDe, 'de', localeExtraDe); // German
4277
+ registerLocaleData(localeAr, 'ar', localeExtraAr); // Arabic
4278
+ registerLocaleData(localeEs, 'es', localeExtraEs); // Spanish
4279
+ registerLocaleData(localePt, 'pt', localeExtraPt); // Portuguese
4280
+ registerLocaleData(localeFr, 'fr', localeExtraFr); // French
4281
+ registerLocaleData(localeZh, 'zh', localeExtraZh); // Chinese
4282
+ registerLocaleData(localeLv, 'lv', localeExtraLv); // Latvian
4283
+ registerLocaleData(localeRu, 'ru', localeExtraRu); // Russian
4284
+ registerLocaleData(localeIt, 'it', localeExtraIt); // Italian
4285
+ registerLocaleData(localeSk, 'sk', localeExtraSk); // Slovak
4286
+ registerLocaleData(localePl, 'pl', localeExtraPl); // Polish
4287
+ registerLocaleData(localeUk, 'uk', localeExtraUk); // Ukrainian
4288
+ registerLocaleData(localeJa, 'ja', localeExtraJa); // Japanese
4289
+ registerLocaleData(localeKo, 'ko', localeExtraKo); // Korean
4290
+ registerLocaleData(localeHi, 'hi', localeExtraHi); // Hindi
4291
+ registerLocaleData(localeBn, 'bn', localeExtraBn); // Bengalese
4292
+ registerLocaleData(localeVi, 'vi', localeExtraVi); // Vietnamese
4293
+ registerLocaleData(localeTr, 'tr', localeExtraTr); // Turkish
4294
+ registerLocaleData(localeNl, 'nl', localeExtraNl); // Dutch
4295
+ registerLocaleData(localeNb, 'nb', localeExtraNb); // Norwegian
4296
+ registerLocaleData(localeTh, 'th', localeExtraTh); // Thai
4297
+ registerLocaleData(localeFi, 'fi', localeExtraFi); // Finnish
4298
+ registerLocaleData(localeSv, 'sv', localeExtraSv); // Swedish
4299
+ registerLocaleData(localeDeCh, 'de-CH', localeExtraDeCh); // German Swiss
4300
+ }
4301
+ /**
4302
+ *
4303
+ * @param string lang
4304
+ * @returns Observable<Object>
4305
+ */
4306
+ getTranslation(lang) {
4307
+ const t = this.config.translations.map((path) => this.loadTranslationFile(path, lang));
4308
+ return forkJoin(t).pipe(map((res) => res.reduce((acc, x) => Object.assign(acc, x), {})));
4309
+ }
4310
+ loadTranslationFile(path, lang) {
4311
+ return this.http.get(`${Utils.getBaseHref()}${path}${lang}.json`).pipe(catchError((e) => {
4312
+ // ISO codes with more than 2 characters are sub-languages like de-CH.
4313
+ // If there is no translation file for that sub-language we'll try to load
4314
+ // the file for the base language (in this case de).
4315
+ return lang.length > 2 ? this.loadTranslationFile(path, lang.substring(0, 2)) : of({});
4316
+ }));
4317
+ }
4318
+ };
4319
+ EoxTranslateJsonLoader = __decorate([
4320
+ __param(1, Inject(CORE_CONFIG)),
4321
+ __metadata("design:paramtypes", [HttpClient, CoreConfig])
4322
+ ], EoxTranslateJsonLoader);
4323
+
4324
+ /**
4325
+ * @ignore
4326
+ */
4327
+ class LoggerConsoleService {
4328
+ constructor(config) {
4329
+ this.config = config;
4330
+ this.styles = {
4331
+ info: 'color:blue',
4332
+ debug: 'background: orange',
4333
+ warn: 'background: rgba(255,0,0,.2);color: red',
4334
+ error: 'background: red; color: #fff'
4335
+ };
4336
+ }
4337
+ apply(fn, args) {
4338
+ args = [`%c${fn}:`, 'font-family: monospace; font-size: 10px; padding: 2px 4px;' + this.styles[fn], ...args];
4339
+ return this.shouldLog(fn) ? console && console[fn] && console[fn](...args) : null;
4340
+ }
4341
+ debug(...args) {
4342
+ this.apply('debug', args);
4343
+ }
4344
+ error(...args) {
4345
+ this.apply('error', args);
4346
+ }
4347
+ info(...args) {
4348
+ this.apply('info', args);
4349
+ }
4350
+ log(...args) {
4351
+ this.apply('log', args);
4352
+ }
4353
+ warn(...args) {
4354
+ this.apply('warn', args);
4355
+ }
4356
+ shouldLog(level) {
4357
+ let should = false;
4358
+ const cfg = this.config.get('core.logging');
4359
+ if (!cfg || !cfg.level)
4360
+ return false;
4361
+ switch (cfg.level) {
4362
+ case 'debug': {
4363
+ should = true;
4364
+ break;
4365
+ }
4366
+ case 'error': {
4367
+ should = ['error'].includes(level);
4368
+ break;
4369
+ }
4370
+ case 'warn': {
4371
+ should = ['warn', 'error'].includes(level);
4372
+ break;
4373
+ }
4374
+ case 'info': {
4375
+ should = ['info', 'warn', 'error'].includes(level);
4376
+ break;
4377
+ }
4378
+ default: {
4379
+ }
4380
+ }
4381
+ return should;
4382
+ }
4383
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LoggerConsoleService, deps: [{ token: ConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
4384
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LoggerConsoleService, providedIn: 'root' }); }
4385
+ }
4386
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LoggerConsoleService, decorators: [{
4387
+ type: Injectable,
4388
+ args: [{
4389
+ providedIn: 'root'
4390
+ }]
4391
+ }], ctorParameters: () => [{ type: ConfigService }] });
4392
+
4393
+ function storageFactory() {
4394
+ return localStorage;
4395
+ }
4396
+ /**
4397
+ * `YuvClientCoreModule` provides a bunch of services to interact with a yuuvis backend.
4398
+ *
4399
+ *
4400
+ */
4401
+ class YuvClientCoreModule {
4402
+ /**
4403
+ * @ignore
4404
+ */
4405
+ constructor(parentModule) {
4406
+ if (parentModule) {
4407
+ throw new Error('YuvClientCoreModule is already loaded.');
4408
+ }
4409
+ }
4410
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: YuvClientCoreModule, deps: [{ token: YuvClientCoreModule, optional: true, skipSelf: true }], target: i0.ɵɵFactoryTarget.NgModule }); }
4411
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: YuvClientCoreModule, imports: [i1.OAuthModule, i1$1.TranslateModule], exports: [YuvClientCoreSharedModule] }); }
4412
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: YuvClientCoreModule, providers: [
4413
+ { provide: Logger, useClass: LoggerConsoleService },
4414
+ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
4415
+ { provide: HTTP_INTERCEPTORS, useClass: OfflineInterceptor, multi: true },
4416
+ { provide: CORE_CONFIG, useClass: CoreConfig, deps: [CUSTOM_CONFIG] },
4417
+ {
4418
+ provide: APP_INITIALIZER,
4419
+ useFactory: init_moduleFnc,
4420
+ multi: true,
4421
+ deps: [CORE_CONFIG, DeviceService, Logger, HttpClient, ConfigService, AuthService]
4422
+ },
4423
+ /**
4424
+ * overriding translate modules defaults
4425
+ * this works because providers are singletons
4426
+ */
4427
+ {
4428
+ provide: TranslateLoader,
4429
+ useClass: EoxTranslateJsonLoader,
4430
+ deps: [HttpClient, CORE_CONFIG]
4431
+ },
4432
+ {
4433
+ provide: MissingTranslationHandler,
4434
+ useClass: EoxMissingTranslationHandler
4435
+ },
4436
+ { provide: OAuthStorage, useFactory: storageFactory },
4437
+ provideHttpClient(withInterceptorsFromDi())
4438
+ ], imports: [OAuthModule.forRoot({
4439
+ resourceServer: {
4440
+ sendAccessToken: false,
4441
+ allowedUrls: []
4442
+ }
4443
+ }),
4444
+ TranslateModule.forRoot(), YuvClientCoreSharedModule] }); }
4445
+ }
4446
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: YuvClientCoreModule, decorators: [{
4447
+ type: NgModule,
4448
+ args: [{
4449
+ exports: [YuvClientCoreSharedModule],
4450
+ imports: [OAuthModule.forRoot({
4451
+ resourceServer: {
4452
+ sendAccessToken: false,
4453
+ allowedUrls: []
4454
+ }
4455
+ }),
4456
+ TranslateModule.forRoot()], providers: [
4457
+ { provide: Logger, useClass: LoggerConsoleService },
4458
+ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
4459
+ { provide: HTTP_INTERCEPTORS, useClass: OfflineInterceptor, multi: true },
4460
+ { provide: CORE_CONFIG, useClass: CoreConfig, deps: [CUSTOM_CONFIG] },
4461
+ {
4462
+ provide: APP_INITIALIZER,
4463
+ useFactory: init_moduleFnc,
4464
+ multi: true,
4465
+ deps: [CORE_CONFIG, DeviceService, Logger, HttpClient, ConfigService, AuthService]
4466
+ },
4467
+ /**
4468
+ * overriding translate modules defaults
4469
+ * this works because providers are singletons
4470
+ */
4471
+ {
4472
+ provide: TranslateLoader,
4473
+ useClass: EoxTranslateJsonLoader,
4474
+ deps: [HttpClient, CORE_CONFIG]
4475
+ },
4476
+ {
4477
+ provide: MissingTranslationHandler,
4478
+ useClass: EoxMissingTranslationHandler
4479
+ },
4480
+ { provide: OAuthStorage, useFactory: storageFactory },
4481
+ provideHttpClient(withInterceptorsFromDi())
4482
+ ]
4483
+ }]
4484
+ }], ctorParameters: () => [{ type: YuvClientCoreModule, decorators: [{
4485
+ type: Optional
4486
+ }, {
4487
+ type: SkipSelf
4488
+ }] }] });
4489
+
4490
+ /**
4491
+ * @ignore
4492
+ */
4493
+ class LocaleDecimalPipe extends DecimalPipe {
4494
+ constructor(translate) {
4495
+ super(translate.currentLang || 'en');
4496
+ this.translate = translate;
4497
+ }
4498
+ transform(value, digits, locale) {
4499
+ return super.transform(value, digits, locale || this.translate.currentLang || 'en');
4500
+ }
4501
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocaleDecimalPipe, deps: [{ token: i1$1.TranslateService }], target: i0.ɵɵFactoryTarget.Pipe }); }
4502
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: LocaleDecimalPipe, isStandalone: true, name: "localeDecimal" }); }
4503
+ }
4504
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocaleDecimalPipe, decorators: [{
4505
+ type: Pipe,
4506
+ args: [{
4507
+ name: 'localeDecimal',
4508
+ standalone: true
4509
+ }]
4510
+ }], ctorParameters: () => [{ type: i1$1.TranslateService }] });
4511
+ /**
4512
+ * @ignore
4513
+ */
4514
+ class LocalePercentPipe extends PercentPipe {
4515
+ constructor(translate) {
4516
+ super(translate.currentLang || 'en');
4517
+ this.translate = translate;
4518
+ }
4519
+ transform(value, digits, locale) {
4520
+ return super.transform(value, digits, locale || this.translate.currentLang || 'en');
4521
+ }
4522
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocalePercentPipe, deps: [{ token: i1$1.TranslateService }], target: i0.ɵɵFactoryTarget.Pipe }); }
4523
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: LocalePercentPipe, isStandalone: true, name: "localePercent", pure: false }); }
4524
+ }
4525
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocalePercentPipe, decorators: [{
4526
+ type: Pipe,
4527
+ args: [{
4528
+ name: 'localePercent',
4529
+ pure: false,
4530
+ standalone: true
4531
+ }]
4532
+ }], ctorParameters: () => [{ type: i1$1.TranslateService }] });
4533
+ /**
4534
+ * @ignore
4535
+ */
4536
+ class LocaleCurrencyPipe extends CurrencyPipe {
4537
+ constructor(translate) {
4538
+ super(translate.currentLang || 'en');
4539
+ this.translate = translate;
4540
+ }
4541
+ transform(value, currencyCode, display, digits, locale) {
4542
+ return super.transform(value, currencyCode, display, digits, locale || this.translate.currentLang || 'en');
4543
+ }
4544
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocaleCurrencyPipe, deps: [{ token: i1$1.TranslateService }], target: i0.ɵɵFactoryTarget.Pipe }); }
4545
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: LocaleCurrencyPipe, isStandalone: true, name: "localeCurrency" }); }
4546
+ }
4547
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocaleCurrencyPipe, decorators: [{
4548
+ type: Pipe,
4549
+ args: [{
4550
+ name: 'localeCurrency',
4551
+ standalone: true
4552
+ }]
4553
+ }], ctorParameters: () => [{ type: i1$1.TranslateService }] });
4554
+ class LocaleNumberPipe {
4555
+ constructor(translate) {
4556
+ this.translate = translate;
4557
+ this.decimalSeparator = '.';
4558
+ this.separator = ',';
4559
+ this.decimalPipe = new LocaleDecimalPipe(this.translate);
4560
+ this.updateSeparators(this.translate.currentLang);
4561
+ }
4562
+ transform(value, grouping, pattern, scale, digits, locale) {
4563
+ value = Array.isArray(value) ? value[0] : value;
4564
+ let number = this.decimalPipe.transform(value, digits, locale);
4565
+ if (number && !grouping) {
4566
+ number = number.replace(new RegExp('\\' + this.separator, 'g'), '');
4567
+ }
4568
+ return number ? (pattern || '{{number}}').replace('{{number}}', number) : number;
4569
+ }
4570
+ updateSeparators(lang) {
4571
+ if (lang) {
4572
+ const pattern = this.decimalPipe.transform(1111.11, '1.2-2', lang);
4573
+ this.decimalSeparator = pattern[5];
4574
+ this.separator = pattern[1];
4575
+ }
4576
+ }
4577
+ stringToNumber(value) {
4578
+ value = (value || '').replace(new RegExp('\\' + this.separator + "|\\s|'| ", 'g'), '').replace(this.decimalSeparator, '.');
4579
+ if (typeof value === 'string' && !isNaN(Number(value) - parseFloat(value))) {
4580
+ return Number(value);
4581
+ }
4582
+ return NaN;
4583
+ }
4584
+ numberToString(value, grouping, pattern, scale) {
4585
+ value = Array.isArray(value) ? value[0] : value;
4586
+ scale = typeof scale === 'number' ? scale : 2;
4587
+ return this.transform(value, grouping, pattern, scale, `1.${scale}-${scale}`);
4588
+ }
4589
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocaleNumberPipe, deps: [{ token: i1$1.TranslateService }], target: i0.ɵɵFactoryTarget.Pipe }); }
4590
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: LocaleNumberPipe, isStandalone: true, name: "localeNumber" }); }
4591
+ }
4592
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocaleNumberPipe, decorators: [{
4593
+ type: Pipe,
4594
+ args: [{
4595
+ name: 'localeNumber',
4596
+ standalone: true
4597
+ }]
4598
+ }], ctorParameters: () => [{ type: i1$1.TranslateService }] });
4599
+
4600
+ /**
4601
+ * This pipe transforms its input (supposed to be a file size in bytes) into a more
4602
+ * human readable format like for example 1MB or 200KB.
4603
+ *
4604
+ * @example
4605
+ * <div *ngFor="let size of file | fileSize">...</div>
4606
+ */
4607
+ class FileSizePipe extends LocaleNumberPipe {
4608
+ constructor() {
4609
+ super(...arguments);
4610
+ this.k = 1024;
4611
+ this.sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
4612
+ }
4613
+ transform(bytes = 0) {
4614
+ if (bytes <= 1) {
4615
+ return bytes === 1 ? '1 Byte' : '0 Bytes';
4616
+ }
4617
+ let i = Math.floor(Math.log(bytes) / Math.log(this.k));
4618
+ return super.transform(parseFloat((bytes / Math.pow(this.k, i)).toFixed(2))) + ' ' + this.sizes[i];
4619
+ }
4620
+ stringToNumber(value) {
4621
+ const sizes = this.sizes.map((s) => s.toLowerCase());
4622
+ const match = value.toLowerCase().match(new RegExp(`(.*)(${sizes.join('|')})`));
4623
+ const number = super.stringToNumber((match ? match[1] : value).trim());
4624
+ return isNaN(number) ? number : Math.round(number * Math.pow(1024, match ? sizes.indexOf(match[2]) : 0));
4625
+ }
4626
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FileSizePipe, deps: null, target: i0.ɵɵFactoryTarget.Pipe }); }
4627
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: FileSizePipe, isStandalone: true, name: "fileSize" }); }
4628
+ }
4629
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FileSizePipe, decorators: [{
4630
+ type: Pipe,
4631
+ args: [{ name: 'fileSize', standalone: true }]
4632
+ }] });
4633
+
4634
+ const predefinedFormats = {
4635
+ short: {
4636
+ timeStyle: 'short',
4637
+ dateStyle: 'short'
4638
+ },
4639
+ medium: {
4640
+ timeStyle: 'medium',
4641
+ dateStyle: 'medium'
4642
+ },
4643
+ shortDate: {
4644
+ dateStyle: 'short'
4645
+ }
4646
+ };
4647
+ class LocaleDatePipe {
4648
+ constructor(translate) {
4649
+ this.translate = translate;
4650
+ }
4651
+ transform(value, format = 'short') {
4652
+ if (!value)
4653
+ return '';
4654
+ else {
4655
+ try {
4656
+ return new Intl.DateTimeFormat(this.translate.currentLang, predefinedFormats[format]).format(!(value instanceof Date) ? new Date(value) : value);
4657
+ }
4658
+ catch (e) {
4659
+ console.error(e);
4660
+ return '';
4661
+ }
4662
+ }
4663
+ }
4664
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocaleDatePipe, deps: [{ token: i1$1.TranslateService }], target: i0.ɵɵFactoryTarget.Pipe }); }
4665
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: LocaleDatePipe, isStandalone: true, name: "localeDate" }); }
4666
+ }
4667
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocaleDatePipe, decorators: [{
4668
+ type: Pipe,
4669
+ args: [{
4670
+ name: 'localeDate',
4671
+ standalone: true
4672
+ }]
4673
+ }], ctorParameters: () => [{ type: i1$1.TranslateService }] });
4674
+
4675
+ /**
4676
+ * This pipe bypass security and trust the given value to be safe HTML.
4677
+ * Only use this when the bound HTML is unsafe (e.g. contains script tags and the code should be executed.).
4678
+ * @example
4679
+ * <div [innerHtml]="value | safeHtml"></div>
4680
+ */
4681
+ class SafeHtmlPipe {
4682
+ constructor(sanitizer) {
4683
+ this.sanitizer = sanitizer;
4684
+ }
4685
+ transform(style) {
4686
+ return this.sanitizer.bypassSecurityTrustHtml(style);
4687
+ }
4688
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SafeHtmlPipe, deps: [{ token: i1$2.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); }
4689
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: SafeHtmlPipe, isStandalone: true, name: "safeHtml" }); }
4690
+ }
4691
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SafeHtmlPipe, decorators: [{
4692
+ type: Pipe,
4693
+ args: [{ name: 'safeHtml', standalone: true }]
4694
+ }], ctorParameters: () => [{ type: i1$2.DomSanitizer }] });
4695
+ /**
4696
+ * This pipe bypass security and trust the given value to be a safe style URL, i.e. a value that can be used in hyperlinks or img src.
4697
+ * @example
4698
+ * <iframe [src]="previewSrc | safeUrl"></iframe>
4699
+ */
4700
+ class SafeUrlPipe {
4701
+ constructor(sanitizer) {
4702
+ this.sanitizer = sanitizer;
4703
+ }
4704
+ transform(url) {
4705
+ return this.sanitizer.bypassSecurityTrustResourceUrl(url);
4706
+ }
4707
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SafeUrlPipe, deps: [{ token: i1$2.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); }
4708
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: SafeUrlPipe, isStandalone: true, name: "safeUrl" }); }
4709
+ }
4710
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SafeUrlPipe, decorators: [{
4711
+ type: Pipe,
4712
+ args: [{ name: 'safeUrl', standalone: true }]
4713
+ }], ctorParameters: () => [{ type: i1$2.DomSanitizer }] });
4714
+
4715
+ /**
4716
+ * @ignore
4717
+ */
4718
+ class KeysPipe {
4719
+ transform(value) {
4720
+ return Object.keys(value);
4721
+ }
4722
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: KeysPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
4723
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: KeysPipe, isStandalone: true, name: "keys", pure: false }); }
4724
+ }
4725
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: KeysPipe, decorators: [{
4726
+ type: Pipe,
4727
+ args: [{ name: 'keys', pure: false, standalone: true }]
4728
+ }] });
4729
+
4730
+ class NativeNotificationService {
4731
+ requestPermission() {
4732
+ if ('Notification' in window) {
4733
+ Notification.requestPermission().then((permission) => {
4734
+ if (permission === 'granted') {
4735
+ console.log('Notification permission granted.');
4736
+ }
4737
+ else {
4738
+ console.log('Notification permission denied.');
4739
+ }
4740
+ });
4741
+ }
4742
+ else {
4743
+ console.log('Notifications are not supported in this browser.');
4744
+ }
4745
+ }
4746
+ showNotification(title, options) {
4747
+ const preventBecauseTabActive = options?.preventOnTabActive && document.visibilityState === 'visible';
4748
+ if ('Notification' in window && Notification.permission === 'granted' && !preventBecauseTabActive) {
4749
+ const n = new Notification(title, options?.options);
4750
+ n.onclick = (e) => {
4751
+ window.focus();
4752
+ if (options?.onClick)
4753
+ options.onClick();
4754
+ n.close();
4755
+ };
4756
+ }
4757
+ }
4758
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NativeNotificationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4759
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NativeNotificationService, providedIn: 'root' }); }
4760
+ }
4761
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NativeNotificationService, decorators: [{
4762
+ type: Injectable,
4763
+ args: [{
4764
+ providedIn: 'root'
4765
+ }]
4766
+ }] });
4767
+
4768
+ // TOKENS
4769
+
4770
+ /**
4771
+ * Generated bundle index. Do not edit.
4772
+ */
4773
+
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 };
4775
+ //# sourceMappingURL=yuuvis-client-core.mjs.map