@arsedizioni/ars-utils 21.2.209 → 21.2.221

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/fesm2022/arsedizioni-ars-utils-clipper.common.mjs +179 -159
  2. package/fesm2022/arsedizioni-ars-utils-clipper.common.mjs.map +1 -1
  3. package/fesm2022/arsedizioni-ars-utils-clipper.ui.mjs +2939 -2939
  4. package/fesm2022/arsedizioni-ars-utils-clipper.ui.mjs.map +1 -1
  5. package/fesm2022/arsedizioni-ars-utils-core.mjs +101 -101
  6. package/fesm2022/arsedizioni-ars-utils-core.mjs.map +1 -1
  7. package/fesm2022/arsedizioni-ars-utils-evolution.common.mjs +280 -252
  8. package/fesm2022/arsedizioni-ars-utils-evolution.common.mjs.map +1 -1
  9. package/fesm2022/arsedizioni-ars-utils-help.mjs +115 -102
  10. package/fesm2022/arsedizioni-ars-utils-help.mjs.map +1 -1
  11. package/fesm2022/arsedizioni-ars-utils-support.common.mjs +43 -36
  12. package/fesm2022/arsedizioni-ars-utils-support.common.mjs.map +1 -1
  13. package/fesm2022/arsedizioni-ars-utils-support.ui.mjs +68 -77
  14. package/fesm2022/arsedizioni-ars-utils-support.ui.mjs.map +1 -1
  15. package/fesm2022/arsedizioni-ars-utils-tinymce.mjs +41 -26
  16. package/fesm2022/arsedizioni-ars-utils-tinymce.mjs.map +1 -1
  17. package/fesm2022/arsedizioni-ars-utils-ui.application.mjs +1461 -1390
  18. package/fesm2022/arsedizioni-ars-utils-ui.application.mjs.map +1 -1
  19. package/fesm2022/arsedizioni-ars-utils-ui.mjs +1349 -1204
  20. package/fesm2022/arsedizioni-ars-utils-ui.mjs.map +1 -1
  21. package/fesm2022/arsedizioni-ars-utils-ui.oauth.mjs +29 -25
  22. package/fesm2022/arsedizioni-ars-utils-ui.oauth.mjs.map +1 -1
  23. package/package.json +1 -1
  24. package/types/arsedizioni-ars-utils-clipper.common.d.ts +88 -62
  25. package/types/arsedizioni-ars-utils-clipper.ui.d.ts +196 -196
  26. package/types/arsedizioni-ars-utils-core.d.ts +16 -16
  27. package/types/arsedizioni-ars-utils-evolution.common.d.ts +131 -70
  28. package/types/arsedizioni-ars-utils-help.d.ts +76 -66
  29. package/types/arsedizioni-ars-utils-support.common.d.ts +29 -19
  30. package/types/arsedizioni-ars-utils-support.ui.d.ts +29 -25
  31. package/types/arsedizioni-ars-utils-tinymce.d.ts +25 -10
  32. package/types/arsedizioni-ars-utils-ui.application.d.ts +597 -467
  33. package/types/arsedizioni-ars-utils-ui.d.ts +474 -337
  34. package/types/arsedizioni-ars-utils-ui.oauth.d.ts +25 -18
@@ -1,8 +1,8 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { inject, signal, Injectable, NgModule } from '@angular/core';
3
+ import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
3
4
  import { BroadcastService, SystemUtils } from '@arsedizioni/ars-utils/core';
4
5
  import { EMPTY, throwError, of, catchError as catchError$1 } from 'rxjs';
5
- import { HttpClient, HttpHeaders } from '@angular/common/http';
6
6
  import { DialogService } from '@arsedizioni/ars-utils/ui';
7
7
  import { catchError, finalize, map } from 'rxjs/operators';
8
8
 
@@ -481,121 +481,140 @@ var ERPPlace;
481
481
  class EvolutionComplianceContextInfo {
482
482
  }
483
483
 
484
+ /**
485
+ * Core service for the Evolution compliance module.
486
+ * Manages authentication (login / logout / MFA), session persistence,
487
+ * and HTTP access to all Evolution API endpoints.
488
+ */
484
489
  class EvolutionService {
485
490
  constructor() {
486
491
  this.httpClient = inject(HttpClient);
487
492
  this.broadcastService = inject(BroadcastService);
488
493
  this.dialogService = inject(DialogService);
489
- this._serviceUri = undefined;
490
494
  this._flags = EvolutionServiceFlags.None;
495
+ /** `true` when the user has an active (non-temporary) session. */
491
496
  this.loggedIn = signal(false, ...(ngDevMode ? [{ debugName: "loggedIn" }] : /* istanbul ignore next */ []));
497
+ /** `true` while a login request is in flight. */
492
498
  this.loggingIn = signal(false, ...(ngDevMode ? [{ debugName: "loggingIn" }] : /* istanbul ignore next */ []));
493
499
  }
500
+ /** Base URI of the Evolution back-end service. */
494
501
  get serviceUri() {
495
502
  return this._serviceUri;
496
503
  }
504
+ /** Feature flags controlling service behaviour (notifications, embedded mode, etc.). */
497
505
  get flags() {
498
506
  return this._flags;
499
507
  }
508
+ /**
509
+ * Returns the current login info, hydrating it from `localStorage` on first access
510
+ * when no in-memory value is available.
511
+ */
500
512
  get loginInfo() {
501
513
  if (!this._loginInfo) {
502
- const loginInfo = localStorage.getItem('evolution_context');
503
- if (loginInfo) {
514
+ const raw = localStorage.getItem('evolution_context');
515
+ if (raw) {
504
516
  try {
505
- this._loginInfo = JSON.parse(loginInfo);
517
+ this._loginInfo = JSON.parse(raw);
506
518
  }
507
- catch { }
519
+ catch { /* invalid JSON — ignore and leave undefined */ }
508
520
  }
509
521
  }
510
522
  return this._loginInfo;
511
523
  }
512
524
  ngOnDestroy() {
513
- if (this.broadcastServiceSubscription) {
514
- this.broadcastServiceSubscription.unsubscribe();
515
- }
525
+ this.broadcastServiceSubscription?.unsubscribe();
516
526
  }
517
527
  /**
518
- * Initialize service
519
- * @param serviceUri : the service uri
520
- * @param flags: the service flags. Default is none.
528
+ * Initialises the service with the back-end URI and optional feature flags.
529
+ * Must be called once during application bootstrap before any other method.
530
+ * @param serviceUri - Base URL of the Evolution service (e.g. `'https://api.example.com/evolution'`).
531
+ * @param flags - Bitmask of `EvolutionServiceFlags` (default: `None`).
521
532
  */
522
533
  initialize(serviceUri, flags = EvolutionServiceFlags.None) {
523
- // Create unique client id and machine id
534
+ // Create a unique per-tab client ID if not already set
524
535
  if (!sessionStorage.getItem('evolution_client_id')) {
525
- sessionStorage.setItem('evolution_client_id', (flags && EvolutionServiceFlags.Embedded) > 0
536
+ sessionStorage.setItem('evolution_client_id', (flags & EvolutionServiceFlags.Embedded) > 0
526
537
  ? 'embedded'
527
538
  : SystemUtils.generateUUID());
528
539
  }
529
- // Initialize
530
540
  this._serviceUri = serviceUri;
531
541
  this._flags = flags;
532
- // React to message broadcasting
542
+ // Subscribe to broadcast messages (only once)
533
543
  if (!this.broadcastServiceSubscription) {
534
- this.broadcastServiceSubscription = this.broadcastService.getMessage().subscribe((message) => {
535
- if (message.id === EvolutionMessages.LOGIN_CHANGED) {
536
- this.login(null, null, true, message.data?.oauth ?? null, message.data?.oauthAccessToken ?? null).subscribe({
537
- next: r => {
538
- if (!r.success) {
539
- if ((this.flags & EvolutionServiceFlags.DisplayConnectionStateMessages) > 0) {
540
- this.dialogService.error("Le credenziali di accesso sono cambiate o non sono più valide. Esegui un nuovo accesso.", undefined, "Errore di Evolution");
541
- }
542
- this.broadcastService.sendMessage(EvolutionMessages.LOGIN_FAILED);
543
- }
544
- else {
545
- if ((this.flags & EvolutionServiceFlags.DisplayConnectionStateMessages) > 0) {
546
- this.dialogService.toast('Connesso a Evolution', 1500, 'power');
547
- }
548
- }
549
- },
550
- error: () => { console.error("Evolution non disponibile."); } // Avoid unwanted errors on client
551
- });
552
- }
553
- else if (message.id === EvolutionMessages.LOGOUT) {
554
- if (this.loggedIn()) {
555
- this.logout().subscribe(r => {
556
- if (!r.success) {
557
- if (r.message) {
558
- this.dialogService.error("<p>" + r.message + "</p><br><br><hr><p class='small'><i>Per eliminare la configurazione di Evolution accedere a:<br><b>menu > personalizza > collegamenti</b></i></p>", null, "Errore di Evolution");
559
- }
560
- }
561
- else {
562
- if ((this.flags & EvolutionServiceFlags.DisplayConnectionStateMessages) > 0) {
563
- this.dialogService.toast('Disconnesso da Evolution', 1500, 'power_off');
564
- }
565
- }
566
- });
567
- }
568
- else {
569
- this.clear();
570
- }
571
- }
544
+ this.broadcastServiceSubscription = this.broadcastService
545
+ .getMessage()
546
+ .subscribe((message) => {
547
+ this.handleBroadcastMessage(message);
572
548
  });
573
549
  }
574
- // Eveluate current session storage in case of page refresh (F5)
550
+ // If a session is already active (e.g. after an F5 page refresh), notify consumers
575
551
  if (this.loggedIn()) {
576
- // Auto login
577
552
  this.loggingIn.set(false);
578
- // Notify
579
553
  this.broadcastService.sendMessage(EvolutionMessages.LOGIN_COMPLETED);
580
554
  }
581
555
  }
582
556
  /**
583
- * Ping
584
- */
557
+ * Dispatches an incoming broadcast message to the appropriate handler.
558
+ * @param message - The message received from the broadcast channel.
559
+ */
560
+ handleBroadcastMessage(message) {
561
+ if (message.id === EvolutionMessages.LOGIN_CHANGED) {
562
+ const data = message.data;
563
+ this.login(undefined, undefined, true, data?.['oauth'], data?.['oauthAccessToken']).subscribe({
564
+ next: r => {
565
+ if (!r.success) {
566
+ if ((this.flags & EvolutionServiceFlags.DisplayConnectionStateMessages) > 0) {
567
+ this.dialogService.error("Le credenziali di accesso sono cambiate o non sono più valide. Esegui un nuovo accesso.", undefined, "Errore di Evolution");
568
+ }
569
+ this.broadcastService.sendMessage(EvolutionMessages.LOGIN_FAILED);
570
+ }
571
+ else {
572
+ if ((this.flags & EvolutionServiceFlags.DisplayConnectionStateMessages) > 0) {
573
+ this.dialogService.toast('Connesso a Evolution', 1500, 'power');
574
+ }
575
+ }
576
+ },
577
+ error: () => { console.error('Evolution non disponibile.'); }
578
+ });
579
+ }
580
+ else if (message.id === EvolutionMessages.LOGOUT) {
581
+ if (this.loggedIn()) {
582
+ this.logout().subscribe(r => {
583
+ if (!r.success) {
584
+ if (r.message) {
585
+ this.dialogService.error("<p>" + r.message + "</p><br><br><hr><p class='small'><i>Per eliminare la configurazione di Evolution accedere a:<br><b>menu > personalizza > collegamenti</b></i></p>", undefined, "Errore di Evolution");
586
+ }
587
+ }
588
+ else {
589
+ if ((this.flags & EvolutionServiceFlags.DisplayConnectionStateMessages) > 0) {
590
+ this.dialogService.toast('Disconnesso da Evolution', 1500, 'power_off');
591
+ }
592
+ }
593
+ });
594
+ }
595
+ else {
596
+ this.clear();
597
+ }
598
+ }
599
+ }
600
+ /**
601
+ * Sends a one-shot ping to the back end to verify connectivity.
602
+ */
585
603
  ping() {
586
- this.httpClient.get(this._serviceUri + '/ping?nocache=' + SystemUtils.generateUUID())
587
- .pipe(catchError(() => { return EMPTY; }))
604
+ this.httpClient
605
+ .get(this._serviceUri + '/ping?nocache=' + SystemUtils.generateUUID())
606
+ .pipe(catchError(() => EMPTY))
588
607
  .subscribe();
589
608
  }
590
609
  /**
591
- * Store login info
592
- */
610
+ * Persists the current login info to `localStorage`.
611
+ */
593
612
  storeContext() {
594
613
  localStorage.setItem('evolution_context', JSON.stringify(this._loginInfo));
595
614
  }
596
615
  /**
597
- * Update context
598
- * @param result: the new context
616
+ * Merges a login result into the stored login info and persists it.
617
+ * @param result - The `EvolutionLoginResult` returned by the login endpoint.
599
618
  */
600
619
  updateContext(result) {
601
620
  if (!this._loginInfo) {
@@ -605,24 +624,24 @@ class EvolutionService {
605
624
  this.storeContext();
606
625
  }
607
626
  /**
608
- * Perform auto login using current link data
609
- * @param onSuccess: function to execute on seccess
610
- */
627
+ * Performs an automatic login using the credentials already stored in the session.
628
+ * Shows a busy indicator and handles success/failure dialogs.
629
+ * @param onSuccess - Optional callback invoked after a successful login.
630
+ * @returns `true` (always) — the result is handled via the subscription callbacks.
631
+ */
611
632
  autoLogin(onSuccess) {
612
- this.login(null, null, true)
633
+ this.login(undefined, undefined, true)
613
634
  .pipe(finalize(() => this.dialogService.clearBusy()))
614
635
  .subscribe({
615
636
  next: r => {
616
637
  if (!r.success) {
617
- this.dialogService.error(r.message, null, "Errore in Evolution");
638
+ this.dialogService.error(r.message, undefined, "Errore in Evolution");
618
639
  }
619
640
  else {
620
- if (!r.value.requiresMfa) {
641
+ if (!r.value?.requiresMfa) {
621
642
  this.dialogService.toast('Connesso ad Evolution', 1500, 'power');
622
643
  }
623
- if (onSuccess) {
624
- onSuccess();
625
- }
644
+ onSuccess?.();
626
645
  }
627
646
  },
628
647
  error: () => { this.dialogService.error("Evolution non disponibile."); }
@@ -630,16 +649,15 @@ class EvolutionService {
630
649
  return true;
631
650
  }
632
651
  /**
633
- * Perform auto logout
634
- * @param onSuccess: function to execute on seccess
652
+ * Performs an automatic logout, notifying the user when the session ends.
653
+ * @param onSuccess - Optional callback invoked after the logout completes.
635
654
  */
636
655
  autoLogout(onSuccess) {
637
- this.logout()
638
- .subscribe({
656
+ this.logout().subscribe({
639
657
  next: r => {
640
658
  if (!r.success) {
641
659
  if (r.message) {
642
- this.dialogService.error(r.message, null, "Errore in Evolution");
660
+ this.dialogService.error(r.message, undefined, "Errore in Evolution");
643
661
  }
644
662
  this.broadcastService.sendMessage(EvolutionMessages.LOGIN_CHANGED);
645
663
  }
@@ -650,48 +668,43 @@ class EvolutionService {
650
668
  error: () => { },
651
669
  complete: () => {
652
670
  this.dialogService.clearBusy();
653
- if (onSuccess) {
654
- onSuccess();
655
- }
671
+ onSuccess?.();
656
672
  }
657
673
  });
658
674
  }
659
675
  /**
660
- * Perform login
661
- * @param email: the optional email if using OAuth2
662
- * @parma password: the optional password if using OAuth2
663
- * @param remember: remember credentials
664
- * @param oauth: the optional open authentication supported
665
- * @param oauthAccessToken: the optional OAuth2 access token
676
+ * Authenticates the user against the Evolution back end.
677
+ * Supports both credential-based and OAuth2 login flows.
678
+ * @param email - User e-mail (credential login only; omit for OAuth2).
679
+ * @param password - User password (credential login only; omit for OAuth2).
680
+ * @param remember - Whether to persist the session across browser restarts.
681
+ * @param oauth - OAuth2 provider type, when using federated login.
682
+ * @param oauthAccessToken - Bearer token from the OAuth2 provider.
683
+ * @returns An observable that emits the `ApiResult<EvolutionLoginResult>`.
666
684
  */
667
- login(email, password, remember, oauth, oauthAccessToken = sessionStorage.getItem("evolution_oauth_token") ?? undefined) {
685
+ login(email, password, remember, oauth, oauthAccessToken = sessionStorage.getItem('evolution_oauth_token') ?? undefined) {
668
686
  return this.httpClient
669
687
  .post(this._serviceUri + '/login2', {
670
688
  user: oauth ? null : email,
671
689
  password: oauth ? null : password,
672
- remember: remember,
673
- oauth: oauth
690
+ remember,
691
+ oauth
674
692
  }, {
675
- headers: !oauth || !oauthAccessToken
676
- ? new HttpHeaders()
693
+ headers: oauth && oauthAccessToken
694
+ ? new HttpHeaders().set('Authorization', oauthAccessToken)
677
695
  : new HttpHeaders()
678
- .set("Authorization", oauthAccessToken ?? '')
679
696
  })
680
- .pipe(catchError(err => {
681
- return throwError(() => err);
682
- }), map((r) => {
697
+ .pipe(catchError(err => throwError(() => err)), map((r) => {
683
698
  if (r.success) {
684
699
  if (!this._loginInfo) {
685
700
  this._loginInfo = { context: undefined };
686
701
  }
687
702
  this._loginInfo.oauth = oauth;
688
703
  this._loginInfo.remember = remember;
689
- if (!oauth && r.value.requiresMfa) {
690
- // Notify login is pending
704
+ if (!oauth && r.value?.requiresMfa) {
691
705
  this.broadcastService.sendMessage(EvolutionMessages.LOGIN_PENDING, {});
692
706
  }
693
707
  else {
694
- // Complete login
695
708
  this.completeLogin(r.value);
696
709
  }
697
710
  }
@@ -699,289 +712,304 @@ class EvolutionService {
699
712
  }));
700
713
  }
701
714
  /**
702
- * Complete login
703
- * @param result : the login result
715
+ * Finalises a successful login by updating the stored context and notifying consumers.
716
+ * @param result - The login result payload from the server.
704
717
  */
705
718
  completeLogin(result) {
706
- // Update context info
707
719
  this.updateContext(result);
708
720
  this.loggedIn.set(!result.context?.isTemporary);
709
721
  this.loggingIn.set(false);
710
- // Keep alive
711
- // Notify
712
722
  this.broadcastService.sendMessage(EvolutionMessages.LOGIN_COMPLETED);
713
723
  }
714
724
  /**
715
- * Confirm MFA procedure
716
- * @param code: the confirm code
725
+ * Confirms a multi-factor authentication challenge and completes the login.
726
+ * @param code - The one-time MFA code entered by the user.
727
+ * @returns An observable that emits the `ApiResult<EvolutionLoginResult>`.
717
728
  */
718
729
  confirmIdentity(code) {
719
730
  return this.httpClient
720
731
  .post(this._serviceUri + '/login/confirm/' + code, {})
721
- .pipe(catchError((err) => {
722
- return throwError(() => err);
723
- }), map((r) => {
732
+ .pipe(catchError(err => throwError(() => err)), map((r) => {
724
733
  if (r.success) {
725
- // Complete login
726
734
  this.completeLogin(r.value);
727
735
  }
728
736
  return r;
729
737
  }));
730
738
  }
731
739
  /**
732
- * Perform logout
733
- * @param forget: true to dispose all user informations
734
- */
740
+ * Logs the current user out of the back end and clears local session data.
741
+ * @param forget - When `true`, instructs the server to discard all stored credentials.
742
+ * @returns An observable that emits `ApiResult<unknown>`.
743
+ */
735
744
  logout(forget = false) {
736
- return this.httpClient.post(this._serviceUri + '/logout/?forget=' + forget, {})
745
+ return this.httpClient
746
+ .post(this._serviceUri + '/logout/?forget=' + forget, {})
737
747
  .pipe(finalize(() => {
738
748
  this.clear();
739
- // Clean up
740
749
  localStorage.removeItem('evolution_context');
741
- }), catchError((_e) => {
742
- return of([]);
743
- }));
750
+ }), catchError(() => of({ success: false, value: undefined, message: undefined })));
744
751
  }
745
752
  /**
746
- * Switch the current login to a new one with the same credentials except role possibly (context change)
747
- * @param id : new user id
748
- */
753
+ * Switches the active session to a different user account while retaining credentials.
754
+ * @param id - The user ID to switch to.
755
+ * @returns An observable that emits the `ApiResult<EvolutionLoginResult>`.
756
+ */
749
757
  loginSwitch(id) {
750
758
  return this.httpClient
751
- .post(this._serviceUri + '/login/switch', {
752
- userId: id,
753
- })
754
- .pipe(catchError((err) => {
755
- return throwError(() => err);
756
- }), map((r) => {
759
+ .post(this._serviceUri + '/login/switch', { userId: id })
760
+ .pipe(catchError(err => throwError(() => err)), map((r) => {
757
761
  if (r.success) {
758
- // Update login
759
762
  this.completeLogin(r.value);
760
763
  }
761
764
  return r;
762
765
  }));
763
766
  }
764
767
  /**
765
- * Reset login refresh timer and login state
768
+ * Resets the in-memory login state and broadcasts a logout-completed event.
769
+ * Does **not** touch `sessionStorage` or `localStorage`; call `clear()` for a full cleanup.
766
770
  */
767
771
  reset() {
768
- // Clear login info
769
772
  this._loginInfo = undefined;
770
- // Logged out
771
773
  this.loggedIn.set(false);
772
- // Notify
773
774
  this.broadcastService.sendMessage(EvolutionMessages.LOGOUT_COMPLETED);
774
775
  }
775
776
  /**
776
- * Clear login data
777
- * @param clearOAuthToken: true to clear oauth token also
777
+ * Removes Evolution session data from `sessionStorage` and calls `reset()`.
778
+ * @param clearOAuthToken - When `true`, also removes the stored OAuth2 access token.
778
779
  */
779
780
  clear(clearOAuthToken = false) {
780
- // Clear local storage
781
781
  sessionStorage.removeItem('evolution_auth');
782
782
  sessionStorage.removeItem('evolution_refresh');
783
783
  sessionStorage.removeItem('evolution_oauth');
784
784
  if (clearOAuthToken) {
785
785
  sessionStorage.removeItem('evolution_oauth_token');
786
786
  }
787
- // Reset login
788
787
  this.reset();
789
788
  }
790
789
  /**
791
- * Convert folders in a tree of Node object.
792
- * @param folders : the subfolders group or null to root
790
+ * Converts a flat list of `INode` items into a hierarchical tree structure.
791
+ * @param folders - The root-level nodes to convert.
792
+ * @returns An array of `INode` objects with nested `children`.
793
793
  */
794
794
  toNodes(folders) {
795
- return this._toNodes(folders, null);
795
+ return this._toNodes(folders, undefined);
796
796
  }
797
797
  /**
798
- * Convert folders in a tree of Node object.
799
- * @param folders : the children group or null to root
798
+ * Recursive helper for `toNodes`.
799
+ * @param folders - The nodes to process at the current depth level.
800
+ * @param parent - The parent node, or `undefined` at the root level.
801
+ * @returns An array of `INode` objects with nested `children`.
800
802
  */
801
803
  _toNodes(folders, parent) {
802
- let nodes = [];
803
- folders.forEach(n => {
804
- let node = {
804
+ const nodes = [];
805
+ for (const n of folders) {
806
+ const node = {
805
807
  id: n.id,
806
808
  name: n.name,
807
809
  count: n.count,
808
- parent: parent,
809
- children: null,
810
+ parent,
811
+ children: undefined,
810
812
  bag: n,
811
813
  };
812
- node.children =
813
- n.children && n.children.length > 0
814
- ? this._toNodes(n.children, node)
815
- : [];
814
+ node.children = n.children && n.children.length > 0
815
+ ? this._toNodes(n.children, node)
816
+ : [];
816
817
  nodes.push(node);
817
- });
818
+ }
818
819
  return nodes;
819
820
  }
820
821
  /**
821
- * Retrieve the taxonomy
822
+ * Retrieves the taxonomy tree from the back end.
823
+ * @returns An observable that emits `ApiResult<FolderTree>`.
822
824
  */
823
825
  getTaxonomy() {
824
826
  return this.httpClient.get(this._serviceUri + '/taxonomy');
825
827
  }
826
828
  /**
827
- * Retrieve groups
828
- * @param group: the group number
829
- * @param register: the optional register id. Default is null.
830
- */
829
+ * Retrieves the compliance groups for a register.
830
+ * @param group - Group index to retrieve (default: `1`).
831
+ * @param register - Optional register ID to scope the query.
832
+ * @returns An observable that emits `ApiResult<string[]>`.
833
+ */
831
834
  getGroups(group = 1, register) {
832
- return this.httpClient.get(this._serviceUri +
833
- (register
834
- ? '/compliance/groups/?group=' +
835
- group +
836
- '&register=' +
837
- register
838
- : '/compliance/groups/?group=' + group));
839
- }
840
- ////
841
- // CONTEXT
842
- ////
835
+ const path = register
836
+ ? `/compliance/groups/?group=${group}&register=${register}`
837
+ : `/compliance/groups/?group=${group}`;
838
+ return this.httpClient.get(this._serviceUri + path);
839
+ }
840
+ // ── Context ────────────────────────────────────────────────────────────────
843
841
  /**
844
- * Change context
842
+ * Sends a context-change request to the back end.
843
+ * @param params - The context model describing the desired switch.
844
+ * @returns An observable that emits `ApiResult<EvolutionChangeContextResultModel>`.
845
845
  */
846
846
  changeContext(params) {
847
847
  return this.httpClient.post(this._serviceUri + '/compliance/context', params);
848
848
  }
849
- ////
850
- // REGISTERS
851
- ////
849
+ // ── Registers ──────────────────────────────────────────────────────────────
852
850
  /**
853
- * Retrieve a register
854
- * @param id the register id
851
+ * Retrieves a single compliance register by ID.
852
+ * @param id - The register ID.
853
+ * @returns An observable that emits `ApiResult<EvolutionComplianceRegister>`.
855
854
  */
856
855
  getRegister(id) {
857
- return this.httpClient.get(this._serviceUri +
858
- '/compliance/registers/' + id);
856
+ return this.httpClient.get(this._serviceUri + '/compliance/registers/' + id);
859
857
  }
860
858
  /**
861
- * Collect register profiles
862
- * @param params parameters
859
+ * Collects register profiles matching the given query parameters.
860
+ * @param params - Query parameters defining the filter criteria.
861
+ * @returns An observable that emits `ApiResult<EvolutionComplianceRegisterProfile[]>`.
863
862
  */
864
863
  collectRegisterProfiles(params) {
865
- return this.httpClient.post(this._serviceUri +
866
- '/compliance/registers/profiles/collect', params);
864
+ return this.httpClient.post(this._serviceUri + '/compliance/registers/profiles/collect', params);
867
865
  }
868
- ////
869
- // LAWS
870
- ////
866
+ // ── Laws ───────────────────────────────────────────────────────────────────
871
867
  /**
872
- * Add one or more laws
873
- * @param params parameters
868
+ * Adds one or more compliance laws.
869
+ * @param params - The laws to add.
870
+ * @returns An observable that emits `ApiResult<EvolutionComplianceLaw[]>`.
874
871
  */
875
872
  addLaws(params) {
876
873
  return this.httpClient.post(this._serviceUri + '/compliance/laws/add', params);
877
874
  }
878
- ////
879
- // ACTIVITIES
880
- ////
875
+ // ── Activities ─────────────────────────────────────────────────────────────
881
876
  /**
882
- * Add one or more activities
883
- * @param params parameters
877
+ * Adds one or more compliance activities.
878
+ * @param params - The activities to add.
879
+ * @returns An observable that emits `ApiResult<EvolutionComplianceActivity>`.
884
880
  */
885
881
  addActivities(params) {
886
882
  return this.httpClient.post(this._serviceUri + '/compliance/activities/add', params);
887
883
  }
888
884
  /**
889
- * Export laws
890
- * @param params parameters
891
- */
885
+ * Exports compliance laws in the format expected by the server.
886
+ * @param params - Export parameters (model shape is server-defined).
887
+ * @returns An observable that emits the binary blob response.
888
+ */
889
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
892
890
  exportLaws(params) {
893
891
  return this.httpClient.post(this._serviceUri + '/compliance/laws/export', params, { responseType: 'blob' });
894
892
  }
895
- ///
896
- // LINKS
897
- ///
893
+ // ── Links ──────────────────────────────────────────────────────────────────
898
894
  /**
899
- * Save a user link
900
- * @param item: the user link
901
- */
895
+ * Persists a user link on the server.
896
+ * @param item - The user link to save.
897
+ * @returns An observable that emits `ApiResult<boolean>`.
898
+ */
902
899
  saveLink(item) {
903
900
  return this.httpClient.post(this._serviceUri + '/account/links/save', item);
904
901
  }
905
902
  /**
906
- * Delete a user link
907
- * @param item: the user link
903
+ * Deletes a user link from the server.
904
+ * @param item - The user link to delete.
905
+ * @returns An observable that emits `ApiResult<boolean>`.
908
906
  */
909
907
  deleteLink(item) {
910
908
  return this.httpClient.post(this._serviceUri + '/account/links/delete', item);
911
909
  }
912
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EvolutionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
913
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EvolutionService, providedIn: 'root' }); }
910
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EvolutionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
911
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EvolutionService, providedIn: 'root' }); }
914
912
  }
915
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EvolutionService, decorators: [{
913
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EvolutionService, decorators: [{
916
914
  type: Injectable,
917
915
  args: [{
918
916
  providedIn: 'root',
919
917
  }]
920
918
  }] });
921
919
 
920
+ /** Minimum milliseconds between consecutive error broadcasts (debounce guard). */
921
+ const ERROR_DEBOUNCE_MS = 5000;
922
+ /**
923
+ * HTTP interceptor that attaches Evolution authentication headers to every request
924
+ * targeting the Evolution service, and broadcasts user-friendly error messages
925
+ * when the server returns an error response.
926
+ */
922
927
  class EvolutionAuthInterceptor {
923
928
  constructor() {
924
929
  this.evolutionService = inject(EvolutionService);
925
930
  this.broadcastService = inject(BroadcastService);
926
931
  this.lastErrorTime = -1;
927
932
  }
933
+ /**
934
+ * Intercepts every outgoing HTTP request.
935
+ * When the request targets the Evolution service URI, attaches credentials and
936
+ * a client-ID header, then pipes the response through an error handler.
937
+ * @param request - The outgoing HTTP request.
938
+ * @param next - The next handler in the interceptor chain.
939
+ * @returns An observable of the HTTP event stream.
940
+ */
928
941
  intercept(request, next) {
929
- if (request.url.startsWith(this.evolutionService.serviceUri ?? '')) {
930
- request = request.clone({
931
- withCredentials: true,
932
- setHeaders: {
933
- 'ngsw-bypass': 'ngsw-bypass',
934
- 'X-Client-Id': sessionStorage.getItem('evolution_client_id') ?? ''
935
- }
936
- });
937
- return next.handle(request)
938
- .pipe(catchError$1(error => {
939
- if (error.url.startsWith(this.evolutionService.serviceUri)) {
940
- const errorStatus = parseInt(error.status ?? "0");
941
- if ((errorStatus > 0 && errorStatus < 500) || (this.evolutionService.flags & EvolutionServiceFlags.NotifySystemErrors) > 0) {
942
- const errorTime = new Date().getTime();
943
- if (errorTime - this.lastErrorTime > 5000) {
944
- this.lastErrorTime = errorTime;
945
- let message = "";
946
- switch (errorStatus) {
947
- case 0:
948
- message = "In questo momento Evolution non è disponibile. Riprova tra qualche minuto.";
949
- break;
950
- case 403:
951
- message = "Non hai i permessi necessari per eseguire l'operazione richiesta.";
952
- break;
953
- default:
954
- message = (error.error?.message ?? error.message ?? "Impossibile eseguire l'operazione richiesta.").replaceAll("\r\n", "</p><p>");
955
- break;
956
- }
957
- this.broadcastService.sendMessage(EvolutionMessages.ERROR, {
958
- invalidateSession: errorStatus === 405 || errorStatus === 410,
959
- message: message,
960
- title: "Errore in Clipper",
961
- errorStatus: errorStatus,
962
- service: this.evolutionService.serviceUri
963
- });
964
- }
965
- }
966
- }
967
- return throwError(() => error);
968
- }));
942
+ const serviceUri = this.evolutionService.serviceUri ?? '';
943
+ if (!serviceUri || !request.url.startsWith(serviceUri)) {
944
+ return next.handle(request);
969
945
  }
970
- return next.handle(request);
946
+ const authenticatedRequest = request.clone({
947
+ withCredentials: true,
948
+ setHeaders: {
949
+ 'ngsw-bypass': 'ngsw-bypass',
950
+ 'X-Client-Id': sessionStorage.getItem('evolution_client_id') ?? ''
951
+ }
952
+ });
953
+ return next.handle(authenticatedRequest).pipe(catchError$1((error) => {
954
+ this.handleError(error);
955
+ return throwError(() => error);
956
+ }));
957
+ }
958
+ /**
959
+ * Processes an HTTP error, broadcasting a user-friendly message when appropriate.
960
+ * Errors are debounced: only one message is sent per `ERROR_DEBOUNCE_MS` window.
961
+ * @param error - The raw error value thrown by the HTTP layer.
962
+ */
963
+ handleError(error) {
964
+ if (!(error instanceof HttpErrorResponse))
965
+ return;
966
+ const serviceUri = this.evolutionService.serviceUri ?? '';
967
+ if (!serviceUri || !error.url?.startsWith(serviceUri))
968
+ return;
969
+ const errorStatus = error.status;
970
+ const shouldNotify = (errorStatus > 0 && errorStatus < 500) ||
971
+ (this.evolutionService.flags & EvolutionServiceFlags.NotifySystemErrors) > 0;
972
+ if (!shouldNotify)
973
+ return;
974
+ const now = Date.now();
975
+ if (now - this.lastErrorTime <= ERROR_DEBOUNCE_MS)
976
+ return;
977
+ this.lastErrorTime = now;
978
+ let message;
979
+ switch (errorStatus) {
980
+ case 0:
981
+ message = "In questo momento Evolution non è disponibile. Riprova tra qualche minuto.";
982
+ break;
983
+ case 403:
984
+ message = "Non hai i permessi necessari per eseguire l'operazione richiesta.";
985
+ break;
986
+ default:
987
+ message = (error.error?.['message'] ??
988
+ error.message ??
989
+ "Impossibile eseguire l'operazione richiesta.").replaceAll('\r\n', '</p><p>');
990
+ break;
991
+ }
992
+ this.broadcastService.sendMessage(EvolutionMessages.ERROR, {
993
+ invalidateSession: errorStatus === 405 || errorStatus === 410,
994
+ message,
995
+ title: "Errore in Evolution",
996
+ errorStatus,
997
+ service: this.evolutionService.serviceUri
998
+ });
971
999
  }
972
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EvolutionAuthInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
973
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EvolutionAuthInterceptor }); }
1000
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EvolutionAuthInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1001
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EvolutionAuthInterceptor }); }
974
1002
  }
975
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EvolutionAuthInterceptor, decorators: [{
1003
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EvolutionAuthInterceptor, decorators: [{
976
1004
  type: Injectable
977
1005
  }] });
978
1006
 
979
1007
  class EvolutionCommonModule {
980
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EvolutionCommonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
981
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: EvolutionCommonModule }); }
982
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EvolutionCommonModule }); }
1008
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EvolutionCommonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
1009
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.10", ngImport: i0, type: EvolutionCommonModule }); }
1010
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EvolutionCommonModule }); }
983
1011
  }
984
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EvolutionCommonModule, decorators: [{
1012
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EvolutionCommonModule, decorators: [{
985
1013
  type: NgModule
986
1014
  }] });
987
1015