@arsedizioni/ars-utils 22.0.34 → 22.0.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/clipper.common/README.md +74 -74
- package/fesm2022/arsedizioni-ars-utils-clipper.common.mjs +1013 -695
- package/fesm2022/arsedizioni-ars-utils-clipper.common.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-clipper.ui.mjs +122 -152
- package/fesm2022/arsedizioni-ars-utils-clipper.ui.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-evolution.common.mjs +13 -8
- package/fesm2022/arsedizioni-ars-utils-evolution.common.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-help.mjs +5 -6
- package/fesm2022/arsedizioni-ars-utils-help.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-support.common.mjs +8 -6
- package/fesm2022/arsedizioni-ars-utils-support.common.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-support.ui.mjs +5 -7
- package/fesm2022/arsedizioni-ars-utils-support.ui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/arsedizioni-ars-utils-clipper.common.d.ts +455 -286
- package/types/arsedizioni-ars-utils-clipper.ui.d.ts +24 -17
- package/types/arsedizioni-ars-utils-evolution.common.d.ts +4 -4
- package/types/arsedizioni-ars-utils-support.common.d.ts +3 -4
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { signal, computed, inject, DestroyRef,
|
|
2
|
+
import { signal, computed, inject, Service, DestroyRef, Injector, Injectable } from '@angular/core';
|
|
3
3
|
import { HttpClient, HttpHeaders, HttpRequest, HttpErrorResponse } from '@angular/common/http';
|
|
4
|
-
import { BroadcastService,
|
|
5
|
-
import {
|
|
6
|
-
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
4
|
+
import { BroadcastService, SystemUtils, SplashService } from '@arsedizioni/ars-utils/core';
|
|
5
|
+
import { throwError, of, EMPTY, catchError as catchError$1 } from 'rxjs';
|
|
7
6
|
import { catchError, map, finalize } from 'rxjs/operators';
|
|
7
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
8
8
|
|
|
9
9
|
const ClipperMessages = {
|
|
10
10
|
/**
|
|
@@ -2191,486 +2191,119 @@ const NotesColors = [{ name: "Verde", value: "#2E8B74" },
|
|
|
2191
2191
|
{ name: "Indaco", value: "#5B6EBF" }
|
|
2192
2192
|
];
|
|
2193
2193
|
|
|
2194
|
-
|
|
2194
|
+
/**
|
|
2195
|
+
* Document search, references, export and metadata, plus the dashboard counters,
|
|
2196
|
+
* taxonomy/topics/tags lookups, the working-documents "bag" and saved searches.
|
|
2197
|
+
*/
|
|
2198
|
+
class ClipperDocumentsService {
|
|
2195
2199
|
constructor() {
|
|
2196
2200
|
this.httpClient = inject(HttpClient);
|
|
2197
|
-
this.destroyRef = inject(DestroyRef);
|
|
2198
2201
|
this.broadcastService = inject(BroadcastService);
|
|
2199
|
-
this.
|
|
2200
|
-
this.broadcastInitialized = false;
|
|
2201
|
-
this._serviceUri = '';
|
|
2202
|
-
this._flags = ClipperServiceFlags.None;
|
|
2203
|
-
this._loggedIn = signal(sessionStorage.getItem("clipper_oauth_token") !== null, /* @ts-ignore */
|
|
2204
|
-
...(ngDevMode ? [{ debugName: "_loggedIn" }] : /* istanbul ignore next */ []));
|
|
2205
|
-
this.loggedIn = this._loggedIn.asReadonly();
|
|
2206
|
-
this.loggingIn = signal(false, /* @ts-ignore */
|
|
2207
|
-
...(ngDevMode ? [{ debugName: "loggingIn" }] : /* istanbul ignore next */ []));
|
|
2208
|
-
this.snapshot = signal(undefined, /* @ts-ignore */
|
|
2209
|
-
...(ngDevMode ? [{ debugName: "snapshot" }] : /* istanbul ignore next */ []));
|
|
2210
|
-
this.supportsRS = signal(false, /* @ts-ignore */
|
|
2211
|
-
...(ngDevMode ? [{ debugName: "supportsRS" }] : /* istanbul ignore next */ []));
|
|
2212
|
-
this.referencesSnapshot = signal(undefined, /* @ts-ignore */
|
|
2213
|
-
...(ngDevMode ? [{ debugName: "referencesSnapshot" }] : /* istanbul ignore next */ []));
|
|
2214
|
-
this.dashboard = new ClipperDashboard();
|
|
2215
|
-
this.bag = signal([], /* @ts-ignore */
|
|
2216
|
-
...(ngDevMode ? [{ debugName: "bag" }] : /* istanbul ignore next */ []));
|
|
2217
|
-
this.bagTotal = computed(() => this.bag().length, /* @ts-ignore */
|
|
2218
|
-
...(ngDevMode ? [{ debugName: "bagTotal" }] : /* istanbul ignore next */ []));
|
|
2219
|
-
this.visible = signal(false, /* @ts-ignore */
|
|
2220
|
-
...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
|
|
2221
|
-
this._teams = [];
|
|
2222
|
-
this.availableChannels = signal([], /* @ts-ignore */
|
|
2223
|
-
...(ngDevMode ? [{ debugName: "availableChannels" }] : /* istanbul ignore next */ []));
|
|
2224
|
-
this.activeChannels = computed(() => {
|
|
2225
|
-
return this.availableChannels()?.filter(x => !x.suspended && !x.disabled && x.active === true);
|
|
2226
|
-
}, /* @ts-ignore */
|
|
2227
|
-
...(ngDevMode ? [{ debugName: "activeChannels" }] : /* istanbul ignore next */ []));
|
|
2228
|
-
this.allowTags = signal(false, /* @ts-ignore */
|
|
2229
|
-
...(ngDevMode ? [{ debugName: "allowTags" }] : /* istanbul ignore next */ []));
|
|
2230
|
-
this.pendingNotes = signal(undefined, /* @ts-ignore */
|
|
2231
|
-
...(ngDevMode ? [{ debugName: "pendingNotes" }] : /* istanbul ignore next */ []));
|
|
2232
|
-
}
|
|
2233
|
-
get appUri() {
|
|
2234
|
-
return this._appUri;
|
|
2202
|
+
this.core = inject(ClipperCoreService);
|
|
2235
2203
|
}
|
|
2236
|
-
|
|
2237
|
-
|
|
2204
|
+
/////
|
|
2205
|
+
// DOCUMENTS
|
|
2206
|
+
/////
|
|
2207
|
+
/**
|
|
2208
|
+
* Queries documents matching the given search parameters.
|
|
2209
|
+
* @param params - The document search parameters.
|
|
2210
|
+
* @returns An observable emitting the API result wrapping the search result.
|
|
2211
|
+
*/
|
|
2212
|
+
query(params) {
|
|
2213
|
+
return this.httpClient.post(this.core.serviceUri + '/documents', params);
|
|
2238
2214
|
}
|
|
2239
|
-
|
|
2240
|
-
|
|
2215
|
+
/**
|
|
2216
|
+
* Retrieves the facets for a document query.
|
|
2217
|
+
* @param params - The document search parameters.
|
|
2218
|
+
* @returns An observable emitting the API result wrapping the search facets.
|
|
2219
|
+
*/
|
|
2220
|
+
queryFacets(params) {
|
|
2221
|
+
return this.httpClient.post(this.core.serviceUri + '/documents/facets', params);
|
|
2241
2222
|
}
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
catch { }
|
|
2250
|
-
}
|
|
2251
|
-
}
|
|
2252
|
-
return this._loginInfo;
|
|
2223
|
+
/**
|
|
2224
|
+
* Updates the state of one or more documents.
|
|
2225
|
+
* @param params - The document state update parameters.
|
|
2226
|
+
* @returns An observable emitting the API result wrapping the number of updated documents.
|
|
2227
|
+
*/
|
|
2228
|
+
updateState(params) {
|
|
2229
|
+
return this.httpClient.post(this.core.serviceUri + '/documents/state/update', params);
|
|
2253
2230
|
}
|
|
2254
|
-
|
|
2255
|
-
|
|
2231
|
+
/**
|
|
2232
|
+
* Exports a single document in PDF format.
|
|
2233
|
+
* @param id - The ID of the document to export.
|
|
2234
|
+
* @returns An observable emitting the PDF binary content as a blob.
|
|
2235
|
+
*/
|
|
2236
|
+
exportPdf(id) {
|
|
2237
|
+
return this.httpClient.get(this.core.serviceUri + '/documents/export/' + id, { responseType: 'blob' });
|
|
2256
2238
|
}
|
|
2257
2239
|
/**
|
|
2258
|
-
*
|
|
2259
|
-
* @param
|
|
2260
|
-
* @
|
|
2261
|
-
* @param flags - Feature flags that control service behaviour. Defaults to `ClipperServiceFlags.None`.
|
|
2240
|
+
* Exports a document list (query or selected items), or exports deadlines as ICS.
|
|
2241
|
+
* @param params - The export parameters.
|
|
2242
|
+
* @returns An observable emitting the exported content as a blob.
|
|
2262
2243
|
*/
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
if (!sessionStorage.getItem('clipper_client_id')) {
|
|
2266
|
-
sessionStorage.setItem('clipper_client_id', (flags && ClipperServiceFlags.Embedded) > 0
|
|
2267
|
-
? 'embedded'
|
|
2268
|
-
: SystemUtils.generateUUID());
|
|
2269
|
-
}
|
|
2270
|
-
// Initialize
|
|
2271
|
-
this._serviceUri = serviceUri;
|
|
2272
|
-
this._appUri = appUri;
|
|
2273
|
-
this._flags = flags;
|
|
2274
|
-
// React to message broadcasting
|
|
2275
|
-
if (!this.broadcastInitialized) {
|
|
2276
|
-
this.broadcastInitialized = true;
|
|
2277
|
-
this.broadcastService.getMessage()
|
|
2278
|
-
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
2279
|
-
.subscribe(message => {
|
|
2280
|
-
if (message.id === ClipperMessages.LOGIN_CHANGED) {
|
|
2281
|
-
this.login(undefined, undefined, true, message.data?.oauth ?? undefined, message.data?.oauthAccessToken ?? undefined).subscribe({
|
|
2282
|
-
next: r => {
|
|
2283
|
-
if (!r.success) {
|
|
2284
|
-
if ((this.flags & ClipperServiceFlags.DisplayConnectionStateMessages) > 0) {
|
|
2285
|
-
this.broadcastService.sendMessage(ClipperMessages.ERROR, { message: "Le credenziali di accesso sono cambiate o non sono più valide. Esegui un nuovo accesso." });
|
|
2286
|
-
}
|
|
2287
|
-
this.broadcastService.sendMessage(ClipperMessages.LOGIN_FAILED);
|
|
2288
|
-
}
|
|
2289
|
-
else {
|
|
2290
|
-
if ((this.flags & ClipperServiceFlags.DisplayConnectionStateMessages) > 0) {
|
|
2291
|
-
this.broadcastService.sendMessage(ClipperMessages.SUCCESS_TOAST, { message: "Connesso a Clipper", icon: 'power', duration: 1500 });
|
|
2292
|
-
}
|
|
2293
|
-
// Load bag
|
|
2294
|
-
this.loadBag();
|
|
2295
|
-
}
|
|
2296
|
-
},
|
|
2297
|
-
error: () => { console.error("Clipper non disponibile."); } // Avoid unwanted errors on client
|
|
2298
|
-
});
|
|
2299
|
-
}
|
|
2300
|
-
else if (message.id === ClipperMessages.LOGOUT) {
|
|
2301
|
-
if (this.loggedIn()) {
|
|
2302
|
-
this.logout().subscribe(r => {
|
|
2303
|
-
if (!r.success) {
|
|
2304
|
-
if (r.message) {
|
|
2305
|
-
this.broadcastService.sendMessage(ClipperMessages.ERROR, { message: "<p>" + r.message + "</p><br><br><hr><p class='small'><i>Per eliminare la configurazione di Clipper accedere a:<br><b>menu > personalizza > collegamenti</b></i></p>" });
|
|
2306
|
-
}
|
|
2307
|
-
}
|
|
2308
|
-
else {
|
|
2309
|
-
if ((this.flags & ClipperServiceFlags.DisplayConnectionStateMessages) > 0) {
|
|
2310
|
-
this.broadcastService.sendMessage(ClipperMessages.SUCCESS_TOAST, { message: "Disconnesso da Clipper", icon: 'power_off', duration: 1500 });
|
|
2311
|
-
}
|
|
2312
|
-
// Empty bag
|
|
2313
|
-
this.bag.set([]);
|
|
2314
|
-
}
|
|
2315
|
-
});
|
|
2316
|
-
}
|
|
2317
|
-
else {
|
|
2318
|
-
this.clear();
|
|
2319
|
-
}
|
|
2320
|
-
}
|
|
2321
|
-
});
|
|
2322
|
-
}
|
|
2323
|
-
// Eveluate current session storage in case of page refresh (F5)
|
|
2324
|
-
if (this.loggedIn()) {
|
|
2325
|
-
// Auto login
|
|
2326
|
-
this.loggingIn.set(false);
|
|
2327
|
-
// Initialize channels
|
|
2328
|
-
this.initializeChannels();
|
|
2329
|
-
// Notify
|
|
2330
|
-
this.broadcastService.sendMessage(ClipperMessages.LOGIN_COMPLETED);
|
|
2331
|
-
}
|
|
2244
|
+
export(params) {
|
|
2245
|
+
return this.httpClient.post(this.core.serviceUri + '/documents/export', params, { responseType: 'blob' });
|
|
2332
2246
|
}
|
|
2333
2247
|
/**
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2248
|
+
* Sends document links by email.
|
|
2249
|
+
* @param params - The send-by-email parameters including recipients and documents.
|
|
2250
|
+
* @returns An observable emitting the API result wrapping the number of sent items.
|
|
2251
|
+
*/
|
|
2252
|
+
sendTo(params) {
|
|
2253
|
+
return this.httpClient.post(this.core.serviceUri + '/documents/send', params);
|
|
2340
2254
|
}
|
|
2341
2255
|
/**
|
|
2342
|
-
*
|
|
2256
|
+
* Sends an email notification about a document note update to the specified recipients.
|
|
2257
|
+
* @param params - The notification parameters including recipients and note details.
|
|
2258
|
+
* @returns An observable emitting the API result wrapping the note tracking update.
|
|
2343
2259
|
*/
|
|
2344
|
-
|
|
2345
|
-
|
|
2260
|
+
notifyNoteTo(params) {
|
|
2261
|
+
return this.httpClient.post(this.core.serviceUri + '/documents/notes/notify', params);
|
|
2346
2262
|
}
|
|
2347
2263
|
/**
|
|
2348
|
-
*
|
|
2349
|
-
* @param
|
|
2264
|
+
* Retrieves the full document report page.
|
|
2265
|
+
* @param id - The ID of the document.
|
|
2266
|
+
* @returns An observable emitting the report content as a blob.
|
|
2350
2267
|
*/
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
this._loginInfo = { context: undefined };
|
|
2354
|
-
}
|
|
2355
|
-
this._loginInfo.context = result.context;
|
|
2356
|
-
this._loginInfo.channels = result.settings;
|
|
2357
|
-
this.storeContext();
|
|
2268
|
+
report(id) {
|
|
2269
|
+
return this.httpClient.get(this.core.serviceUri + '/documents/report/' + id, { responseType: 'blob' });
|
|
2358
2270
|
}
|
|
2359
2271
|
/**
|
|
2360
|
-
*
|
|
2361
|
-
* @param
|
|
2272
|
+
* Gets the comment associated with a document.
|
|
2273
|
+
* @param id - The ID of the document.
|
|
2274
|
+
* @returns An observable emitting the API result wrapping the comment text.
|
|
2362
2275
|
*/
|
|
2363
|
-
|
|
2364
|
-
this.
|
|
2365
|
-
.subscribe({
|
|
2366
|
-
next: r => {
|
|
2367
|
-
if (!r.success) {
|
|
2368
|
-
this.broadcastService.sendMessage(ClipperMessages.ERROR, { message: r.message });
|
|
2369
|
-
}
|
|
2370
|
-
else {
|
|
2371
|
-
if (!r.value.requiresMfa) {
|
|
2372
|
-
this.broadcastService.sendMessage(ClipperMessages.SUCCESS_TOAST, { message: "Connesso a Clipper", icon: 'power', duration: 1500 });
|
|
2373
|
-
}
|
|
2374
|
-
if (onSuccess) {
|
|
2375
|
-
onSuccess(r.value);
|
|
2376
|
-
}
|
|
2377
|
-
}
|
|
2378
|
-
},
|
|
2379
|
-
error: () => { this.broadcastService.sendMessage(ClipperMessages.ERROR, { message: "Clipper non disponibile." }); }
|
|
2380
|
-
});
|
|
2276
|
+
comment(id) {
|
|
2277
|
+
return this.httpClient.get(this.core.serviceUri + '/documents/comment/' + id);
|
|
2381
2278
|
}
|
|
2382
2279
|
/**
|
|
2383
|
-
*
|
|
2384
|
-
* @param
|
|
2280
|
+
* Gets the info for a document.
|
|
2281
|
+
* @param id - The ID of the document.
|
|
2282
|
+
* @returns An observable emitting the API result wrapping the document info.
|
|
2385
2283
|
*/
|
|
2386
|
-
|
|
2387
|
-
this.
|
|
2388
|
-
.subscribe({
|
|
2389
|
-
next: r => {
|
|
2390
|
-
if (!r.success) {
|
|
2391
|
-
if (r.message) {
|
|
2392
|
-
this.broadcastService.sendMessage(ClipperMessages.ERROR, { message: r.message });
|
|
2393
|
-
}
|
|
2394
|
-
this.broadcastService.sendMessage(ClipperMessages.LOGIN_CHANGED);
|
|
2395
|
-
}
|
|
2396
|
-
else {
|
|
2397
|
-
this.broadcastService.sendMessage(ClipperMessages.SUCCESS_TOAST, { message: "Disconnesso da Clipper", icon: 'power_off', duration: 1500 });
|
|
2398
|
-
}
|
|
2399
|
-
},
|
|
2400
|
-
error: () => { },
|
|
2401
|
-
complete: () => {
|
|
2402
|
-
if (onSuccess) {
|
|
2403
|
-
onSuccess();
|
|
2404
|
-
}
|
|
2405
|
-
}
|
|
2406
|
-
});
|
|
2284
|
+
info(id) {
|
|
2285
|
+
return this.httpClient.get(this.core.serviceUri + '/documents/info/' + id);
|
|
2407
2286
|
}
|
|
2408
2287
|
/**
|
|
2409
|
-
*
|
|
2410
|
-
*
|
|
2411
|
-
* @
|
|
2412
|
-
* @param password - The user's password (credential login only).
|
|
2413
|
-
* @param remember - When `true`, the session is remembered across browser restarts.
|
|
2414
|
-
* @param oauth - The OAuth2 provider type, when authenticating via SSO.
|
|
2415
|
-
* @param oauthAccessToken - The OAuth2 bearer token. Defaults to the value stored in session storage.
|
|
2288
|
+
* Gets the structure (index) of a document.
|
|
2289
|
+
* @param id - The ID of the document.
|
|
2290
|
+
* @returns An observable emitting the API result wrapping the document structure.
|
|
2416
2291
|
*/
|
|
2417
|
-
|
|
2418
|
-
this.
|
|
2419
|
-
return this.httpClient
|
|
2420
|
-
.post(this._serviceUri + '/login2', {
|
|
2421
|
-
user: oauth ? null : email,
|
|
2422
|
-
password: oauth ? null : password,
|
|
2423
|
-
remember: remember,
|
|
2424
|
-
oauth: oauth
|
|
2425
|
-
}, {
|
|
2426
|
-
headers: !oauth || !oauthAccessToken
|
|
2427
|
-
? new HttpHeaders()
|
|
2428
|
-
: new HttpHeaders()
|
|
2429
|
-
.set("Authorization", 'Bearer ' + oauthAccessToken)
|
|
2430
|
-
})
|
|
2431
|
-
.pipe(catchError(err => {
|
|
2432
|
-
return throwError(() => err);
|
|
2433
|
-
}), map((r) => {
|
|
2434
|
-
if (r.success) {
|
|
2435
|
-
if (!this._loginInfo) {
|
|
2436
|
-
this._loginInfo = { context: undefined };
|
|
2437
|
-
}
|
|
2438
|
-
this._loginInfo.oauth = oauth;
|
|
2439
|
-
this._loginInfo.remember = remember;
|
|
2440
|
-
if (!oauth && r.value.requiresMfa) {
|
|
2441
|
-
// Notify login is pending
|
|
2442
|
-
this.broadcastService.sendMessage(ClipperMessages.LOGIN_PENDING);
|
|
2443
|
-
}
|
|
2444
|
-
else {
|
|
2445
|
-
// Complete login
|
|
2446
|
-
this.completeLogin(r.value);
|
|
2447
|
-
}
|
|
2448
|
-
}
|
|
2449
|
-
return r;
|
|
2450
|
-
}));
|
|
2292
|
+
index(id) {
|
|
2293
|
+
return this.httpClient.get(this.core.serviceUri + '/documents/structure/' + id);
|
|
2451
2294
|
}
|
|
2452
2295
|
/**
|
|
2453
|
-
*
|
|
2454
|
-
*
|
|
2455
|
-
* @
|
|
2296
|
+
* Gets the last-update metadata for a document.
|
|
2297
|
+
* @param id - The ID of the document.
|
|
2298
|
+
* @returns An observable emitting the API result wrapping the last update string and its notes.
|
|
2456
2299
|
*/
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
this.updateContext(result);
|
|
2460
|
-
this._loggedIn.set(!result.context?.isTemporary);
|
|
2461
|
-
this.loggingIn.set(false);
|
|
2462
|
-
// Initialize channels
|
|
2463
|
-
this.initializeChannels();
|
|
2464
|
-
// Notify
|
|
2465
|
-
this.broadcastService.sendMessage(ClipperMessages.LOGIN_COMPLETED);
|
|
2300
|
+
metadata(id) {
|
|
2301
|
+
return this.httpClient.get(this.core.serviceUri + '/documents/metadata/' + id);
|
|
2466
2302
|
}
|
|
2467
2303
|
/**
|
|
2468
|
-
*
|
|
2469
|
-
* @param
|
|
2470
|
-
|
|
2471
|
-
confirmIdentity(code) {
|
|
2472
|
-
return this.httpClient
|
|
2473
|
-
.post(this._serviceUri + '/login/confirm/' + code, {})
|
|
2474
|
-
.pipe(catchError((err) => {
|
|
2475
|
-
return throwError(() => err);
|
|
2476
|
-
}), map((r) => {
|
|
2477
|
-
if (r.success) {
|
|
2478
|
-
this.completeLogin(r.value);
|
|
2479
|
-
}
|
|
2480
|
-
return r;
|
|
2481
|
-
}));
|
|
2482
|
-
}
|
|
2483
|
-
/**
|
|
2484
|
-
* Logs the user out and clears the current session.
|
|
2485
|
-
* @param forget - When `true`, all stored user credentials are also removed.
|
|
2486
|
-
*/
|
|
2487
|
-
logout(forget = false) {
|
|
2488
|
-
return this.httpClient.post(this._serviceUri + '/logout/?forget=' + forget, {})
|
|
2489
|
-
.pipe(finalize(() => {
|
|
2490
|
-
this.clear(true);
|
|
2491
|
-
// Clean up
|
|
2492
|
-
localStorage.removeItem('clipper_context');
|
|
2493
|
-
}), catchError((_e) => {
|
|
2494
|
-
return of([]);
|
|
2495
|
-
}));
|
|
2496
|
-
}
|
|
2497
|
-
/**
|
|
2498
|
-
* Resets the login state, clears the stored login info, and broadcasts `LOGOUT_COMPLETED`.
|
|
2499
|
-
*/
|
|
2500
|
-
reset() {
|
|
2501
|
-
// Clear login info
|
|
2502
|
-
this._loginInfo = undefined;
|
|
2503
|
-
// Logged out
|
|
2504
|
-
this._loggedIn.set(false);
|
|
2505
|
-
// Reset channels
|
|
2506
|
-
this.availableChannels.set([]);
|
|
2507
|
-
// Notify
|
|
2508
|
-
this.broadcastService.sendMessage(ClipperMessages.LOGOUT_COMPLETED);
|
|
2509
|
-
}
|
|
2510
|
-
/**
|
|
2511
|
-
* Clears all session-storage authentication keys and resets the login state.
|
|
2512
|
-
* @param clearOAuthToken - When `true`, the OAuth bearer token is also removed.
|
|
2513
|
-
*/
|
|
2514
|
-
clear(clearOAuthToken = false) {
|
|
2515
|
-
// Clear local storage
|
|
2516
|
-
sessionStorage.removeItem('clipper_auth');
|
|
2517
|
-
sessionStorage.removeItem('clipper_oauth');
|
|
2518
|
-
if (clearOAuthToken) {
|
|
2519
|
-
sessionStorage.removeItem('clipper_oauth_token');
|
|
2520
|
-
}
|
|
2521
|
-
// Reset login
|
|
2522
|
-
this.reset();
|
|
2523
|
-
}
|
|
2524
|
-
/**
|
|
2525
|
-
* Applies a new dashboard result: updates channel settings, dashboard counters, and
|
|
2526
|
-
* re-initialises the available-channels signal.
|
|
2527
|
-
* @param value - The dashboard result containing updated channel and counter data.
|
|
2528
|
-
*/
|
|
2529
|
-
setChannelsState(value) {
|
|
2530
|
-
// Update channels
|
|
2531
|
-
if (this._loginInfo) {
|
|
2532
|
-
this._loginInfo.channels = value.channels ?? [];
|
|
2533
|
-
}
|
|
2534
|
-
// Update dashboard
|
|
2535
|
-
this.dashboard.documentUpdates = value.documentUpdates;
|
|
2536
|
-
this.dashboard.expiredDeadlines = value.expiredDeadlines;
|
|
2537
|
-
this.dashboard.expiringDeadlines = value.expiringDeadlines;
|
|
2538
|
-
this.dashboard.isTrial = value.isTrial;
|
|
2539
|
-
this.dashboard.items.set(value.items ?? []);
|
|
2540
|
-
this.broadcastService.sendMessage(ClipperMessages.COMMAND_DASHBOARD_UPDATED);
|
|
2541
|
-
this.storeContext();
|
|
2542
|
-
this.initializeChannels();
|
|
2543
|
-
}
|
|
2544
|
-
/**
|
|
2545
|
-
* Replaces the stored channel settings and re-initialises the available-channels signal.
|
|
2546
|
-
* @param channels - The new channel settings to store and activate.
|
|
2547
|
-
*/
|
|
2548
|
-
setChannels(channels) {
|
|
2549
|
-
if (this._loginInfo) {
|
|
2550
|
-
this._loginInfo.channels = channels;
|
|
2551
|
-
this.storeContext();
|
|
2552
|
-
this.initializeChannels();
|
|
2553
|
-
}
|
|
2554
|
-
}
|
|
2555
|
-
/**
|
|
2556
|
-
* Rebuilds the `availableChannels` signal from the current login context.
|
|
2557
|
-
*/
|
|
2558
|
-
initializeChannels() {
|
|
2559
|
-
if (this.loginInfo) {
|
|
2560
|
-
const channels = [];
|
|
2561
|
-
this.loginInfo.channels?.forEach(n => {
|
|
2562
|
-
const channelSubscription = this.loginInfo?.context?.channels?.find(x => x.channel === n.channelId);
|
|
2563
|
-
n.isSuspended = channelSubscription?.isSuspended === true;
|
|
2564
|
-
const channel = ClipperChannels.find(x => x.value === n.channelId);
|
|
2565
|
-
if (channel) {
|
|
2566
|
-
channel.disabled = !n.isActive;
|
|
2567
|
-
channel.suspended = n.isSuspended === true;
|
|
2568
|
-
channel.active = n.isActive === true && n.isEnabled === true;
|
|
2569
|
-
channels.push(channel);
|
|
2570
|
-
}
|
|
2571
|
-
});
|
|
2572
|
-
this.availableChannels.set(channels);
|
|
2573
|
-
}
|
|
2574
|
-
}
|
|
2575
|
-
/**
|
|
2576
|
-
* Toggles the active state of available channels based on the supplied selection list.
|
|
2577
|
-
* @param values - The selected channel items; channels absent from this list are deactivated.
|
|
2578
|
-
*/
|
|
2579
|
-
updateChannels(values) {
|
|
2580
|
-
this.availableChannels().forEach(channel => {
|
|
2581
|
-
if (!channel.disabled) {
|
|
2582
|
-
channel.active = values?.findIndex(x => x.value === channel.value) !== -1;
|
|
2583
|
-
}
|
|
2584
|
-
});
|
|
2585
|
-
}
|
|
2586
|
-
/**
|
|
2587
|
-
* Requests a new one-time password for the given repository.
|
|
2588
|
-
* @param id - The repository ID for which the OTP should be generated.
|
|
2589
|
-
*/
|
|
2590
|
-
newOTP(id) {
|
|
2591
|
-
return this.httpClient.get(this._serviceUri + '/otp/new/?id=' + id);
|
|
2592
|
-
}
|
|
2593
|
-
/**
|
|
2594
|
-
* Load Ars events calendar
|
|
2595
|
-
*/
|
|
2596
|
-
events(params) {
|
|
2597
|
-
return this.httpClient.post(this._serviceUri + '/ars/events', params);
|
|
2598
|
-
}
|
|
2599
|
-
/**
|
|
2600
|
-
* Query documents
|
|
2601
|
-
*/
|
|
2602
|
-
query(params) {
|
|
2603
|
-
return this.httpClient.post(this._serviceUri + '/documents', params);
|
|
2604
|
-
}
|
|
2605
|
-
/**
|
|
2606
|
-
* Get facets for a query
|
|
2607
|
-
*/
|
|
2608
|
-
queryFacets(params) {
|
|
2609
|
-
return this.httpClient.post(this._serviceUri + '/documents/facets', params);
|
|
2610
|
-
}
|
|
2611
|
-
/**
|
|
2612
|
-
* Update document state
|
|
2613
|
-
*/
|
|
2614
|
-
updateState(params) {
|
|
2615
|
-
return this.httpClient.post(this._serviceUri + '/documents/state/update', params);
|
|
2616
|
-
}
|
|
2617
|
-
/**
|
|
2618
|
-
* Export a document in pdf format
|
|
2619
|
-
*/
|
|
2620
|
-
exportPdf(id) {
|
|
2621
|
-
return this.httpClient.get(this._serviceUri + '/documents/export/' + id, { responseType: 'blob' });
|
|
2622
|
-
}
|
|
2623
|
-
/**
|
|
2624
|
-
* Export document list (query or selected items) or export deadlines as ics
|
|
2625
|
-
*/
|
|
2626
|
-
export(params) {
|
|
2627
|
-
return this.httpClient.post(this._serviceUri + '/documents/export', params, { responseType: 'blob' });
|
|
2628
|
-
}
|
|
2629
|
-
/**
|
|
2630
|
-
* Send documents link by email
|
|
2631
|
-
*/
|
|
2632
|
-
sendTo(params) {
|
|
2633
|
-
return this.httpClient.post(this._serviceUri + '/documents/send', params);
|
|
2634
|
-
}
|
|
2635
|
-
/**
|
|
2636
|
-
* Sends an email notification about a document note update to the specified recipients.
|
|
2637
|
-
* @param params - The notification parameters including recipients and note details.
|
|
2638
|
-
*/
|
|
2639
|
-
notifyNoteTo(params) {
|
|
2640
|
-
return this.httpClient.post(this._serviceUri + '/documents/notes/notify', params);
|
|
2641
|
-
}
|
|
2642
|
-
/**
|
|
2643
|
-
* Display a page the full document report
|
|
2644
|
-
*/
|
|
2645
|
-
report(id) {
|
|
2646
|
-
return this.httpClient.get(this._serviceUri + '/documents/report/' + id, { responseType: 'blob' });
|
|
2647
|
-
}
|
|
2648
|
-
/**
|
|
2649
|
-
* Get document comment
|
|
2650
|
-
*/
|
|
2651
|
-
comment(id) {
|
|
2652
|
-
return this.httpClient.get(this._serviceUri + '/documents/comment/' + id);
|
|
2653
|
-
}
|
|
2654
|
-
/**
|
|
2655
|
-
* Get document info
|
|
2656
|
-
*/
|
|
2657
|
-
info(id) {
|
|
2658
|
-
return this.httpClient.get(this._serviceUri + '/documents/info/' + id);
|
|
2659
|
-
}
|
|
2660
|
-
/**
|
|
2661
|
-
* Get document structure
|
|
2662
|
-
*/
|
|
2663
|
-
index(id) {
|
|
2664
|
-
return this.httpClient.get(this._serviceUri + '/documents/structure/' + id);
|
|
2665
|
-
}
|
|
2666
|
-
/**
|
|
2667
|
-
* Get document last update
|
|
2668
|
-
*/
|
|
2669
|
-
metadata(id) {
|
|
2670
|
-
return this.httpClient.get(this._serviceUri + '/documents/metadata/' + id);
|
|
2671
|
-
}
|
|
2672
|
-
/**
|
|
2673
|
-
* Query document references
|
|
2304
|
+
* Queries document references, changes or jurisprudence depending on the requested mode.
|
|
2305
|
+
* @param params - The references search parameters; `mode` defaults to `ReferencesIn`.
|
|
2306
|
+
* @returns An observable emitting the API result wrapping the search result, or `null` for an unsupported mode.
|
|
2674
2307
|
*/
|
|
2675
2308
|
references(params) {
|
|
2676
2309
|
let mode = params.mode;
|
|
@@ -2680,18 +2313,20 @@ class ClipperService {
|
|
|
2680
2313
|
case ClipperQueryReferencesMode.ReferencesIn:
|
|
2681
2314
|
case ClipperQueryReferencesMode.ReferencesOut:
|
|
2682
2315
|
params.mode = mode;
|
|
2683
|
-
return this.httpClient.post(this.
|
|
2316
|
+
return this.httpClient.post(this.core.serviceUri + '/documents/references', params);
|
|
2684
2317
|
case ClipperQueryReferencesMode.ChangesIn:
|
|
2685
2318
|
case ClipperQueryReferencesMode.ChangesOut:
|
|
2686
|
-
return this.httpClient.post(this.
|
|
2319
|
+
return this.httpClient.post(this.core.serviceUri + '/documents/changes', params);
|
|
2687
2320
|
case ClipperQueryReferencesMode.Juris:
|
|
2688
|
-
return this.httpClient.post(this.
|
|
2321
|
+
return this.httpClient.post(this.core.serviceUri + '/documents/juris', params);
|
|
2689
2322
|
default:
|
|
2690
2323
|
return null;
|
|
2691
2324
|
}
|
|
2692
2325
|
}
|
|
2693
2326
|
/**
|
|
2694
|
-
*
|
|
2327
|
+
* Retrieves the facets for a document references query.
|
|
2328
|
+
* @param params - The references search parameters; `mode` defaults to `ReferencesIn`.
|
|
2329
|
+
* @returns An observable emitting the API result wrapping the search facets, or `null` for an unsupported mode.
|
|
2695
2330
|
*/
|
|
2696
2331
|
referencesFacets(params) {
|
|
2697
2332
|
let mode = params.mode ?? ClipperQueryReferencesMode.ReferencesIn;
|
|
@@ -2699,105 +2334,77 @@ class ClipperService {
|
|
|
2699
2334
|
case ClipperQueryReferencesMode.ReferencesIn:
|
|
2700
2335
|
case ClipperQueryReferencesMode.ReferencesOut:
|
|
2701
2336
|
params.mode = mode;
|
|
2702
|
-
return this.httpClient.post(this.
|
|
2337
|
+
return this.httpClient.post(this.core.serviceUri + '/documents/references/facets', params);
|
|
2703
2338
|
case ClipperQueryReferencesMode.ChangesIn:
|
|
2704
2339
|
case ClipperQueryReferencesMode.ChangesOut:
|
|
2705
|
-
return this.httpClient.post(this.
|
|
2340
|
+
return this.httpClient.post(this.core.serviceUri + '/documents/changes/facets', params);
|
|
2706
2341
|
case ClipperQueryReferencesMode.Juris:
|
|
2707
|
-
return this.httpClient.post(this.
|
|
2342
|
+
return this.httpClient.post(this.core.serviceUri + '/documents/juris/facets', params);
|
|
2708
2343
|
default: return null;
|
|
2709
2344
|
}
|
|
2710
2345
|
}
|
|
2711
2346
|
/**
|
|
2712
|
-
*
|
|
2347
|
+
* Wraps document rendering to allow token refresh.
|
|
2348
|
+
* @returns An observable emitting the API result wrapping a boolean readiness flag.
|
|
2713
2349
|
*/
|
|
2714
2350
|
preRender() {
|
|
2715
|
-
return this.httpClient.get(this.
|
|
2351
|
+
return this.httpClient.get(this.core.serviceUri + '/documents/pre-render?nocache=' + SystemUtils.generateUUID());
|
|
2716
2352
|
}
|
|
2717
2353
|
/**
|
|
2718
|
-
*
|
|
2354
|
+
* Gets the jurisprudence articles for a document query.
|
|
2355
|
+
* @param params - The document search parameters.
|
|
2356
|
+
* @returns An observable emitting the API result wrapping the search result.
|
|
2719
2357
|
*/
|
|
2720
2358
|
jurisArticles(params) {
|
|
2721
|
-
return this.httpClient.post(this.
|
|
2359
|
+
return this.httpClient.post(this.core.serviceUri + '/documents/juris/articles', params);
|
|
2722
2360
|
}
|
|
2723
2361
|
/**
|
|
2724
|
-
|
|
2725
|
-
|
|
2362
|
+
* Gets a deadlines snapshot based on the supplied deadlines.
|
|
2363
|
+
* @param params - The calendar search parameters.
|
|
2364
|
+
* @returns An observable emitting the API result wrapping the calendar snapshot result.
|
|
2365
|
+
*/
|
|
2726
2366
|
deadlinesSnapshot(params) {
|
|
2727
|
-
return this.httpClient.post(this.
|
|
2367
|
+
return this.httpClient.post(this.core.serviceUri + '/documents/calendar/snapshot', params);
|
|
2728
2368
|
}
|
|
2729
2369
|
/**
|
|
2730
|
-
*
|
|
2370
|
+
* Retrieves the taxonomy.
|
|
2371
|
+
* @param params - Optional taxonomy parameters. Defaults to `{ model: 0, countItems: false }`.
|
|
2372
|
+
* @returns An observable emitting the API result wrapping the taxonomy folder tree.
|
|
2731
2373
|
*/
|
|
2732
2374
|
getTaxonomy(params) {
|
|
2733
|
-
return this.httpClient.post(this.
|
|
2375
|
+
return this.httpClient.post(this.core.serviceUri + '/taxonomy', params ?? { model: 0, countItems: false });
|
|
2734
2376
|
}
|
|
2735
2377
|
/**
|
|
2736
|
-
*
|
|
2378
|
+
* Retrieves the topics as a flat list.
|
|
2379
|
+
* @returns An observable emitting the API result wrapping the list of topics.
|
|
2737
2380
|
*/
|
|
2738
2381
|
getTopics() {
|
|
2739
|
-
return this.httpClient.get(this.
|
|
2382
|
+
return this.httpClient.get(this.core.serviceUri + '/topics');
|
|
2740
2383
|
}
|
|
2741
2384
|
/**
|
|
2742
|
-
|
|
2743
|
-
|
|
2385
|
+
* Retrieves the topics as a tree.
|
|
2386
|
+
* @returns An observable emitting the API result wrapping the topics folder tree.
|
|
2387
|
+
*/
|
|
2744
2388
|
getTopicsAsTree() {
|
|
2745
|
-
return this.httpClient.get(this.
|
|
2389
|
+
return this.httpClient.get(this.core.serviceUri + '/topics2');
|
|
2746
2390
|
}
|
|
2747
2391
|
/**
|
|
2748
|
-
*
|
|
2392
|
+
* Retrieves the tags.
|
|
2393
|
+
* @returns An observable emitting the API result wrapping the list of tags.
|
|
2749
2394
|
*/
|
|
2750
2395
|
getTags() {
|
|
2751
|
-
return this.httpClient.get(this.
|
|
2752
|
-
}
|
|
2753
|
-
///
|
|
2754
|
-
// DASHBOARD
|
|
2755
|
-
///
|
|
2756
|
-
/**
|
|
2757
|
-
* Retrieve current dashboard
|
|
2758
|
-
*/
|
|
2759
|
-
loadDashboard() {
|
|
2760
|
-
return this.httpClient
|
|
2761
|
-
.post(this._serviceUri + '/account/dashboard', { refreshing: true }).subscribe((r) => {
|
|
2762
|
-
if (r.success) {
|
|
2763
|
-
this.dashboard.documentUpdates = r.value.documentUpdates;
|
|
2764
|
-
this.dashboard.expiredDeadlines = r.value.expiredDeadlines;
|
|
2765
|
-
this.dashboard.expiringDeadlines = r.value.expiringDeadlines;
|
|
2766
|
-
this.dashboard.isTrial = r.value.isTrial;
|
|
2767
|
-
this.dashboard.items.set(r.value.items ?? []);
|
|
2768
|
-
this.broadcastService.sendMessage(ClipperMessages.COMMAND_DASHBOARD_UPDATED);
|
|
2769
|
-
}
|
|
2770
|
-
});
|
|
2771
|
-
}
|
|
2772
|
-
/**
|
|
2773
|
-
* Retrieves documents updated in the last 15 days for the given search parameters.
|
|
2774
|
-
* @param params - The search parameters to filter results.
|
|
2775
|
-
*/
|
|
2776
|
-
last15Days(params) {
|
|
2777
|
-
return this.httpClient.post(this._serviceUri + '/account/last-15-days', params);
|
|
2778
|
-
}
|
|
2779
|
-
/**
|
|
2780
|
-
* Adjusts the unread-item counter for the given module and broadcasts a dashboard update.
|
|
2781
|
-
* @param module - The Clipper module whose counter should be adjusted.
|
|
2782
|
-
* @param model - Optional document model to further scope the counter update.
|
|
2783
|
-
* @param increment - The signed increment to apply (use negative values to decrement).
|
|
2784
|
-
*/
|
|
2785
|
-
updateUnreadItems(module, model, increment) {
|
|
2786
|
-
increment ??= 0;
|
|
2787
|
-
if (increment !== 0) {
|
|
2788
|
-
this.dashboard.updateUnreadItems(module, model, increment);
|
|
2789
|
-
}
|
|
2790
|
-
this.broadcastService.sendMessage(ClipperMessages.COMMAND_DASHBOARD_UPDATED);
|
|
2396
|
+
return this.httpClient.get(this.core.serviceUri + '/tags');
|
|
2791
2397
|
}
|
|
2792
2398
|
///
|
|
2793
|
-
// BAG
|
|
2399
|
+
// BAG
|
|
2794
2400
|
///
|
|
2795
2401
|
/**
|
|
2796
|
-
*
|
|
2402
|
+
* Loads the working documents and populates the shared bag.
|
|
2403
|
+
* @returns The subscription to the working-documents request.
|
|
2797
2404
|
*/
|
|
2798
2405
|
loadBag() {
|
|
2799
2406
|
return this.httpClient
|
|
2800
|
-
.get(this.serviceUri + '/documents/working')
|
|
2407
|
+
.get(this.core.serviceUri + '/documents/working')
|
|
2801
2408
|
.subscribe(r => {
|
|
2802
2409
|
if (!r.success) {
|
|
2803
2410
|
this.broadcastService.sendMessage(ClipperMessages.ERROR, { message: r.message });
|
|
@@ -2819,7 +2426,7 @@ class ClipperService {
|
|
|
2819
2426
|
items.push(n);
|
|
2820
2427
|
}
|
|
2821
2428
|
});
|
|
2822
|
-
this.bag.set(items);
|
|
2429
|
+
this.core.bag.set(items);
|
|
2823
2430
|
}
|
|
2824
2431
|
}
|
|
2825
2432
|
});
|
|
@@ -2827,10 +2434,11 @@ class ClipperService {
|
|
|
2827
2434
|
/**
|
|
2828
2435
|
* Adds one or more documents to the working documents bag.
|
|
2829
2436
|
* @param documentIds - The IDs of the documents to add.
|
|
2437
|
+
* @returns The subscription to the add-to-bag request.
|
|
2830
2438
|
*/
|
|
2831
2439
|
addToBag(documentIds) {
|
|
2832
2440
|
return this.httpClient
|
|
2833
|
-
.post(this.serviceUri + '/documents/working/add', { documentIds: documentIds })
|
|
2441
|
+
.post(this.core.serviceUri + '/documents/working/add', { documentIds: documentIds })
|
|
2834
2442
|
.subscribe((r) => {
|
|
2835
2443
|
if (!r.success) {
|
|
2836
2444
|
this.broadcastService.sendMessage(ClipperMessages.LOGIN_CHANGED);
|
|
@@ -2851,7 +2459,7 @@ class ClipperService {
|
|
|
2851
2459
|
}
|
|
2852
2460
|
});
|
|
2853
2461
|
if (newItems.length > 0) {
|
|
2854
|
-
this.bag.update((values) => [...values, ...newItems]);
|
|
2462
|
+
this.core.bag.update((values) => [...values, ...newItems]);
|
|
2855
2463
|
}
|
|
2856
2464
|
this.broadcastService.sendMessage(ClipperMessages.SUCCESS_TOAST, { message: "Operazione completata con successo.", icon: 'check', duration: 1500 });
|
|
2857
2465
|
}
|
|
@@ -2861,18 +2469,19 @@ class ClipperService {
|
|
|
2861
2469
|
/**
|
|
2862
2470
|
* Removes a document from the working documents bag.
|
|
2863
2471
|
* @param documentId - The ID of the document to remove.
|
|
2472
|
+
* @returns The subscription to the remove-from-bag request.
|
|
2864
2473
|
*/
|
|
2865
2474
|
removeFromBag(documentId) {
|
|
2866
2475
|
return this.httpClient
|
|
2867
|
-
.post(this.serviceUri + '/documents/working/delete', { documentIds: [documentId] })
|
|
2476
|
+
.post(this.core.serviceUri + '/documents/working/delete', { documentIds: [documentId] })
|
|
2868
2477
|
.subscribe((r) => {
|
|
2869
2478
|
if (!r.success) {
|
|
2870
2479
|
this.broadcastService.sendMessage(ClipperMessages.ERROR, { message: r.message });
|
|
2871
2480
|
}
|
|
2872
2481
|
else {
|
|
2873
|
-
const p = this.bag().findIndex((n) => n.documentId === documentId);
|
|
2482
|
+
const p = this.core.bag().findIndex((n) => n.documentId === documentId);
|
|
2874
2483
|
if (p !== -1) {
|
|
2875
|
-
this.bag.update((values) => {
|
|
2484
|
+
this.core.bag.update((values) => {
|
|
2876
2485
|
values.splice(p, 1);
|
|
2877
2486
|
return [...values];
|
|
2878
2487
|
});
|
|
@@ -2882,128 +2491,712 @@ class ClipperService {
|
|
|
2882
2491
|
});
|
|
2883
2492
|
}
|
|
2884
2493
|
/**
|
|
2885
|
-
*
|
|
2494
|
+
* Clears all working documents from the bag.
|
|
2495
|
+
* @returns The subscription to the clear-bag request.
|
|
2886
2496
|
*/
|
|
2887
2497
|
clearBag() {
|
|
2888
2498
|
return this.httpClient
|
|
2889
|
-
.post(this.serviceUri + '/documents/working/delete', { deleteAll: true })
|
|
2499
|
+
.post(this.core.serviceUri + '/documents/working/delete', { deleteAll: true })
|
|
2890
2500
|
.subscribe((r) => {
|
|
2891
2501
|
if (!r.success) {
|
|
2892
2502
|
this.broadcastService.sendMessage(ClipperMessages.ERROR, { message: r.message });
|
|
2893
2503
|
}
|
|
2894
2504
|
else {
|
|
2895
|
-
this.bag.set([]);
|
|
2505
|
+
this.core.bag.set([]);
|
|
2896
2506
|
this.broadcastService.sendMessage(ClipperMessages.SUCCESS_TOAST, { message: "Operazione completata con successo.", icon: 'check', duration: 1500 });
|
|
2897
2507
|
}
|
|
2898
2508
|
});
|
|
2899
2509
|
}
|
|
2900
|
-
///
|
|
2901
|
-
// WORKING SEARCHES
|
|
2902
|
-
///
|
|
2903
2510
|
/**
|
|
2904
|
-
* Retrieves the saved searches for the given module.
|
|
2905
|
-
* @param module - The Clipper module whose saved searches to load.
|
|
2511
|
+
* Retrieves the saved searches for the given module.
|
|
2512
|
+
* @param module - The Clipper module whose saved searches to load.
|
|
2513
|
+
* @returns An observable emitting the API result wrapping the list of saved searches.
|
|
2514
|
+
*/
|
|
2515
|
+
loadSearches(module) {
|
|
2516
|
+
return this.httpClient
|
|
2517
|
+
.get(this.core.serviceUri + '/documents/searches/?module=' + module);
|
|
2518
|
+
}
|
|
2519
|
+
/**
|
|
2520
|
+
* Persists a user search configuration on the server.
|
|
2521
|
+
* @param params - The search configuration to save.
|
|
2522
|
+
* @returns An observable emitting the API result wrapping the saved search.
|
|
2523
|
+
*/
|
|
2524
|
+
saveSearch(params) {
|
|
2525
|
+
return this.httpClient
|
|
2526
|
+
.post(this.core.serviceUri + '/documents/searches/save', params);
|
|
2527
|
+
}
|
|
2528
|
+
/**
|
|
2529
|
+
* Deletes a saved search by its ID.
|
|
2530
|
+
* @param id - The ID of the saved search to remove.
|
|
2531
|
+
* @returns An observable emitting the API result wrapping the number of deleted searches.
|
|
2532
|
+
*/
|
|
2533
|
+
deleteSearch(id) {
|
|
2534
|
+
return this.httpClient
|
|
2535
|
+
.post(this.core.serviceUri + '/documents/searches/delete', { id: id });
|
|
2536
|
+
}
|
|
2537
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: ClipperDocumentsService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
|
|
2538
|
+
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.0.1", ngImport: i0, type: ClipperDocumentsService }); }
|
|
2539
|
+
}
|
|
2540
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: ClipperDocumentsService, decorators: [{
|
|
2541
|
+
type: Service
|
|
2542
|
+
}] });
|
|
2543
|
+
|
|
2544
|
+
/**
|
|
2545
|
+
* Authentication: credential / OAuth2 login, MFA confirmation, logout and OTP.
|
|
2546
|
+
* Shared login context, channels and the logged-in flag live in `ClipperCoreService`.
|
|
2547
|
+
*/
|
|
2548
|
+
class ClipperLoginService {
|
|
2549
|
+
constructor() {
|
|
2550
|
+
this.httpClient = inject(HttpClient);
|
|
2551
|
+
this.broadcastService = inject(BroadcastService);
|
|
2552
|
+
this.splashService = inject(SplashService);
|
|
2553
|
+
this.core = inject(ClipperCoreService);
|
|
2554
|
+
}
|
|
2555
|
+
/**
|
|
2556
|
+
* Attempts an automatic login using the credentials currently stored in session storage.
|
|
2557
|
+
* @param onSuccess - Optional callback invoked with the login result value on success.
|
|
2558
|
+
*/
|
|
2559
|
+
autoLogin(onSuccess) {
|
|
2560
|
+
this.login(undefined, undefined, true)
|
|
2561
|
+
.subscribe({
|
|
2562
|
+
next: r => {
|
|
2563
|
+
if (!r.success) {
|
|
2564
|
+
this.broadcastService.sendMessage(ClipperMessages.ERROR, { message: r.message });
|
|
2565
|
+
}
|
|
2566
|
+
else {
|
|
2567
|
+
if (!r.value.requiresMfa) {
|
|
2568
|
+
this.broadcastService.sendMessage(ClipperMessages.SUCCESS_TOAST, { message: "Connesso a Clipper", icon: 'power', duration: 1500 });
|
|
2569
|
+
}
|
|
2570
|
+
if (onSuccess) {
|
|
2571
|
+
onSuccess(r.value);
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2574
|
+
},
|
|
2575
|
+
error: () => { this.broadcastService.sendMessage(ClipperMessages.ERROR, { message: "Clipper non disponibile." }); }
|
|
2576
|
+
});
|
|
2577
|
+
}
|
|
2578
|
+
/**
|
|
2579
|
+
* Performs an automatic logout and clears the stored session.
|
|
2580
|
+
* @param onSuccess - Optional callback invoked after a successful logout.
|
|
2581
|
+
*/
|
|
2582
|
+
autoLogout(onSuccess) {
|
|
2583
|
+
this.logout()
|
|
2584
|
+
.subscribe({
|
|
2585
|
+
next: r => {
|
|
2586
|
+
if (!r.success) {
|
|
2587
|
+
if (r.message) {
|
|
2588
|
+
this.broadcastService.sendMessage(ClipperMessages.ERROR, { message: r.message });
|
|
2589
|
+
}
|
|
2590
|
+
this.broadcastService.sendMessage(ClipperMessages.LOGIN_CHANGED);
|
|
2591
|
+
}
|
|
2592
|
+
else {
|
|
2593
|
+
this.broadcastService.sendMessage(ClipperMessages.SUCCESS_TOAST, { message: "Disconnesso da Clipper", icon: 'power_off', duration: 1500 });
|
|
2594
|
+
}
|
|
2595
|
+
},
|
|
2596
|
+
error: () => { },
|
|
2597
|
+
complete: () => {
|
|
2598
|
+
if (onSuccess) {
|
|
2599
|
+
onSuccess();
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
});
|
|
2603
|
+
}
|
|
2604
|
+
/**
|
|
2605
|
+
* Authenticates the user against the Clipper API, supporting both credential-based and
|
|
2606
|
+
* OAuth2 login flows.
|
|
2607
|
+
* @param email - The user's email address (credential login only).
|
|
2608
|
+
* @param password - The user's password (credential login only).
|
|
2609
|
+
* @param remember - When `true`, the session is remembered across browser restarts.
|
|
2610
|
+
* @param oauth - The OAuth2 provider type, when authenticating via SSO.
|
|
2611
|
+
* @param oauthAccessToken - The OAuth2 bearer token. Defaults to the value stored in session storage.
|
|
2612
|
+
* @returns An observable emitting the API result wrapping the login result.
|
|
2613
|
+
*/
|
|
2614
|
+
login(email, password, remember, oauth, oauthAccessToken = sessionStorage.getItem("clipper_oauth_token") ?? undefined) {
|
|
2615
|
+
this.splashService.setMessage('Accesso in corso...');
|
|
2616
|
+
return this.httpClient
|
|
2617
|
+
.post(this.core.serviceUri + '/login2', {
|
|
2618
|
+
user: oauth ? null : email,
|
|
2619
|
+
password: oauth ? null : password,
|
|
2620
|
+
remember: remember,
|
|
2621
|
+
oauth: oauth
|
|
2622
|
+
}, {
|
|
2623
|
+
headers: !oauth || !oauthAccessToken
|
|
2624
|
+
? new HttpHeaders()
|
|
2625
|
+
: new HttpHeaders()
|
|
2626
|
+
.set("Authorization", 'Bearer ' + oauthAccessToken)
|
|
2627
|
+
})
|
|
2628
|
+
.pipe(catchError(err => {
|
|
2629
|
+
return throwError(() => err);
|
|
2630
|
+
}), map((r) => {
|
|
2631
|
+
if (r.success) {
|
|
2632
|
+
const info = this.core.ensureLoginInfo();
|
|
2633
|
+
info.oauth = oauth;
|
|
2634
|
+
info.remember = remember;
|
|
2635
|
+
if (!oauth && r.value.requiresMfa) {
|
|
2636
|
+
// Notify login is pending
|
|
2637
|
+
this.broadcastService.sendMessage(ClipperMessages.LOGIN_PENDING);
|
|
2638
|
+
}
|
|
2639
|
+
else {
|
|
2640
|
+
// Complete login
|
|
2641
|
+
this.completeLogin(r.value);
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
return r;
|
|
2645
|
+
}));
|
|
2646
|
+
}
|
|
2647
|
+
/**
|
|
2648
|
+
* Finalises the login flow by updating the stored context, setting the logged-in signal,
|
|
2649
|
+
* initialising channels, and broadcasting `LOGIN_COMPLETED`.
|
|
2650
|
+
* @param result - The login result returned by the API.
|
|
2651
|
+
*/
|
|
2652
|
+
completeLogin(result) {
|
|
2653
|
+
// Update context info
|
|
2654
|
+
this.core.updateContext(result);
|
|
2655
|
+
this.core.setLoggedIn(!result.context?.isTemporary);
|
|
2656
|
+
this.core.loggingIn.set(false);
|
|
2657
|
+
// Initialize channels
|
|
2658
|
+
this.core.initializeChannels();
|
|
2659
|
+
// Notify
|
|
2660
|
+
this.broadcastService.sendMessage(ClipperMessages.LOGIN_COMPLETED);
|
|
2661
|
+
}
|
|
2662
|
+
/**
|
|
2663
|
+
* Submits the MFA confirmation code to complete a two-factor login flow.
|
|
2664
|
+
* @param code - The one-time confirmation code provided to the user.
|
|
2665
|
+
* @returns An observable emitting the API result wrapping the login result.
|
|
2666
|
+
*/
|
|
2667
|
+
confirmIdentity(code) {
|
|
2668
|
+
return this.httpClient
|
|
2669
|
+
.post(this.core.serviceUri + '/login/confirm/' + code, {})
|
|
2670
|
+
.pipe(catchError((err) => {
|
|
2671
|
+
return throwError(() => err);
|
|
2672
|
+
}), map((r) => {
|
|
2673
|
+
if (r.success) {
|
|
2674
|
+
this.completeLogin(r.value);
|
|
2675
|
+
}
|
|
2676
|
+
return r;
|
|
2677
|
+
}));
|
|
2678
|
+
}
|
|
2679
|
+
/**
|
|
2680
|
+
* Logs the user out and clears the current session.
|
|
2681
|
+
* @param forget - When `true`, all stored user credentials are also removed.
|
|
2682
|
+
* @returns An observable that completes once the logout request has been processed.
|
|
2683
|
+
*/
|
|
2684
|
+
logout(forget = false) {
|
|
2685
|
+
return this.httpClient.post(this.core.serviceUri + '/logout/?forget=' + forget, {})
|
|
2686
|
+
.pipe(finalize(() => {
|
|
2687
|
+
this.core.clear(true);
|
|
2688
|
+
// Clean up
|
|
2689
|
+
localStorage.removeItem('clipper_context');
|
|
2690
|
+
}), catchError((_e) => {
|
|
2691
|
+
return of([]);
|
|
2692
|
+
}));
|
|
2693
|
+
}
|
|
2694
|
+
/**
|
|
2695
|
+
* Requests a new one-time password for the given repository.
|
|
2696
|
+
* @param id - The repository ID for which the OTP should be generated.
|
|
2697
|
+
* @returns An observable emitting the API result wrapping the generated OTP info.
|
|
2698
|
+
*/
|
|
2699
|
+
newOTP(id) {
|
|
2700
|
+
return this.httpClient.get(this.core.serviceUri + '/otp/new/?id=' + id);
|
|
2701
|
+
}
|
|
2702
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: ClipperLoginService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
|
|
2703
|
+
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.0.1", ngImport: i0, type: ClipperLoginService }); }
|
|
2704
|
+
}
|
|
2705
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: ClipperLoginService, decorators: [{
|
|
2706
|
+
type: Service
|
|
2707
|
+
}] });
|
|
2708
|
+
|
|
2709
|
+
/**
|
|
2710
|
+
* Shared state and bootstrap for the Clipper application.
|
|
2711
|
+
*
|
|
2712
|
+
* Holds every piece of state used by more than one feature service (service URI,
|
|
2713
|
+
* flags, login context, teams, dashboard, working-documents bag, channels and the
|
|
2714
|
+
* various UI signals) plus the low-level helpers that mutate that state.
|
|
2715
|
+
*
|
|
2716
|
+
* The feature services (`ClipperLoginService`, `ClipperDocumentsService`, ...) inject
|
|
2717
|
+
* this service to read shared state and call shared helpers. `ClipperService` (the
|
|
2718
|
+
* barrel/facade) re-exports the state declared here.
|
|
2719
|
+
*/
|
|
2720
|
+
class ClipperCoreService {
|
|
2721
|
+
constructor() {
|
|
2722
|
+
this.httpClient = inject(HttpClient);
|
|
2723
|
+
this.destroyRef = inject(DestroyRef);
|
|
2724
|
+
this.broadcastService = inject(BroadcastService);
|
|
2725
|
+
/** Used to lazily resolve feature services inside `initialize`, avoiding circular DI. */
|
|
2726
|
+
this.injector = inject(Injector);
|
|
2727
|
+
this.broadcastInitialized = false;
|
|
2728
|
+
this._serviceUri = '';
|
|
2729
|
+
this._flags = ClipperServiceFlags.None;
|
|
2730
|
+
this._loggedIn = signal(sessionStorage.getItem("clipper_oauth_token") !== null, /* @ts-ignore */
|
|
2731
|
+
...(ngDevMode ? [{ debugName: "_loggedIn" }] : /* istanbul ignore next */ []));
|
|
2732
|
+
this.loggedIn = this._loggedIn.asReadonly();
|
|
2733
|
+
this.loggingIn = signal(false, /* @ts-ignore */
|
|
2734
|
+
...(ngDevMode ? [{ debugName: "loggingIn" }] : /* istanbul ignore next */ []));
|
|
2735
|
+
this.snapshot = signal(undefined, /* @ts-ignore */
|
|
2736
|
+
...(ngDevMode ? [{ debugName: "snapshot" }] : /* istanbul ignore next */ []));
|
|
2737
|
+
this.supportsRS = signal(false, /* @ts-ignore */
|
|
2738
|
+
...(ngDevMode ? [{ debugName: "supportsRS" }] : /* istanbul ignore next */ []));
|
|
2739
|
+
this.referencesSnapshot = signal(undefined, /* @ts-ignore */
|
|
2740
|
+
...(ngDevMode ? [{ debugName: "referencesSnapshot" }] : /* istanbul ignore next */ []));
|
|
2741
|
+
this.dashboard = new ClipperDashboard();
|
|
2742
|
+
this.bag = signal([], /* @ts-ignore */
|
|
2743
|
+
...(ngDevMode ? [{ debugName: "bag" }] : /* istanbul ignore next */ []));
|
|
2744
|
+
this.bagTotal = computed(() => this.bag().length, /* @ts-ignore */
|
|
2745
|
+
...(ngDevMode ? [{ debugName: "bagTotal" }] : /* istanbul ignore next */ []));
|
|
2746
|
+
this.visible = signal(false, /* @ts-ignore */
|
|
2747
|
+
...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
|
|
2748
|
+
this._teams = [];
|
|
2749
|
+
this.availableChannels = signal([], /* @ts-ignore */
|
|
2750
|
+
...(ngDevMode ? [{ debugName: "availableChannels" }] : /* istanbul ignore next */ []));
|
|
2751
|
+
this.activeChannels = computed(() => {
|
|
2752
|
+
return this.availableChannels()?.filter(x => !x.suspended && !x.disabled && x.active === true);
|
|
2753
|
+
}, /* @ts-ignore */
|
|
2754
|
+
...(ngDevMode ? [{ debugName: "activeChannels" }] : /* istanbul ignore next */ []));
|
|
2755
|
+
this.allowTags = signal(false, /* @ts-ignore */
|
|
2756
|
+
...(ngDevMode ? [{ debugName: "allowTags" }] : /* istanbul ignore next */ []));
|
|
2757
|
+
this.pendingNotes = signal(undefined, /* @ts-ignore */
|
|
2758
|
+
...(ngDevMode ? [{ debugName: "pendingNotes" }] : /* istanbul ignore next */ []));
|
|
2759
|
+
}
|
|
2760
|
+
/** @returns The URI of the Clipper web application, or `undefined` if not set. */
|
|
2761
|
+
get appUri() {
|
|
2762
|
+
return this._appUri;
|
|
2763
|
+
}
|
|
2764
|
+
/** @returns The base URI of the Clipper REST API. */
|
|
2765
|
+
get serviceUri() {
|
|
2766
|
+
return this._serviceUri;
|
|
2767
|
+
}
|
|
2768
|
+
/** @returns The active feature flags. */
|
|
2769
|
+
get flags() {
|
|
2770
|
+
return this._flags;
|
|
2771
|
+
}
|
|
2772
|
+
/**
|
|
2773
|
+
* Lazily loads the login context from `localStorage` on first access.
|
|
2774
|
+
* @returns The current login context, or `undefined` if not authenticated.
|
|
2775
|
+
*/
|
|
2776
|
+
get loginInfo() {
|
|
2777
|
+
if (!this._loginInfo) {
|
|
2778
|
+
const loginInfo = localStorage.getItem('clipper_context');
|
|
2779
|
+
if (loginInfo) {
|
|
2780
|
+
try {
|
|
2781
|
+
this._loginInfo = JSON.parse(loginInfo);
|
|
2782
|
+
}
|
|
2783
|
+
catch { }
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
return this._loginInfo;
|
|
2787
|
+
}
|
|
2788
|
+
/** @returns The shared teams collection. */
|
|
2789
|
+
get teams() {
|
|
2790
|
+
return this._teams;
|
|
2791
|
+
}
|
|
2792
|
+
////
|
|
2793
|
+
// SHARED MUTATORS
|
|
2794
|
+
////
|
|
2795
|
+
/**
|
|
2796
|
+
* Ensures a login-info object exists and returns it for further mutation.
|
|
2797
|
+
* Replaces the inline `if (!this._loginInfo) { ... }` guards now that the field
|
|
2798
|
+
* is private to this service.
|
|
2799
|
+
* @returns The existing login-info object, or a freshly created empty one.
|
|
2800
|
+
*/
|
|
2801
|
+
ensureLoginInfo() {
|
|
2802
|
+
if (!this._loginInfo) {
|
|
2803
|
+
this._loginInfo = { context: undefined };
|
|
2804
|
+
}
|
|
2805
|
+
return this._loginInfo;
|
|
2806
|
+
}
|
|
2807
|
+
/**
|
|
2808
|
+
* Sets the logged-in state. The backing signal is read-only to consumers, so the
|
|
2809
|
+
* feature services use this method instead.
|
|
2810
|
+
* @param value - The new logged-in state.
|
|
2811
|
+
*/
|
|
2812
|
+
setLoggedIn(value) {
|
|
2813
|
+
this._loggedIn.set(value);
|
|
2814
|
+
}
|
|
2815
|
+
/**
|
|
2816
|
+
* Replaces the shared teams collection (populated by the calendar, archive and
|
|
2817
|
+
* collaboration queries).
|
|
2818
|
+
* @param teams - The teams to store.
|
|
2819
|
+
*/
|
|
2820
|
+
setTeams(teams) {
|
|
2821
|
+
this._teams = teams;
|
|
2822
|
+
}
|
|
2823
|
+
/**
|
|
2824
|
+
* Persists the current login context to `localStorage`.
|
|
2825
|
+
*/
|
|
2826
|
+
storeContext() {
|
|
2827
|
+
localStorage.setItem('clipper_context', JSON.stringify(this._loginInfo));
|
|
2828
|
+
}
|
|
2829
|
+
/**
|
|
2830
|
+
* Updates the stored login context with the values from a fresh login result.
|
|
2831
|
+
* @param result - The login result containing the new user context and channel settings.
|
|
2832
|
+
*/
|
|
2833
|
+
updateContext(result) {
|
|
2834
|
+
const info = this.ensureLoginInfo();
|
|
2835
|
+
info.context = result.context;
|
|
2836
|
+
info.channels = result.settings;
|
|
2837
|
+
this.storeContext();
|
|
2838
|
+
}
|
|
2839
|
+
/**
|
|
2840
|
+
* Rebuilds the `availableChannels` signal from the current login context.
|
|
2841
|
+
*/
|
|
2842
|
+
initializeChannels() {
|
|
2843
|
+
if (this.loginInfo) {
|
|
2844
|
+
const channels = [];
|
|
2845
|
+
this.loginInfo.channels?.forEach(n => {
|
|
2846
|
+
const channelSubscription = this.loginInfo?.context?.channels?.find(x => x.channel === n.channelId);
|
|
2847
|
+
n.isSuspended = channelSubscription?.isSuspended === true;
|
|
2848
|
+
const channel = ClipperChannels.find(x => x.value === n.channelId);
|
|
2849
|
+
if (channel) {
|
|
2850
|
+
channel.disabled = !n.isActive;
|
|
2851
|
+
channel.suspended = n.isSuspended === true;
|
|
2852
|
+
channel.active = n.isActive === true && n.isEnabled === true;
|
|
2853
|
+
channels.push(channel);
|
|
2854
|
+
}
|
|
2855
|
+
});
|
|
2856
|
+
this.availableChannels.set(channels);
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
/**
|
|
2860
|
+
* Resets the login state, clears the stored login info, and broadcasts `LOGOUT_COMPLETED`.
|
|
2861
|
+
*/
|
|
2862
|
+
reset() {
|
|
2863
|
+
// Clear login info
|
|
2864
|
+
this._loginInfo = undefined;
|
|
2865
|
+
// Logged out
|
|
2866
|
+
this._loggedIn.set(false);
|
|
2867
|
+
// Reset channels
|
|
2868
|
+
this.availableChannels.set([]);
|
|
2869
|
+
// Notify
|
|
2870
|
+
this.broadcastService.sendMessage(ClipperMessages.LOGOUT_COMPLETED);
|
|
2871
|
+
}
|
|
2872
|
+
/**
|
|
2873
|
+
* Clears all session-storage authentication keys and resets the login state.
|
|
2874
|
+
* @param clearOAuthToken - When `true`, the OAuth bearer token is also removed.
|
|
2875
|
+
*/
|
|
2876
|
+
clear(clearOAuthToken = false) {
|
|
2877
|
+
// Clear local storage
|
|
2878
|
+
sessionStorage.removeItem('clipper_auth');
|
|
2879
|
+
sessionStorage.removeItem('clipper_oauth');
|
|
2880
|
+
if (clearOAuthToken) {
|
|
2881
|
+
sessionStorage.removeItem('clipper_oauth_token');
|
|
2882
|
+
}
|
|
2883
|
+
// Reset login
|
|
2884
|
+
this.reset();
|
|
2885
|
+
}
|
|
2886
|
+
////
|
|
2887
|
+
// BOOTSTRAP
|
|
2888
|
+
////
|
|
2889
|
+
/**
|
|
2890
|
+
* Initialises the service with the API base URI, optional app URI, and feature flags.
|
|
2891
|
+
* @param serviceUri - The base URI of the Clipper REST API.
|
|
2892
|
+
* @param appUri - Optional URI of the Clipper web application (used to build document links).
|
|
2893
|
+
* @param flags - Feature flags that control service behaviour. Defaults to `ClipperServiceFlags.None`.
|
|
2894
|
+
*/
|
|
2895
|
+
initialize(serviceUri, appUri, flags = ClipperServiceFlags.None) {
|
|
2896
|
+
// Create unique client and machine id
|
|
2897
|
+
if (!sessionStorage.getItem('clipper_client_id')) {
|
|
2898
|
+
sessionStorage.setItem('clipper_client_id', (flags && ClipperServiceFlags.Embedded) > 0
|
|
2899
|
+
? 'embedded'
|
|
2900
|
+
: SystemUtils.generateUUID());
|
|
2901
|
+
}
|
|
2902
|
+
// Initialize
|
|
2903
|
+
this._serviceUri = serviceUri;
|
|
2904
|
+
this._appUri = appUri;
|
|
2905
|
+
this._flags = flags;
|
|
2906
|
+
// React to message broadcasting
|
|
2907
|
+
if (!this.broadcastInitialized) {
|
|
2908
|
+
this.broadcastInitialized = true;
|
|
2909
|
+
this.broadcastService.getMessage()
|
|
2910
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
2911
|
+
.subscribe(message => {
|
|
2912
|
+
if (message.id === ClipperMessages.LOGIN_CHANGED) {
|
|
2913
|
+
this.injector.get(ClipperLoginService).login(undefined, undefined, true, message.data?.oauth ?? undefined, message.data?.oauthAccessToken ?? undefined).subscribe({
|
|
2914
|
+
next: r => {
|
|
2915
|
+
if (!r.success) {
|
|
2916
|
+
if ((this.flags & ClipperServiceFlags.DisplayConnectionStateMessages) > 0) {
|
|
2917
|
+
this.broadcastService.sendMessage(ClipperMessages.ERROR, { message: "Le credenziali di accesso sono cambiate o non sono più valide. Esegui un nuovo accesso." });
|
|
2918
|
+
}
|
|
2919
|
+
this.broadcastService.sendMessage(ClipperMessages.LOGIN_FAILED);
|
|
2920
|
+
}
|
|
2921
|
+
else {
|
|
2922
|
+
if ((this.flags & ClipperServiceFlags.DisplayConnectionStateMessages) > 0) {
|
|
2923
|
+
this.broadcastService.sendMessage(ClipperMessages.SUCCESS_TOAST, { message: "Connesso a Clipper", icon: 'power', duration: 1500 });
|
|
2924
|
+
}
|
|
2925
|
+
// Load bag
|
|
2926
|
+
this.injector.get(ClipperDocumentsService).loadBag();
|
|
2927
|
+
}
|
|
2928
|
+
},
|
|
2929
|
+
error: () => { console.error("Clipper non disponibile."); } // Avoid unwanted errors on client
|
|
2930
|
+
});
|
|
2931
|
+
}
|
|
2932
|
+
else if (message.id === ClipperMessages.LOGOUT) {
|
|
2933
|
+
if (this.loggedIn()) {
|
|
2934
|
+
this.injector.get(ClipperLoginService).logout().subscribe(r => {
|
|
2935
|
+
if (!r.success) {
|
|
2936
|
+
if (r.message) {
|
|
2937
|
+
this.broadcastService.sendMessage(ClipperMessages.ERROR, { message: "<p>" + r.message + "</p><br><br><hr><p class='small'><i>Per eliminare la configurazione di Clipper accedere a:<br><b>menu > personalizza > collegamenti</b></i></p>" });
|
|
2938
|
+
}
|
|
2939
|
+
}
|
|
2940
|
+
else {
|
|
2941
|
+
if ((this.flags & ClipperServiceFlags.DisplayConnectionStateMessages) > 0) {
|
|
2942
|
+
this.broadcastService.sendMessage(ClipperMessages.SUCCESS_TOAST, { message: "Disconnesso da Clipper", icon: 'power_off', duration: 1500 });
|
|
2943
|
+
}
|
|
2944
|
+
// Empty bag
|
|
2945
|
+
this.bag.set([]);
|
|
2946
|
+
}
|
|
2947
|
+
});
|
|
2948
|
+
}
|
|
2949
|
+
else {
|
|
2950
|
+
this.clear();
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
});
|
|
2954
|
+
}
|
|
2955
|
+
// Eveluate current session storage in case of page refresh (F5)
|
|
2956
|
+
if (this.loggedIn()) {
|
|
2957
|
+
// Auto login
|
|
2958
|
+
this.loggingIn.set(false);
|
|
2959
|
+
// Initialize channels
|
|
2960
|
+
this.initializeChannels();
|
|
2961
|
+
// Notify
|
|
2962
|
+
this.broadcastService.sendMessage(ClipperMessages.LOGIN_COMPLETED);
|
|
2963
|
+
}
|
|
2964
|
+
}
|
|
2965
|
+
/**
|
|
2966
|
+
* Ping
|
|
2967
|
+
*/
|
|
2968
|
+
ping() {
|
|
2969
|
+
this.httpClient.get(this._serviceUri + '/ping?nocache=' + SystemUtils.generateUUID())
|
|
2970
|
+
.pipe(catchError(() => { return EMPTY; }))
|
|
2971
|
+
.subscribe();
|
|
2972
|
+
}
|
|
2973
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: ClipperCoreService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
|
|
2974
|
+
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.0.1", ngImport: i0, type: ClipperCoreService }); }
|
|
2975
|
+
}
|
|
2976
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: ClipperCoreService, decorators: [{
|
|
2977
|
+
type: Service
|
|
2978
|
+
}] });
|
|
2979
|
+
|
|
2980
|
+
/**
|
|
2981
|
+
* Account management: password reset/recovery, settings, channel activation, trial info
|
|
2982
|
+
* and user links. Channel state lives in `ClipperCoreService`; the channel-mutating
|
|
2983
|
+
* helpers (`setChannels`, `setChannelsState`, `updateChannels`) live here.
|
|
2984
|
+
*/
|
|
2985
|
+
class ClipperAccountService {
|
|
2986
|
+
constructor() {
|
|
2987
|
+
this.httpClient = inject(HttpClient);
|
|
2988
|
+
this.broadcastService = inject(BroadcastService);
|
|
2989
|
+
this.core = inject(ClipperCoreService);
|
|
2990
|
+
}
|
|
2991
|
+
/**
|
|
2992
|
+
* Resets the user's password using the provided parameters.
|
|
2993
|
+
* @param params - The new password and confirmation data.
|
|
2994
|
+
* @returns An observable emitting the API result wrapping the reset password payload.
|
|
2995
|
+
*/
|
|
2996
|
+
resetPassword(params) {
|
|
2997
|
+
return this.httpClient.post(this.core.serviceUri + '/account/password/reset', params);
|
|
2998
|
+
}
|
|
2999
|
+
/**
|
|
3000
|
+
* Initiates a password recovery flow by sending a reset link to the user's email.
|
|
3001
|
+
* @param params - The password recovery request data.
|
|
3002
|
+
* @returns An observable emitting the API result wrapping a boolean success flag.
|
|
2906
3003
|
*/
|
|
2907
|
-
|
|
2908
|
-
return this.httpClient
|
|
2909
|
-
.get(this.serviceUri + '/documents/searches/?module=' + module);
|
|
3004
|
+
recoverPassword(params) {
|
|
3005
|
+
return this.httpClient.post(this.core.serviceUri + '/account/password/recover', params);
|
|
2910
3006
|
}
|
|
2911
3007
|
/**
|
|
2912
|
-
*
|
|
2913
|
-
* @
|
|
3008
|
+
* Gets the current user account settings.
|
|
3009
|
+
* @returns An observable emitting the API result wrapping the account settings.
|
|
2914
3010
|
*/
|
|
2915
|
-
|
|
2916
|
-
return this.httpClient
|
|
2917
|
-
.post(this.serviceUri + '/documents/searches/save', params);
|
|
3011
|
+
getSettings() {
|
|
3012
|
+
return this.httpClient.get(this.core.serviceUri + '/account/settings');
|
|
2918
3013
|
}
|
|
2919
3014
|
/**
|
|
2920
|
-
*
|
|
2921
|
-
* @param
|
|
3015
|
+
* Updates user account settings and applies any channel configuration changes.
|
|
3016
|
+
* @param params - A map of settings key-value pairs to update.
|
|
3017
|
+
* @returns An observable emitting the API result wrapping a boolean success flag.
|
|
2922
3018
|
*/
|
|
2923
|
-
|
|
2924
|
-
return this.httpClient
|
|
2925
|
-
|
|
3019
|
+
updateSettings(params) {
|
|
3020
|
+
return this.httpClient.post(this.core.serviceUri + '/account/settings/update', params).pipe(map(r => {
|
|
3021
|
+
if (r.success) {
|
|
3022
|
+
if (params.channels) {
|
|
3023
|
+
this.setChannels(params.channels);
|
|
3024
|
+
}
|
|
3025
|
+
}
|
|
3026
|
+
return r;
|
|
3027
|
+
}));
|
|
2926
3028
|
}
|
|
2927
|
-
///
|
|
2928
|
-
// CALENDAR
|
|
2929
|
-
///
|
|
2930
3029
|
/**
|
|
2931
|
-
*
|
|
3030
|
+
* Saves updated channel activation states to the server and applies the new dashboard result.
|
|
3031
|
+
* @param params - The channel state update parameters.
|
|
3032
|
+
* @returns An observable emitting the API result wrapping the dashboard result.
|
|
2932
3033
|
*/
|
|
2933
|
-
|
|
2934
|
-
return this.httpClient.post(this.
|
|
2935
|
-
.pipe(map((r) => {
|
|
2936
|
-
// Store teams
|
|
3034
|
+
updateChannelsState(params) {
|
|
3035
|
+
return this.httpClient.post(this.core.serviceUri + '/account/settings/channels/update', params).pipe(map(r => {
|
|
2937
3036
|
if (r.success) {
|
|
2938
|
-
this.
|
|
3037
|
+
this.setChannelsState(r.value);
|
|
2939
3038
|
}
|
|
2940
3039
|
return r;
|
|
2941
3040
|
}));
|
|
2942
3041
|
}
|
|
2943
3042
|
/**
|
|
2944
|
-
*
|
|
3043
|
+
* Applies a new dashboard result: updates channel settings, dashboard counters, and
|
|
3044
|
+
* re-initialises the available-channels signal.
|
|
3045
|
+
* @param value - The dashboard result containing updated channel and counter data.
|
|
2945
3046
|
*/
|
|
2946
|
-
|
|
2947
|
-
|
|
3047
|
+
setChannelsState(value) {
|
|
3048
|
+
// Update channels
|
|
3049
|
+
const info = this.core.loginInfo;
|
|
3050
|
+
if (info) {
|
|
3051
|
+
info.channels = value.channels ?? [];
|
|
3052
|
+
}
|
|
3053
|
+
// Update dashboard
|
|
3054
|
+
this.core.dashboard.documentUpdates = value.documentUpdates;
|
|
3055
|
+
this.core.dashboard.expiredDeadlines = value.expiredDeadlines;
|
|
3056
|
+
this.core.dashboard.expiringDeadlines = value.expiringDeadlines;
|
|
3057
|
+
this.core.dashboard.isTrial = value.isTrial;
|
|
3058
|
+
this.core.dashboard.items.set(value.items ?? []);
|
|
3059
|
+
this.broadcastService.sendMessage(ClipperMessages.COMMAND_DASHBOARD_UPDATED);
|
|
3060
|
+
this.core.storeContext();
|
|
3061
|
+
this.core.initializeChannels();
|
|
2948
3062
|
}
|
|
2949
3063
|
/**
|
|
2950
|
-
*
|
|
2951
|
-
* @param
|
|
3064
|
+
* Replaces the stored channel settings and re-initialises the available-channels signal.
|
|
3065
|
+
* @param channels - The new channel settings to store and activate.
|
|
2952
3066
|
*/
|
|
2953
|
-
|
|
2954
|
-
|
|
3067
|
+
setChannels(channels) {
|
|
3068
|
+
const info = this.core.loginInfo;
|
|
3069
|
+
if (info) {
|
|
3070
|
+
info.channels = channels;
|
|
3071
|
+
this.core.storeContext();
|
|
3072
|
+
this.core.initializeChannels();
|
|
3073
|
+
}
|
|
2955
3074
|
}
|
|
2956
3075
|
/**
|
|
2957
|
-
*
|
|
2958
|
-
* @param
|
|
3076
|
+
* Toggles the active state of available channels based on the supplied selection list.
|
|
3077
|
+
* @param values - The selected channel items; channels absent from this list are deactivated.
|
|
2959
3078
|
*/
|
|
2960
|
-
|
|
2961
|
-
|
|
3079
|
+
updateChannels(values) {
|
|
3080
|
+
this.core.availableChannels().forEach(channel => {
|
|
3081
|
+
if (!channel.disabled) {
|
|
3082
|
+
channel.active = values?.findIndex(x => x.value === channel.value) !== -1;
|
|
3083
|
+
}
|
|
3084
|
+
});
|
|
2962
3085
|
}
|
|
2963
3086
|
/**
|
|
2964
|
-
*
|
|
2965
|
-
* @
|
|
3087
|
+
* Gets the trial info for the current account.
|
|
3088
|
+
* @returns An observable emitting the API result wrapping the trial info.
|
|
2966
3089
|
*/
|
|
2967
|
-
|
|
2968
|
-
return this.httpClient.
|
|
3090
|
+
getTrialInfo() {
|
|
3091
|
+
return this.httpClient.get(this.core.serviceUri + '/account/trial');
|
|
2969
3092
|
}
|
|
2970
3093
|
/**
|
|
2971
|
-
*
|
|
2972
|
-
* @param params - The deadline data to save.
|
|
3094
|
+
* Refreshes the trial status from the server and updates the stored login context.
|
|
2973
3095
|
*/
|
|
2974
|
-
|
|
2975
|
-
|
|
3096
|
+
updateTrialInfo() {
|
|
3097
|
+
const info = this.core.loginInfo;
|
|
3098
|
+
if (!info || info?.context?.hasTrial === false)
|
|
3099
|
+
return; // Not supported
|
|
3100
|
+
this.getTrialInfo().subscribe((r) => {
|
|
3101
|
+
if (r.success) {
|
|
3102
|
+
if (info?.context) {
|
|
3103
|
+
if (r.value) {
|
|
3104
|
+
info.context.hasTrial = true;
|
|
3105
|
+
info.context.trialInfo = r.value;
|
|
3106
|
+
}
|
|
3107
|
+
else {
|
|
3108
|
+
info.context.hasTrial = false;
|
|
3109
|
+
info.context.trialInfo = undefined;
|
|
3110
|
+
}
|
|
3111
|
+
}
|
|
3112
|
+
}
|
|
3113
|
+
});
|
|
2976
3114
|
}
|
|
2977
3115
|
/**
|
|
2978
|
-
*
|
|
2979
|
-
* @param
|
|
3116
|
+
* Creates or updates a user link record.
|
|
3117
|
+
* @param item - The user link data to save.
|
|
3118
|
+
* @returns An observable emitting the API result wrapping a boolean success flag.
|
|
2980
3119
|
*/
|
|
2981
|
-
|
|
2982
|
-
return this.httpClient.
|
|
3120
|
+
saveLink(item) {
|
|
3121
|
+
return this.httpClient.post(this.core.serviceUri + '/account/links/save', item);
|
|
2983
3122
|
}
|
|
2984
3123
|
/**
|
|
2985
|
-
*
|
|
2986
|
-
* @param
|
|
3124
|
+
* Deletes a user link record.
|
|
3125
|
+
* @param item - The user link to remove.
|
|
3126
|
+
* @returns An observable emitting the API result wrapping a boolean success flag.
|
|
2987
3127
|
*/
|
|
2988
|
-
|
|
2989
|
-
return this.httpClient.post(this.
|
|
2990
|
-
responseType: 'blob'
|
|
2991
|
-
});
|
|
3128
|
+
deleteLink(item) {
|
|
3129
|
+
return this.httpClient.post(this.core.serviceUri + '/account/links/delete', item);
|
|
2992
3130
|
}
|
|
2993
3131
|
///
|
|
2994
|
-
//
|
|
3132
|
+
// DASHBOARD
|
|
2995
3133
|
///
|
|
2996
3134
|
/**
|
|
2997
|
-
* Retrieves
|
|
3135
|
+
* Retrieves the current dashboard and applies its counters to the shared dashboard state.
|
|
3136
|
+
* @returns The subscription to the dashboard request.
|
|
3137
|
+
*/
|
|
3138
|
+
loadDashboard() {
|
|
3139
|
+
return this.httpClient
|
|
3140
|
+
.post(this.core.serviceUri + '/account/dashboard', { refreshing: true }).subscribe((r) => {
|
|
3141
|
+
if (r.success) {
|
|
3142
|
+
this.core.dashboard.documentUpdates = r.value.documentUpdates;
|
|
3143
|
+
this.core.dashboard.expiredDeadlines = r.value.expiredDeadlines;
|
|
3144
|
+
this.core.dashboard.expiringDeadlines = r.value.expiringDeadlines;
|
|
3145
|
+
this.core.dashboard.isTrial = r.value.isTrial;
|
|
3146
|
+
this.core.dashboard.items.set(r.value.items ?? []);
|
|
3147
|
+
this.broadcastService.sendMessage(ClipperMessages.COMMAND_DASHBOARD_UPDATED);
|
|
3148
|
+
}
|
|
3149
|
+
});
|
|
3150
|
+
}
|
|
3151
|
+
/**
|
|
3152
|
+
* Retrieves documents updated in the last 15 days for the given search parameters.
|
|
3153
|
+
* @param params - The search parameters to filter results.
|
|
3154
|
+
* @returns An observable emitting the API result wrapping the last-days result.
|
|
3155
|
+
*/
|
|
3156
|
+
last15Days(params) {
|
|
3157
|
+
return this.httpClient.post(this.core.serviceUri + '/account/last-15-days', params);
|
|
3158
|
+
}
|
|
3159
|
+
/**
|
|
3160
|
+
* Adjusts the unread-item counter for the given module and broadcasts a dashboard update.
|
|
3161
|
+
* @param module - The Clipper module whose counter should be adjusted.
|
|
3162
|
+
* @param model - Optional document model to further scope the counter update.
|
|
3163
|
+
* @param increment - The signed increment to apply (use negative values to decrement).
|
|
3164
|
+
*/
|
|
3165
|
+
updateUnreadItems(module, model, increment) {
|
|
3166
|
+
increment ??= 0;
|
|
3167
|
+
if (increment !== 0) {
|
|
3168
|
+
this.core.dashboard.updateUnreadItems(module, model, increment);
|
|
3169
|
+
}
|
|
3170
|
+
this.broadcastService.sendMessage(ClipperMessages.COMMAND_DASHBOARD_UPDATED);
|
|
3171
|
+
}
|
|
3172
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: ClipperAccountService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
|
|
3173
|
+
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.0.1", ngImport: i0, type: ClipperAccountService }); }
|
|
3174
|
+
}
|
|
3175
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: ClipperAccountService, decorators: [{
|
|
3176
|
+
type: Service
|
|
3177
|
+
}] });
|
|
3178
|
+
|
|
3179
|
+
/**
|
|
3180
|
+
* Document archive: folders and files search, save, copy, delete, import/export and download.
|
|
3181
|
+
*/
|
|
3182
|
+
class ClipperArchiveService {
|
|
3183
|
+
constructor() {
|
|
3184
|
+
this.httpClient = inject(HttpClient);
|
|
3185
|
+
this.core = inject(ClipperCoreService);
|
|
3186
|
+
}
|
|
3187
|
+
/**
|
|
3188
|
+
* Retrieves all archive folders matching the given search parameters and stores the
|
|
3189
|
+
* returned teams in the shared state.
|
|
2998
3190
|
* @param params - The folder search parameters.
|
|
3191
|
+
* @returns An observable emitting the API result wrapping the folders search result.
|
|
2999
3192
|
*/
|
|
3000
3193
|
getArchiveFolders(params) {
|
|
3001
3194
|
return this.httpClient
|
|
3002
|
-
.post(this.
|
|
3195
|
+
.post(this.core.serviceUri + '/archive/folders', params)
|
|
3003
3196
|
.pipe(map((r) => {
|
|
3004
3197
|
// Store teams
|
|
3005
3198
|
if (r.success) {
|
|
3006
|
-
this.
|
|
3199
|
+
this.core.setTeams(r.value.teams);
|
|
3007
3200
|
}
|
|
3008
3201
|
return r;
|
|
3009
3202
|
}));
|
|
@@ -3011,17 +3204,19 @@ class ClipperService {
|
|
|
3011
3204
|
/**
|
|
3012
3205
|
* Creates or updates an archive folder.
|
|
3013
3206
|
* @param params - The folder data to save.
|
|
3207
|
+
* @returns An observable emitting the API result wrapping the saved folder.
|
|
3014
3208
|
*/
|
|
3015
3209
|
saveArchiveFolder(params) {
|
|
3016
|
-
return this.httpClient.post(this.
|
|
3210
|
+
return this.httpClient.post(this.core.serviceUri + '/archive/folders/save', params);
|
|
3017
3211
|
}
|
|
3018
3212
|
/**
|
|
3019
3213
|
* Exports archive folders as a downloadable file.
|
|
3020
3214
|
* @param id - The folder ID to export, or `undefined` to export all folders.
|
|
3021
3215
|
* @param teamId - The optional team ID. Defaults to `undefined` (personal workspace).
|
|
3216
|
+
* @returns An observable emitting the exported folders content as a blob.
|
|
3022
3217
|
*/
|
|
3023
3218
|
exportArchiveFolders(id, teamId) {
|
|
3024
|
-
let url = this.
|
|
3219
|
+
let url = this.core.serviceUri + '/archive/export/?';
|
|
3025
3220
|
if (id) {
|
|
3026
3221
|
url += 'id=' + id;
|
|
3027
3222
|
}
|
|
@@ -3041,6 +3236,7 @@ class ClipperService {
|
|
|
3041
3236
|
/**
|
|
3042
3237
|
* Uploads and imports archive folders from a file.
|
|
3043
3238
|
* @param params - The import parameters including the source file and destination folder.
|
|
3239
|
+
* @returns An observable of HTTP events reporting upload progress and the final response.
|
|
3044
3240
|
*/
|
|
3045
3241
|
importArchiveFolders(params) {
|
|
3046
3242
|
// Prepare form
|
|
@@ -3055,32 +3251,36 @@ class ClipperService {
|
|
|
3055
3251
|
formData.append('teamId', params.teamId);
|
|
3056
3252
|
}
|
|
3057
3253
|
// Create request
|
|
3058
|
-
return this.httpClient.request(new HttpRequest('POST', this.
|
|
3254
|
+
return this.httpClient.request(new HttpRequest('POST', this.core.serviceUri + '/archive/import/', formData, { reportProgress: true }));
|
|
3059
3255
|
}
|
|
3060
3256
|
/**
|
|
3061
3257
|
* Retrieves archive files and folders matching the given search parameters.
|
|
3062
3258
|
* @param params - The archive files search parameters.
|
|
3259
|
+
* @returns An observable emitting the API result wrapping the files search result.
|
|
3063
3260
|
*/
|
|
3064
3261
|
queryArchiveItems(params) {
|
|
3065
|
-
return this.httpClient.post(this.
|
|
3262
|
+
return this.httpClient.post(this.core.serviceUri + '/archive/files', params);
|
|
3066
3263
|
}
|
|
3067
3264
|
/**
|
|
3068
3265
|
* Deletes one or more archive files or folders.
|
|
3069
3266
|
* @param params - The delete operation parameters.
|
|
3267
|
+
* @returns An observable emitting the API result wrapping the number of deleted items.
|
|
3070
3268
|
*/
|
|
3071
3269
|
deleteArchiveItems(params) {
|
|
3072
|
-
return this.httpClient.post(this.
|
|
3270
|
+
return this.httpClient.post(this.core.serviceUri + '/archive/files/delete', params);
|
|
3073
3271
|
}
|
|
3074
3272
|
/**
|
|
3075
3273
|
* Copies archive files or folders to a destination folder.
|
|
3076
3274
|
* @param params - The copy operation parameters.
|
|
3275
|
+
* @returns An observable emitting the API result wrapping the number of copied items.
|
|
3077
3276
|
*/
|
|
3078
3277
|
copyArchiveItems(params) {
|
|
3079
|
-
return this.httpClient.post(this.
|
|
3278
|
+
return this.httpClient.post(this.core.serviceUri + '/archive/files/copy', params);
|
|
3080
3279
|
}
|
|
3081
3280
|
/**
|
|
3082
3281
|
* Uploads and saves an archive file using multipart form data.
|
|
3083
3282
|
* @param params - The file metadata and binary content to save.
|
|
3283
|
+
* @returns An observable of HTTP events reporting upload progress and the final response.
|
|
3084
3284
|
*/
|
|
3085
3285
|
saveArchiveFile(params) {
|
|
3086
3286
|
// Prepare form
|
|
@@ -3124,139 +3324,148 @@ class ClipperService {
|
|
|
3124
3324
|
if (params.model)
|
|
3125
3325
|
formData.append('model', params.model.toString());
|
|
3126
3326
|
// Create request
|
|
3127
|
-
return this.httpClient.request(new HttpRequest('POST', this.
|
|
3327
|
+
return this.httpClient.request(new HttpRequest('POST', this.core.serviceUri + '/archive/files/save', formData, { reportProgress: true }));
|
|
3128
3328
|
}
|
|
3129
3329
|
/**
|
|
3130
3330
|
* Retrieves the metadata for a single archive file.
|
|
3131
3331
|
* @param id - The ID of the archive file to retrieve.
|
|
3332
|
+
* @returns An observable emitting the API result wrapping the archive file info.
|
|
3132
3333
|
*/
|
|
3133
3334
|
getArchiveFile(id) {
|
|
3134
|
-
return this.httpClient.get(this.
|
|
3335
|
+
return this.httpClient.get(this.core.serviceUri + '/archive/files/' + id);
|
|
3135
3336
|
}
|
|
3136
3337
|
/**
|
|
3137
3338
|
* Downloads the binary content of an archive file.
|
|
3138
3339
|
* @param id - The binary ID of the file to download.
|
|
3139
3340
|
* @param otp - An optional one-time password for authenticated downloads.
|
|
3341
|
+
* @returns An observable emitting the file binary content as a blob.
|
|
3140
3342
|
*/
|
|
3141
3343
|
downloadArchiveFile(id, otp) {
|
|
3142
|
-
return this.httpClient.get(this.
|
|
3344
|
+
return this.httpClient.get(this.core.serviceUri + '/archive/files/download/?id=' + id + '&otp=' + (otp ?? ''), { responseType: 'blob' });
|
|
3143
3345
|
}
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3346
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: ClipperArchiveService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
|
|
3347
|
+
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.0.1", ngImport: i0, type: ClipperArchiveService }); }
|
|
3348
|
+
}
|
|
3349
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: ClipperArchiveService, decorators: [{
|
|
3350
|
+
type: Service
|
|
3351
|
+
}] });
|
|
3352
|
+
|
|
3353
|
+
/**
|
|
3354
|
+
* Calendar deadlines: search, snapshot, save/copy/close/delete and iCalendar export.
|
|
3355
|
+
*/
|
|
3356
|
+
class ClipperCalendarService {
|
|
3357
|
+
constructor() {
|
|
3358
|
+
this.httpClient = inject(HttpClient);
|
|
3359
|
+
this.core = inject(ClipperCoreService);
|
|
3153
3360
|
}
|
|
3154
3361
|
/**
|
|
3155
|
-
*
|
|
3156
|
-
* @param params - The
|
|
3362
|
+
* Queries the calendar and stores the returned teams in the shared state.
|
|
3363
|
+
* @param params - The calendar search parameters.
|
|
3364
|
+
* @returns An observable emitting the API result wrapping the calendar search result.
|
|
3157
3365
|
*/
|
|
3158
|
-
|
|
3159
|
-
return this.httpClient.post(this.
|
|
3366
|
+
queryCalendar(params) {
|
|
3367
|
+
return this.httpClient.post(this.core.serviceUri + '/calendar', params)
|
|
3368
|
+
.pipe(map((r) => {
|
|
3369
|
+
// Store teams
|
|
3370
|
+
if (r.success) {
|
|
3371
|
+
this.core.setTeams(r.value.teams);
|
|
3372
|
+
}
|
|
3373
|
+
return r;
|
|
3374
|
+
}));
|
|
3160
3375
|
}
|
|
3161
3376
|
/**
|
|
3162
|
-
* Gets the
|
|
3377
|
+
* Gets the calendar snapshot.
|
|
3378
|
+
* @param params - The calendar search parameters.
|
|
3379
|
+
* @returns An observable emitting the API result wrapping the calendar snapshot result.
|
|
3163
3380
|
*/
|
|
3164
|
-
|
|
3165
|
-
return this.httpClient.
|
|
3381
|
+
calendarSnapshot(params) {
|
|
3382
|
+
return this.httpClient.post(this.core.serviceUri + '/calendar/snapshot', params);
|
|
3166
3383
|
}
|
|
3167
3384
|
/**
|
|
3168
|
-
*
|
|
3169
|
-
* @param
|
|
3385
|
+
* Deletes one or more calendar deadlines by ID.
|
|
3386
|
+
* @param ids - The IDs of the deadlines to delete.
|
|
3387
|
+
* @returns An observable emitting the API result wrapping the number of deleted deadlines.
|
|
3170
3388
|
*/
|
|
3171
|
-
|
|
3172
|
-
return this.httpClient.post(this.
|
|
3173
|
-
if (r.success) {
|
|
3174
|
-
if (params.channels) {
|
|
3175
|
-
this.setChannels(params.channels);
|
|
3176
|
-
}
|
|
3177
|
-
}
|
|
3178
|
-
return r;
|
|
3179
|
-
}));
|
|
3389
|
+
deleteCalendarDeadlines(ids) {
|
|
3390
|
+
return this.httpClient.post(this.core.serviceUri + '/calendar/delete', { ids: ids });
|
|
3180
3391
|
}
|
|
3181
3392
|
/**
|
|
3182
|
-
*
|
|
3183
|
-
* @param params - The
|
|
3393
|
+
* Copies one or more calendar deadlines using the given parameters.
|
|
3394
|
+
* @param params - The copy operation parameters.
|
|
3395
|
+
* @returns An observable emitting the API result wrapping the number of copied deadlines.
|
|
3184
3396
|
*/
|
|
3185
|
-
|
|
3186
|
-
return this.httpClient.post(this.
|
|
3187
|
-
if (r.success) {
|
|
3188
|
-
this.setChannelsState(r.value);
|
|
3189
|
-
}
|
|
3190
|
-
return r;
|
|
3191
|
-
}));
|
|
3397
|
+
copyCalendarDeadlines(params) {
|
|
3398
|
+
return this.httpClient.post(this.core.serviceUri + '/calendar/copy', params);
|
|
3192
3399
|
}
|
|
3193
|
-
///
|
|
3194
|
-
// TRIAL
|
|
3195
|
-
///
|
|
3196
3400
|
/**
|
|
3197
|
-
*
|
|
3401
|
+
* Marks the given calendar deadline as closed.
|
|
3402
|
+
* @param id - The ID of the deadline to close.
|
|
3403
|
+
* @returns An observable emitting the API result wrapping the updated deadline.
|
|
3198
3404
|
*/
|
|
3199
|
-
|
|
3200
|
-
return this.httpClient.
|
|
3405
|
+
closeCalendarDeadline(id) {
|
|
3406
|
+
return this.httpClient.post(this.core.serviceUri + '/calendar/close', { id: id });
|
|
3201
3407
|
}
|
|
3202
3408
|
/**
|
|
3203
|
-
*
|
|
3409
|
+
* Creates or updates a calendar deadline.
|
|
3410
|
+
* @param params - The deadline data to save.
|
|
3411
|
+
* @returns An observable emitting the API result wrapping the saved deadlines.
|
|
3204
3412
|
*/
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
return; // Not supported
|
|
3208
|
-
this.getTrialInfo().subscribe((r) => {
|
|
3209
|
-
if (r.success) {
|
|
3210
|
-
if (this._loginInfo?.context) {
|
|
3211
|
-
if (r.value) {
|
|
3212
|
-
this._loginInfo.context.hasTrial = true;
|
|
3213
|
-
this._loginInfo.context.trialInfo = r.value;
|
|
3214
|
-
}
|
|
3215
|
-
else {
|
|
3216
|
-
this._loginInfo.context.hasTrial = false;
|
|
3217
|
-
this._loginInfo.context.trialInfo = undefined;
|
|
3218
|
-
}
|
|
3219
|
-
}
|
|
3220
|
-
}
|
|
3221
|
-
});
|
|
3413
|
+
saveCalendarDeadline(params) {
|
|
3414
|
+
return this.httpClient.post(this.core.serviceUri + '/calendar/save', params);
|
|
3222
3415
|
}
|
|
3223
|
-
///
|
|
3224
|
-
// LINKS
|
|
3225
|
-
///
|
|
3226
3416
|
/**
|
|
3227
|
-
*
|
|
3228
|
-
* @param
|
|
3417
|
+
* Retrieves a single calendar deadline by its ID.
|
|
3418
|
+
* @param id - The ID of the deadline to retrieve.
|
|
3419
|
+
* @returns An observable emitting the API result wrapping the deadline.
|
|
3229
3420
|
*/
|
|
3230
|
-
|
|
3231
|
-
return this.httpClient.
|
|
3421
|
+
getCalendarDeadline(id) {
|
|
3422
|
+
return this.httpClient.get(this.core.serviceUri + '/calendar/' + id);
|
|
3232
3423
|
}
|
|
3233
3424
|
/**
|
|
3234
|
-
*
|
|
3235
|
-
* @param
|
|
3425
|
+
* Exports the selected deadlines in iCalendar (.ics) format.
|
|
3426
|
+
* @param ids - The IDs of the deadlines to export.
|
|
3427
|
+
* @returns An observable emitting the iCalendar content as a blob.
|
|
3236
3428
|
*/
|
|
3237
|
-
|
|
3238
|
-
return this.httpClient.post(this.
|
|
3429
|
+
exportCalendarDeadlines(ids) {
|
|
3430
|
+
return this.httpClient.post(this.core.serviceUri + '/calendar/export', { ids: ids }, {
|
|
3431
|
+
responseType: 'blob'
|
|
3432
|
+
});
|
|
3433
|
+
}
|
|
3434
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: ClipperCalendarService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
|
|
3435
|
+
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.0.1", ngImport: i0, type: ClipperCalendarService }); }
|
|
3436
|
+
}
|
|
3437
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: ClipperCalendarService, decorators: [{
|
|
3438
|
+
type: Service
|
|
3439
|
+
}] });
|
|
3440
|
+
|
|
3441
|
+
/**
|
|
3442
|
+
* Collaboration: teams and team members, contacts and shared document notes.
|
|
3443
|
+
*/
|
|
3444
|
+
class ClipperCollaborationService {
|
|
3445
|
+
constructor() {
|
|
3446
|
+
this.httpClient = inject(HttpClient);
|
|
3447
|
+
this.core = inject(ClipperCoreService);
|
|
3239
3448
|
}
|
|
3240
|
-
///
|
|
3241
|
-
// TEAMS
|
|
3242
|
-
///
|
|
3243
3449
|
/**
|
|
3244
3450
|
* Renames the current user's team.
|
|
3245
3451
|
* @param newName - The new display name for the team.
|
|
3452
|
+
* @returns An observable emitting the API result wrapping the updated team info.
|
|
3246
3453
|
*/
|
|
3247
3454
|
renameTeam(newName) {
|
|
3248
|
-
return this.httpClient.post(this.
|
|
3455
|
+
return this.httpClient.post(this.core.serviceUri + '/account/teams/update', { title: newName });
|
|
3249
3456
|
}
|
|
3250
3457
|
/**
|
|
3251
|
-
* Retrieves the list of teams available to the current user.
|
|
3458
|
+
* Retrieves the list of teams available to the current user. When not querying
|
|
3459
|
+
* admins only, the result is also stored in the shared teams state.
|
|
3252
3460
|
* @param params - The teams search parameters.
|
|
3461
|
+
* @returns An observable emitting the API result wrapping the teams search result.
|
|
3253
3462
|
*/
|
|
3254
3463
|
getTeams(params) {
|
|
3255
|
-
return this.httpClient.post(this.
|
|
3464
|
+
return this.httpClient.post(this.core.serviceUri + '/account/teams', params)
|
|
3256
3465
|
.pipe(map((r) => {
|
|
3257
3466
|
// Store teams
|
|
3258
3467
|
if (!params.adminsOnly) {
|
|
3259
|
-
this.
|
|
3468
|
+
this.core.setTeams(r.value.items);
|
|
3260
3469
|
}
|
|
3261
3470
|
return r;
|
|
3262
3471
|
}));
|
|
@@ -3264,61 +3473,63 @@ class ClipperService {
|
|
|
3264
3473
|
/**
|
|
3265
3474
|
* Retrieves the members of a team matching the given search parameters.
|
|
3266
3475
|
* @param params - The team members search parameters.
|
|
3476
|
+
* @returns An observable emitting the API result wrapping the team members search result.
|
|
3267
3477
|
*/
|
|
3268
3478
|
getTeamMembers(params) {
|
|
3269
|
-
return this.httpClient.post(this.
|
|
3479
|
+
return this.httpClient.post(this.core.serviceUri + '/account/teams/members', params);
|
|
3270
3480
|
}
|
|
3271
3481
|
/**
|
|
3272
3482
|
* Removes the specified members from the team.
|
|
3273
3483
|
* @param teamId - The ID of the team.
|
|
3274
3484
|
* @param ids - The numeric IDs of the team members to remove.
|
|
3485
|
+
* @returns An observable emitting the API result wrapping the number of removed members.
|
|
3275
3486
|
*/
|
|
3276
3487
|
deleteTeamMembers(teamId, ids) {
|
|
3277
|
-
return this.httpClient.post(this.
|
|
3488
|
+
return this.httpClient.post(this.core.serviceUri + '/account/teams/members/delete', { teamId: teamId, ids: ids });
|
|
3278
3489
|
}
|
|
3279
3490
|
/**
|
|
3280
3491
|
* Creates or updates a team member record.
|
|
3281
3492
|
* @param item - The team member data to save.
|
|
3493
|
+
* @returns An observable emitting the API result wrapping the saved team member.
|
|
3282
3494
|
*/
|
|
3283
3495
|
saveTeamMember(item) {
|
|
3284
|
-
return this.httpClient.post(this.
|
|
3496
|
+
return this.httpClient.post(this.core.serviceUri + '/account/teams/members/save', item);
|
|
3285
3497
|
}
|
|
3286
|
-
///
|
|
3287
|
-
// CONTACTS
|
|
3288
|
-
///
|
|
3289
3498
|
/**
|
|
3290
3499
|
* Retrieves contacts matching the given search parameters.
|
|
3291
3500
|
* @param params - The contacts search parameters.
|
|
3501
|
+
* @returns An observable emitting the API result wrapping the contacts query result.
|
|
3292
3502
|
*/
|
|
3293
3503
|
queryContacts(params) {
|
|
3294
|
-
return this.httpClient.post(this.
|
|
3504
|
+
return this.httpClient.post(this.core.serviceUri + '/account/contacts', params);
|
|
3295
3505
|
}
|
|
3296
3506
|
/**
|
|
3297
3507
|
* Deletes the specified contacts.
|
|
3298
3508
|
* @param ids - The numeric IDs of the contacts to remove.
|
|
3509
|
+
* @returns An observable emitting the API result wrapping the number of deleted contacts.
|
|
3299
3510
|
*/
|
|
3300
3511
|
deleteContacts(ids) {
|
|
3301
|
-
return this.httpClient.post(this.
|
|
3512
|
+
return this.httpClient.post(this.core.serviceUri + '/account/contacts/delete', { ids: ids });
|
|
3302
3513
|
}
|
|
3303
3514
|
/**
|
|
3304
3515
|
* Creates or updates a contact record.
|
|
3305
3516
|
* @param item - The contact data to save.
|
|
3517
|
+
* @returns An observable emitting the API result wrapping the saved contact.
|
|
3306
3518
|
*/
|
|
3307
3519
|
saveContact(item) {
|
|
3308
|
-
return this.httpClient.post(this.
|
|
3520
|
+
return this.httpClient.post(this.core.serviceUri + '/account/contacts/save', item);
|
|
3309
3521
|
}
|
|
3310
|
-
///
|
|
3311
|
-
// NOTES
|
|
3312
|
-
///
|
|
3313
3522
|
/**
|
|
3314
|
-
* Retrieves document notes matching the given search parameters
|
|
3523
|
+
* Retrieves document notes matching the given search parameters and stores the
|
|
3524
|
+
* returned teams in the shared state.
|
|
3315
3525
|
* @param params - The notes search parameters.
|
|
3526
|
+
* @returns An observable emitting the API result wrapping the notes search result.
|
|
3316
3527
|
*/
|
|
3317
3528
|
queryNotes(params) {
|
|
3318
|
-
return this.httpClient.post(this.
|
|
3529
|
+
return this.httpClient.post(this.core.serviceUri + '/account/notes', params).pipe(map((r) => {
|
|
3319
3530
|
// Store teams
|
|
3320
3531
|
if (r.success) {
|
|
3321
|
-
this.
|
|
3532
|
+
this.core.setTeams(r.value.teams);
|
|
3322
3533
|
}
|
|
3323
3534
|
return r;
|
|
3324
3535
|
}));
|
|
@@ -3326,30 +3537,122 @@ class ClipperService {
|
|
|
3326
3537
|
/**
|
|
3327
3538
|
* Deletes the specified document notes.
|
|
3328
3539
|
* @param ids - The numeric IDs of the notes to remove.
|
|
3540
|
+
* @returns An observable emitting the API result wrapping the number of deleted notes.
|
|
3329
3541
|
*/
|
|
3330
3542
|
deleteNotes(ids) {
|
|
3331
|
-
return this.httpClient.post(this.
|
|
3543
|
+
return this.httpClient.post(this.core.serviceUri + '/account/notes/delete', { ids: ids });
|
|
3332
3544
|
}
|
|
3333
3545
|
/**
|
|
3334
3546
|
* Creates or updates a document note.
|
|
3335
3547
|
* @param item - The note data to save.
|
|
3548
|
+
* @returns An observable emitting the API result wrapping the saved note.
|
|
3336
3549
|
*/
|
|
3337
3550
|
saveNote(item) {
|
|
3338
|
-
return this.httpClient.post(this.
|
|
3551
|
+
return this.httpClient.post(this.core.serviceUri + '/account/notes/save', item);
|
|
3339
3552
|
}
|
|
3340
3553
|
/**
|
|
3341
3554
|
* Retrieves the tracking history for the given document note.
|
|
3342
3555
|
* @param id - The numeric ID of the note whose tracking records to retrieve.
|
|
3556
|
+
* @returns An observable emitting the API result wrapping the note tracking records.
|
|
3343
3557
|
*/
|
|
3344
3558
|
getNoteTrackings(id) {
|
|
3345
|
-
return this.httpClient.get(this.
|
|
3559
|
+
return this.httpClient.get(this.core.serviceUri + '/account/notes/trackings/' + id);
|
|
3346
3560
|
}
|
|
3347
3561
|
/**
|
|
3348
3562
|
* Gets the count of troubled tracking notifications for document notes,
|
|
3349
3563
|
* which can be used to display an unread counter in the UI.
|
|
3564
|
+
* @returns An observable emitting the API result wrapping the troubled tracking count.
|
|
3350
3565
|
*/
|
|
3351
3566
|
countNotesTrackingsTroubled() {
|
|
3352
|
-
return this.httpClient.get(this.
|
|
3567
|
+
return this.httpClient.get(this.core.serviceUri + '/account/notes/trackings/troubled');
|
|
3568
|
+
}
|
|
3569
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: ClipperCollaborationService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
|
|
3570
|
+
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.0.1", ngImport: i0, type: ClipperCollaborationService }); }
|
|
3571
|
+
}
|
|
3572
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: ClipperCollaborationService, decorators: [{
|
|
3573
|
+
type: Service
|
|
3574
|
+
}] });
|
|
3575
|
+
|
|
3576
|
+
/**
|
|
3577
|
+
* Barrel / facade for the Clipper application.
|
|
3578
|
+
*
|
|
3579
|
+
* Exposes the feature services as named properties and re-exports the shared state
|
|
3580
|
+
* declared in `ClipperCoreService`. Inject `ClipperService` and reach a feature via
|
|
3581
|
+
* its property, e.g. `clipper.login.login(...)`, `clipper.documents.query(...)`,
|
|
3582
|
+
* `clipper.calendar.queryCalendar(...)`.
|
|
3583
|
+
*/
|
|
3584
|
+
class ClipperService {
|
|
3585
|
+
constructor() {
|
|
3586
|
+
this.core = inject(ClipperCoreService);
|
|
3587
|
+
/** Authentication: login/logout, MFA, OTP. */
|
|
3588
|
+
this.session = inject(ClipperLoginService);
|
|
3589
|
+
/** Document search, references, export, working-documents bag and saved searches. */
|
|
3590
|
+
this.documents = inject(ClipperDocumentsService);
|
|
3591
|
+
/** Account settings, dashboard, password, channels, trial info and user links. */
|
|
3592
|
+
this.account = inject(ClipperAccountService);
|
|
3593
|
+
/** Archive folders and files. */
|
|
3594
|
+
this.archive = inject(ClipperArchiveService);
|
|
3595
|
+
/** Calendar deadlines. */
|
|
3596
|
+
this.calendar = inject(ClipperCalendarService);
|
|
3597
|
+
/** Teams, contacts and shared notes. */
|
|
3598
|
+
this.collaboration = inject(ClipperCollaborationService);
|
|
3599
|
+
}
|
|
3600
|
+
////
|
|
3601
|
+
// RE-EXPORTED CORE STATE
|
|
3602
|
+
////
|
|
3603
|
+
/** @returns The URI of the Clipper web application, or `undefined` if not set. */
|
|
3604
|
+
get appUri() { return this.core.appUri; }
|
|
3605
|
+
/** @returns The base URI of the Clipper REST API. */
|
|
3606
|
+
get serviceUri() { return this.core.serviceUri; }
|
|
3607
|
+
/** @returns The active feature flags. */
|
|
3608
|
+
get flags() { return this.core.flags; }
|
|
3609
|
+
/** @returns The current login context, or `undefined` if not authenticated. */
|
|
3610
|
+
get loginInfo() { return this.core.loginInfo; }
|
|
3611
|
+
/** @returns A read-only signal indicating whether the user is logged in. */
|
|
3612
|
+
get loggedIn() { return this.core.loggedIn; }
|
|
3613
|
+
/** @returns A signal indicating whether a login is in progress. */
|
|
3614
|
+
get loggingIn() { return this.core.loggingIn; }
|
|
3615
|
+
/** @returns A signal holding the current documents search snapshot. */
|
|
3616
|
+
get snapshot() { return this.core.snapshot; }
|
|
3617
|
+
/** @returns A signal indicating whether reference search is supported. */
|
|
3618
|
+
get supportsRS() { return this.core.supportsRS; }
|
|
3619
|
+
/** @returns A signal holding the current references search snapshot. */
|
|
3620
|
+
get referencesSnapshot() { return this.core.referencesSnapshot; }
|
|
3621
|
+
/** @returns The shared dashboard state object. */
|
|
3622
|
+
get dashboard() { return this.core.dashboard; }
|
|
3623
|
+
/** @returns A signal holding the working-documents bag. */
|
|
3624
|
+
get bag() { return this.core.bag; }
|
|
3625
|
+
/** @returns A computed signal with the number of items in the bag. */
|
|
3626
|
+
get bagTotal() { return this.core.bagTotal; }
|
|
3627
|
+
/** @returns A signal controlling the Clipper UI visibility. */
|
|
3628
|
+
get visible() { return this.core.visible; }
|
|
3629
|
+
/** @returns The shared teams collection. */
|
|
3630
|
+
get teams() { return this.core.teams; }
|
|
3631
|
+
/** @returns A signal holding the available channels. */
|
|
3632
|
+
get availableChannels() { return this.core.availableChannels; }
|
|
3633
|
+
/** @returns A computed signal with the currently active channels. */
|
|
3634
|
+
get activeChannels() { return this.core.activeChannels; }
|
|
3635
|
+
/** @returns A signal indicating whether tagging is allowed. */
|
|
3636
|
+
get allowTags() { return this.core.allowTags; }
|
|
3637
|
+
/** @returns A signal with the number of pending notes, or `undefined` if unknown. */
|
|
3638
|
+
get pendingNotes() { return this.core.pendingNotes; }
|
|
3639
|
+
////
|
|
3640
|
+
// BOOTSTRAP
|
|
3641
|
+
////
|
|
3642
|
+
/**
|
|
3643
|
+
* Initialises the application with the API base URI, optional app URI, and feature flags.
|
|
3644
|
+
* @param serviceUri - The base URI of the Clipper REST API.
|
|
3645
|
+
* @param appUri - Optional URI of the Clipper web application (used to build document links).
|
|
3646
|
+
* @param flags - Feature flags that control service behaviour. Defaults to `ClipperServiceFlags.None`.
|
|
3647
|
+
*/
|
|
3648
|
+
initialize(serviceUri, appUri, flags = ClipperServiceFlags.None) {
|
|
3649
|
+
this.core.initialize(serviceUri, appUri, flags);
|
|
3650
|
+
}
|
|
3651
|
+
/**
|
|
3652
|
+
* Pings the Clipper REST API to keep the session/token alive.
|
|
3653
|
+
*/
|
|
3654
|
+
ping() {
|
|
3655
|
+
this.core.ping();
|
|
3353
3656
|
}
|
|
3354
3657
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: ClipperService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
|
|
3355
3658
|
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.0.1", ngImport: i0, type: ClipperService }); }
|
|
@@ -3398,15 +3701,23 @@ class ClipperAuthInterceptor {
|
|
|
3398
3701
|
/**
|
|
3399
3702
|
* Processes an HTTP error, broadcasting a user-friendly message when appropriate.
|
|
3400
3703
|
* Errors are debounced: only one message is sent per `ERROR_DEBOUNCE_MS` window.
|
|
3704
|
+
*
|
|
3705
|
+
* This handler only ever runs for requests already targeting the Clipper service
|
|
3706
|
+
* (see `intercept`). A transport-level failure produces an `HttpErrorResponse`
|
|
3707
|
+
* with status `0` and a `null` url, so the url is only validated when present —
|
|
3708
|
+
* that way genuine network failures still surface the "service unavailable" message.
|
|
3401
3709
|
* @param error - The raw error value thrown by the HTTP layer.
|
|
3402
3710
|
*/
|
|
3403
3711
|
handleError(error) {
|
|
3404
3712
|
if (!(error instanceof HttpErrorResponse))
|
|
3405
3713
|
return;
|
|
3406
|
-
|
|
3714
|
+
// Reject only errors that explicitly belong to a different service; a missing
|
|
3715
|
+
// url (network failure on a Clipper request) is allowed through.
|
|
3716
|
+
if (error.url && !error.url.startsWith(this.clipperService.serviceUri))
|
|
3407
3717
|
return;
|
|
3408
3718
|
const errorStatus = error.status;
|
|
3409
|
-
const shouldNotify =
|
|
3719
|
+
const shouldNotify = errorStatus === 0 ||
|
|
3720
|
+
(errorStatus > 0 && errorStatus < 500) ||
|
|
3410
3721
|
(this.clipperService.flags & ClipperServiceFlags.NotifySystemErrors) > 0;
|
|
3411
3722
|
if (!shouldNotify)
|
|
3412
3723
|
return;
|
|
@@ -3443,6 +3754,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
3443
3754
|
type: Injectable
|
|
3444
3755
|
}] });
|
|
3445
3756
|
|
|
3757
|
+
// Public API surface for the Clipper services.
|
|
3758
|
+
//
|
|
3759
|
+
// `ClipperService` is the facade/barrel: inject it and reach a feature via its
|
|
3760
|
+
// property (e.g. `clipper.login.login(...)`, `clipper.documents.query(...)`).
|
|
3761
|
+
// The feature and core services are exported as well so they can be injected
|
|
3762
|
+
// directly or referenced as types where needed.
|
|
3763
|
+
|
|
3446
3764
|
/*
|
|
3447
3765
|
* Public API Surface of ars-utils
|
|
3448
3766
|
*/
|
|
@@ -3451,5 +3769,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
3451
3769
|
* Generated bundle index. Do not edit.
|
|
3452
3770
|
*/
|
|
3453
3771
|
|
|
3454
|
-
export { ClipperArchiveCopyMode, ClipperArchiveFileStorageType, ClipperArchiveFileStorageTypes, ClipperArchiveFileType, ClipperArchiveFileTypes, ClipperArchiveFilesSearchParams, ClipperArchiveFoldersSearchParams, ClipperAuthInterceptor, ClipperAuthors, ClipperCalendarCopyMode, ClipperCalendarSearchParams, ClipperCalendarState, ClipperCalendarStates, ClipperChannel, ClipperChannelSettings, ClipperChannels, ClipperDashboard, ClipperDocumentChangeReasons, ClipperDocumentContainer, ClipperExportDocumentsFormat, ClipperFacet, ClipperMessages, ClipperModel, ClipperModels, ClipperModule, ClipperModuleGroup, ClipperModuleGroups, ClipperModules, ClipperQueryDocumentFlags, ClipperQueryReferencesMode, ClipperRecurrenceType, ClipperRecurrenceTypes, ClipperRegions, ClipperSearchCalendarSnapshotResult, ClipperSearchFacetsSnapshot, ClipperSearchParams, ClipperSearchResult, ClipperSearchUtils, ClipperSectorTypes, ClipperSectors, ClipperSelectionMode, ClipperService, ClipperServiceFlags, ClipperSort, ClipperSources, ClipperTeamInfo, ClipperTeamProduct, ClipperTeamProductPermission, ClipperUpdateChannelsStateParams, ClipperUtils, NotesColors };
|
|
3772
|
+
export { ClipperAccountService, ClipperArchiveCopyMode, ClipperArchiveFileStorageType, ClipperArchiveFileStorageTypes, ClipperArchiveFileType, ClipperArchiveFileTypes, ClipperArchiveFilesSearchParams, ClipperArchiveFoldersSearchParams, ClipperArchiveService, ClipperAuthInterceptor, ClipperAuthors, ClipperCalendarCopyMode, ClipperCalendarSearchParams, ClipperCalendarService, ClipperCalendarState, ClipperCalendarStates, ClipperChannel, ClipperChannelSettings, ClipperChannels, ClipperCollaborationService, ClipperDashboard, ClipperDocumentChangeReasons, ClipperDocumentContainer, ClipperDocumentsService, ClipperExportDocumentsFormat, ClipperFacet, ClipperLoginService, ClipperMessages, ClipperModel, ClipperModels, ClipperModule, ClipperModuleGroup, ClipperModuleGroups, ClipperModules, ClipperQueryDocumentFlags, ClipperQueryReferencesMode, ClipperRecurrenceType, ClipperRecurrenceTypes, ClipperRegions, ClipperSearchCalendarSnapshotResult, ClipperSearchFacetsSnapshot, ClipperSearchParams, ClipperSearchResult, ClipperSearchUtils, ClipperSectorTypes, ClipperSectors, ClipperSelectionMode, ClipperService, ClipperServiceFlags, ClipperSort, ClipperSources, ClipperTeamInfo, ClipperTeamProduct, ClipperTeamProductPermission, ClipperUpdateChannelsStateParams, ClipperUtils, NotesColors };
|
|
3455
3773
|
//# sourceMappingURL=arsedizioni-ars-utils-clipper.common.mjs.map
|