@opendevstack/ngx-appshell 19.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +131 -0
  2. package/fesm2022/opendevstack-ngx-appshell.mjs +727 -0
  3. package/fesm2022/opendevstack-ngx-appshell.mjs.map +1 -0
  4. package/index.d.ts +5 -0
  5. package/lib/components/appshell-breadcrumb/appshell-breadcrumb.component.d.ts +7 -0
  6. package/lib/components/appshell-chip/appshell-chip.component.d.ts +6 -0
  7. package/lib/components/appshell-filters/appshell-filters.component.d.ts +12 -0
  8. package/lib/components/appshell-header/appshell-header.component.d.ts +24 -0
  9. package/lib/components/appshell-icon/appshell-icon.component.d.ts +12 -0
  10. package/lib/components/appshell-layout/appshell-layout.component.d.ts +25 -0
  11. package/lib/components/appshell-page-header/appshell-page-header.component.d.ts +18 -0
  12. package/lib/components/appshell-platform-header/appshell-platform-header.component.d.ts +37 -0
  13. package/lib/components/appshell-platform-layout/appshell-platform-layout.component.d.ts +30 -0
  14. package/lib/components/appshell-product-card/appshell-product-card.component.d.ts +23 -0
  15. package/lib/components/appshell-product-card-v2/appshell-product-card-v2.component.d.ts +16 -0
  16. package/lib/components/appshell-select/appshell-select.component.d.ts +9 -0
  17. package/lib/components/appshell-sidebar-menu/appshell-sidebar-menu.component.d.ts +12 -0
  18. package/lib/components/appshell-toast/appshell-toast.component.d.ts +9 -0
  19. package/lib/components/appshell-toasts/appshell-toasts.component.d.ts +14 -0
  20. package/lib/components/index.d.ts +15 -0
  21. package/lib/directives/appshell-link.directive.d.ts +15 -0
  22. package/lib/directives/index.d.ts +1 -0
  23. package/lib/models/appshell-button.d.ts +5 -0
  24. package/lib/models/appshell-filter.d.ts +4 -0
  25. package/lib/models/appshell-link.d.ts +6 -0
  26. package/lib/models/appshell-links-group.d.ts +5 -0
  27. package/lib/models/appshell-notification.d.ts +10 -0
  28. package/lib/models/appshell-picker.d.ts +9 -0
  29. package/lib/models/appshell-product.d.ts +12 -0
  30. package/lib/models/appshell-tag.d.ts +4 -0
  31. package/lib/models/appshell-toast.d.ts +6 -0
  32. package/lib/models/appshell-user.d.ts +5 -0
  33. package/lib/models/index.d.ts +10 -0
  34. package/lib/screens/appshell-notifications-screen/appshell-notifications-screen.component.d.ts +23 -0
  35. package/lib/screens/appshell-product-catalog-screen/appshell-product-catalog-screen.component.d.ts +16 -0
  36. package/lib/screens/appshell-product-view-screen/appshell-product-view-screen.component.d.ts +19 -0
  37. package/lib/screens/index.d.ts +3 -0
  38. package/lib/services/appshell-toast.service.d.ts +12 -0
  39. package/lib/services/icon-registry.service.d.ts +14 -0
  40. package/lib/services/index.d.ts +2 -0
  41. package/opendevstack-ngx-appshell-19.0.5.tgz +0 -0
  42. package/package.json +44 -0
  43. package/public-api.d.ts +5 -0
  44. package/schematics/azure-login/files/app-config/config.json.template +12 -0
  45. package/schematics/azure-login/files/app-config-service/app-config.service.spec.ts.template +48 -0
  46. package/schematics/azure-login/files/app-config-service/app-config.service.ts.template +39 -0
  47. package/schematics/azure-login/files/azure-config/azure.config.ts.template +94 -0
  48. package/schematics/azure-login/files/azure-service/azure.service.spec.ts.template +311 -0
  49. package/schematics/azure-login/files/azure-service/azure.service.ts.template +161 -0
  50. package/schematics/azure-login/index.d.ts +2 -0
  51. package/schematics/azure-login/index.js +325 -0
  52. package/schematics/azure-login/index.js.map +1 -0
  53. package/schematics/azure-login/schema.json +8 -0
  54. package/schematics/collection.json +19 -0
  55. package/schematics/nats-notifications/files/nats-service/nats.service.spec.ts.template +473 -0
  56. package/schematics/nats-notifications/files/nats-service/nats.service.ts.template +255 -0
  57. package/schematics/nats-notifications/files/notifications-screen/notifications-screen.component.html.template +7 -0
  58. package/schematics/nats-notifications/files/notifications-screen/notifications-screen.component.spec.ts.template +152 -0
  59. package/schematics/nats-notifications/files/notifications-screen/notifications-screen.component.ts.template +61 -0
  60. package/schematics/nats-notifications/index.d.ts +2 -0
  61. package/schematics/nats-notifications/index.js +502 -0
  62. package/schematics/nats-notifications/index.js.map +1 -0
  63. package/schematics/nats-notifications/schema.json +8 -0
  64. package/schematics/ng-add/files/_fonts.scss +85 -0
  65. package/schematics/ng-add/files/styles.scss +47 -0
  66. package/schematics/ng-add/index.d.ts +2 -0
  67. package/schematics/ng-add/index.js +442 -0
  68. package/schematics/ng-add/index.js.map +1 -0
  69. package/styles/appshell-typography-config.scss +19 -0
  70. package/styles/appshell.theme.scss +75 -0
  71. package/styles/palette.css +92 -0
@@ -0,0 +1,14 @@
1
+ import { OnInit } from '@angular/core';
2
+ import { AppShellToastService } from '../../services/appshell-toast.service';
3
+ import { AppShellToast } from '../../models/appshell-toast';
4
+ import * as i0 from "@angular/core";
5
+ export declare class AppShellToastsComponent implements OnInit {
6
+ private readonly toastService;
7
+ toastsLimit: import("@angular/core").InputSignal<number>;
8
+ toasts: AppShellToast[];
9
+ constructor(toastService: AppShellToastService);
10
+ ngOnInit(): void;
11
+ closeToast(id: number): void;
12
+ static ɵfac: i0.ɵɵFactoryDeclaration<AppShellToastsComponent, never>;
13
+ static ɵcmp: i0.ɵɵComponentDeclaration<AppShellToastsComponent, "appshell-toasts", never, { "toastsLimit": { "alias": "toastsLimit"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
14
+ }
@@ -0,0 +1,15 @@
1
+ export * from './appshell-breadcrumb/appshell-breadcrumb.component';
2
+ export * from './appshell-chip/appshell-chip.component';
3
+ export * from './appshell-page-header/appshell-page-header.component';
4
+ export * from './appshell-filters/appshell-filters.component';
5
+ export * from './appshell-header/appshell-header.component';
6
+ export * from './appshell-icon/appshell-icon.component';
7
+ export * from './appshell-layout/appshell-layout.component';
8
+ export * from './appshell-platform-header/appshell-platform-header.component';
9
+ export * from './appshell-platform-layout/appshell-platform-layout.component';
10
+ export * from './appshell-product-card/appshell-product-card.component';
11
+ export * from './appshell-product-card-v2/appshell-product-card-v2.component';
12
+ export * from './appshell-select/appshell-select.component';
13
+ export * from './appshell-sidebar-menu/appshell-sidebar-menu.component';
14
+ export * from './appshell-toast/appshell-toast.component';
15
+ export * from './appshell-toasts/appshell-toasts.component';
@@ -0,0 +1,15 @@
1
+ import { ElementRef, OnChanges, Renderer2, SimpleChanges } from '@angular/core';
2
+ import { Router } from '@angular/router';
3
+ import * as i0 from "@angular/core";
4
+ export declare class AppShellLinkDirective implements OnChanges {
5
+ private readonly el;
6
+ private readonly router;
7
+ private readonly renderer;
8
+ link: string;
9
+ constructor(el: ElementRef, router: Router, renderer: Renderer2);
10
+ ngOnChanges(changes: SimpleChanges): void;
11
+ onClick(event: UIEvent): void;
12
+ private isExternalLink;
13
+ static ɵfac: i0.ɵɵFactoryDeclaration<AppShellLinkDirective, never>;
14
+ static ɵdir: i0.ɵɵDirectiveDeclaration<AppShellLinkDirective, "[appShellLink]", never, { "link": { "alias": "appShellLink"; "required": false; }; }, {}, never, never, true, never>;
15
+ }
@@ -0,0 +1 @@
1
+ export * from './appshell-link.directive';
@@ -0,0 +1,5 @@
1
+ export interface AppShellButton {
2
+ label?: string;
3
+ disabled?: boolean;
4
+ tooltip?: string;
5
+ }
@@ -0,0 +1,4 @@
1
+ import { AppShellTag } from "./appshell-tag";
2
+ export interface AppShellFilter extends AppShellTag {
3
+ placeholder: string;
4
+ }
@@ -0,0 +1,6 @@
1
+ export interface AppShellLink {
2
+ label?: string;
3
+ anchor: string;
4
+ icon?: string;
5
+ target?: string;
6
+ }
@@ -0,0 +1,5 @@
1
+ import { AppShellLink } from "./appshell-link";
2
+ export interface AppShellLinksGroup {
3
+ label: string;
4
+ links: AppShellLink[];
5
+ }
@@ -0,0 +1,10 @@
1
+ export interface AppShellNotification {
2
+ id: string;
3
+ subject: string;
4
+ type?: 'info' | 'success' | 'error';
5
+ title?: string;
6
+ message?: string;
7
+ date?: Date;
8
+ expanded?: boolean;
9
+ read: boolean;
10
+ }
@@ -0,0 +1,9 @@
1
+ export interface AppShellPicker {
2
+ label: string;
3
+ options: string[];
4
+ selected?: string;
5
+ noOptionsTitle?: string;
6
+ noOptionsMessage?: string;
7
+ noFilteredOptionsTitle?: string;
8
+ noFilteredOptionsMessage?: string;
9
+ }
@@ -0,0 +1,12 @@
1
+ import { AppShellTag } from "./appshell-tag";
2
+ export interface AppShellProduct {
3
+ id: string;
4
+ title: string;
5
+ shortDescription: string;
6
+ description: string;
7
+ image?: string;
8
+ link?: string;
9
+ tags?: AppShellTag[];
10
+ authors: string[];
11
+ date?: Date;
12
+ }
@@ -0,0 +1,4 @@
1
+ export interface AppShellTag {
2
+ label: string;
3
+ options: string[];
4
+ }
@@ -0,0 +1,6 @@
1
+ import { AppShellNotification } from "./appshell-notification";
2
+ export interface AppShellToast {
3
+ id: number;
4
+ notification: AppShellNotification;
5
+ closeFn: () => void;
6
+ }
@@ -0,0 +1,5 @@
1
+ export interface AppShellUser {
2
+ fullName: string;
3
+ username: string;
4
+ avatarSrc?: string;
5
+ }
@@ -0,0 +1,10 @@
1
+ export * from './appshell-button';
2
+ export * from './appshell-tag';
3
+ export * from './appshell-filter';
4
+ export * from './appshell-link';
5
+ export * from './appshell-links-group';
6
+ export * from './appshell-product';
7
+ export * from './appshell-user';
8
+ export * from './appshell-picker';
9
+ export * from './appshell-notification';
10
+ export * from './appshell-toast';
@@ -0,0 +1,23 @@
1
+ import { AppShellLink } from '../../models/appshell-link';
2
+ import { AppShellNotification } from 'ngx-appshell';
3
+ import { MarkdownService } from 'ngx-markdown';
4
+ import * as i0 from "@angular/core";
5
+ export declare class AppShellNotificationsScreenComponent {
6
+ private readonly markdownService;
7
+ pageTitle: import("@angular/core").InputSignal<string>;
8
+ breadcrumbLinks: import("@angular/core").InputSignal<AppShellLink[]>;
9
+ notifications: import("@angular/core").InputSignal<AppShellNotification[]>;
10
+ computedNotifications: import("@angular/core").Signal<AppShellNotification[]>;
11
+ readNotification: import("@angular/core").OutputEmitterRef<AppShellNotification>;
12
+ readAllNotifications: import("@angular/core").OutputEmitterRef<void>;
13
+ expandedNotifications: string[];
14
+ constructor(markdownService: MarkdownService);
15
+ getIcon(notification: AppShellNotification): string;
16
+ getIconClasses(notification: AppShellNotification): string;
17
+ expandNotification(notification: AppShellNotification): void;
18
+ isNotificationExpanded(notification: AppShellNotification): boolean;
19
+ markAsRead(notification: AppShellNotification): void;
20
+ markAllAsRead(): void;
21
+ static ɵfac: i0.ɵɵFactoryDeclaration<AppShellNotificationsScreenComponent, never>;
22
+ static ɵcmp: i0.ɵɵComponentDeclaration<AppShellNotificationsScreenComponent, "appshell-notifications-screen", never, { "pageTitle": { "alias": "pageTitle"; "required": true; "isSignal": true; }; "breadcrumbLinks": { "alias": "breadcrumbLinks"; "required": true; "isSignal": true; }; "notifications": { "alias": "notifications"; "required": true; "isSignal": true; }; }, { "readNotification": "readNotification"; "readAllNotifications": "readAllNotifications"; }, never, never, true, never>;
23
+ }
@@ -0,0 +1,16 @@
1
+ import { AppShellLink } from '../../models/appshell-link';
2
+ import { AppShellProduct } from '../../models/appshell-product';
3
+ import { AppShellFilter } from '../../models/appshell-filter';
4
+ import * as i0 from "@angular/core";
5
+ export declare class AppShellProductCatalogScreenComponent {
6
+ pageTitle: import("@angular/core").InputSignal<string>;
7
+ breadcrumbLinks: import("@angular/core").InputSignal<AppShellLink[]>;
8
+ products: import("@angular/core").InputSignal<AppShellProduct[]>;
9
+ filters: import("@angular/core").InputSignal<AppShellFilter[]>;
10
+ noProductsIcon: import("@angular/core").InputSignal<string | undefined>;
11
+ noProductsHtmlMessage: import("@angular/core").InputSignal<string | undefined>;
12
+ activeFiltersChange: import("@angular/core").OutputEmitterRef<Map<string, string[]>>;
13
+ getProductLabels(product: AppShellProduct): string[];
14
+ static ɵfac: i0.ɵɵFactoryDeclaration<AppShellProductCatalogScreenComponent, never>;
15
+ static ɵcmp: i0.ɵɵComponentDeclaration<AppShellProductCatalogScreenComponent, "appshell-product-catalog-screen", never, { "pageTitle": { "alias": "pageTitle"; "required": true; "isSignal": true; }; "breadcrumbLinks": { "alias": "breadcrumbLinks"; "required": true; "isSignal": true; }; "products": { "alias": "products"; "required": true; "isSignal": true; }; "filters": { "alias": "filters"; "required": true; "isSignal": true; }; "noProductsIcon": { "alias": "noProductsIcon"; "required": false; "isSignal": true; }; "noProductsHtmlMessage": { "alias": "noProductsHtmlMessage"; "required": false; "isSignal": true; }; }, { "activeFiltersChange": "activeFiltersChange"; }, never, never, true, never>;
16
+ }
@@ -0,0 +1,19 @@
1
+ import { AppShellLink } from '../../models/appshell-link';
2
+ import { AppShellProduct } from '../../models/appshell-product';
3
+ import { AppShellPicker } from '../../models/appshell-picker';
4
+ import { AppShellButton } from '../../models/appshell-button';
5
+ import * as i0 from "@angular/core";
6
+ export declare class AppShellProductViewScreenComponent {
7
+ pageTitle: import("@angular/core").InputSignal<string>;
8
+ breadcrumbLinks: import("@angular/core").InputSignal<AppShellLink[]>;
9
+ actionButton: import("@angular/core").InputSignal<AppShellButton | undefined>;
10
+ actionButtonClicked: import("@angular/core").OutputEmitterRef<void>;
11
+ product: import("@angular/core").InputSignal<AppShellProduct>;
12
+ secondaryButton: import("@angular/core").InputSignal<AppShellButton | undefined>;
13
+ secondaryButtonClicked: import("@angular/core").OutputEmitterRef<void>;
14
+ actionPicker: import("@angular/core").InputSignal<AppShellPicker | undefined>;
15
+ actionPick: import("@angular/core").OutputEmitterRef<string>;
16
+ productLabels: import("@angular/core").Signal<string[]>;
17
+ static ɵfac: i0.ɵɵFactoryDeclaration<AppShellProductViewScreenComponent, never>;
18
+ static ɵcmp: i0.ɵɵComponentDeclaration<AppShellProductViewScreenComponent, "appshell-product-view-screen", never, { "pageTitle": { "alias": "pageTitle"; "required": true; "isSignal": true; }; "breadcrumbLinks": { "alias": "breadcrumbLinks"; "required": true; "isSignal": true; }; "actionButton": { "alias": "actionButton"; "required": false; "isSignal": true; }; "product": { "alias": "product"; "required": true; "isSignal": true; }; "secondaryButton": { "alias": "secondaryButton"; "required": false; "isSignal": true; }; "actionPicker": { "alias": "actionPicker"; "required": false; "isSignal": true; }; }, { "actionButtonClicked": "actionButtonClicked"; "secondaryButtonClicked": "secondaryButtonClicked"; "actionPick": "actionPick"; }, never, never, true, never>;
19
+ }
@@ -0,0 +1,3 @@
1
+ export * from './appshell-product-catalog-screen/appshell-product-catalog-screen.component';
2
+ export * from './appshell-product-view-screen/appshell-product-view-screen.component';
3
+ export * from './appshell-notifications-screen/appshell-notifications-screen.component';
@@ -0,0 +1,12 @@
1
+ import { AppShellNotification, AppShellToast } from 'ngx-appshell';
2
+ import { BehaviorSubject } from 'rxjs';
3
+ import * as i0 from "@angular/core";
4
+ export declare class AppShellToastService {
5
+ toastsSubject: BehaviorSubject<AppShellToast[]>;
6
+ toasts$: import("rxjs").Observable<AppShellToast[]>;
7
+ private currentId;
8
+ showToast(notification: AppShellNotification, duration?: number, closeFn?: () => void): void;
9
+ removeToast(id: number): void;
10
+ static ɵfac: i0.ɵɵFactoryDeclaration<AppShellToastService, never>;
11
+ static ɵprov: i0.ɵɵInjectableDeclaration<AppShellToastService>;
12
+ }
@@ -0,0 +1,14 @@
1
+ import { HttpBackend } from '@angular/common/http';
2
+ import { MatIconRegistry } from '@angular/material/icon';
3
+ import { DomSanitizer } from '@angular/platform-browser';
4
+ import * as i0 from "@angular/core";
5
+ export declare class IconRegistryService {
6
+ private matIconRegistry;
7
+ private sanitizer;
8
+ private namespace;
9
+ private http;
10
+ constructor(httpBackend: HttpBackend, matIconRegistry: MatIconRegistry, sanitizer: DomSanitizer);
11
+ registerIconsFromManifest(manifestUrl?: string): Promise<void>;
12
+ static ɵfac: i0.ɵɵFactoryDeclaration<IconRegistryService, never>;
13
+ static ɵprov: i0.ɵɵInjectableDeclaration<IconRegistryService>;
14
+ }
@@ -0,0 +1,2 @@
1
+ export * from './appshell-toast.service';
2
+ export * from './icon-registry.service';
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@opendevstack/ngx-appshell",
3
+ "version": "19.0.5",
4
+ "description": "A comprehensive Angular library providing pre-built UI components, directives, and schematics for building modern enterprise applications with Material Design.",
5
+ "author": "OpenDevStack",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/opendevstack/ods-ngx-appshell.git"
9
+ },
10
+ "license": "Apache-2.0",
11
+ "ng-add": {
12
+ "save": "true"
13
+ },
14
+ "schematics": "./schematics/collection.json",
15
+ "peerDependencies": {
16
+ "@angular/common": ">=19.0.0",
17
+ "@angular/core": ">=19.0.0",
18
+ "@angular/material": ">=19.0.0",
19
+ "@angular/animations": ">=19.0.0"
20
+ },
21
+ "dependencies": {
22
+ "@angular/material": "19.2.16",
23
+ "@azure/msal-angular": "3.1.0",
24
+ "@azure/msal-browser": "3.27.0",
25
+ "@nats-io/nats-core": "3.0.0",
26
+ "@nats-io/jetstream": "3.0.0",
27
+ "@nats-io/kv": "3.0.0",
28
+ "marked": "15.0.11",
29
+ "ngx-markdown": "19.1.1",
30
+ "tslib": "2.3.0"
31
+ },
32
+ "sideEffects": false,
33
+ "module": "fesm2022/opendevstack-ngx-appshell.mjs",
34
+ "typings": "index.d.ts",
35
+ "exports": {
36
+ "./package.json": {
37
+ "default": "./package.json"
38
+ },
39
+ ".": {
40
+ "types": "./index.d.ts",
41
+ "default": "./fesm2022/opendevstack-ngx-appshell.mjs"
42
+ }
43
+ }
44
+ }
@@ -0,0 +1,5 @@
1
+ export * from './lib/components';
2
+ export * from './lib/directives';
3
+ export * from './lib/models';
4
+ export * from './lib/screens';
5
+ export * from './lib/services';
@@ -0,0 +1,12 @@
1
+ {
2
+ "msalConfig": {
3
+ "auth": {
4
+ "clientId": "ENTER_CLIENT_ID",
5
+ "authority": "ENTER_AUTHORITY"
6
+ }
7
+ },
8
+ "apiConfig": {
9
+ "scopes": ["ENTER_SCOPE"],
10
+ "uri": "ENTER_AUTHORITY"
11
+ }
12
+ }
@@ -0,0 +1,48 @@
1
+ import { TestBed } from '@angular/core/testing';
2
+ import { AppConfigService } from './app-config.service';
3
+ import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
4
+
5
+ describe('AppConfigService', () => {
6
+ let service: AppConfigService;
7
+ let httpMock: HttpTestingController;
8
+
9
+ beforeEach(() => {
10
+ TestBed.configureTestingModule({
11
+ providers: [AppConfigService, provideHttpClientTesting()]
12
+ });
13
+ service = TestBed.inject(AppConfigService);
14
+ httpMock = TestBed.inject(HttpTestingController);
15
+ });
16
+
17
+ afterEach(() => {
18
+ httpMock.verify();
19
+ });
20
+
21
+ it('should be created', () => {
22
+ expect(service).toBeTruthy();
23
+ });
24
+
25
+ it('should load config', async () => {
26
+ const mockConfig = { apiUrl: 'http://example.com' };
27
+
28
+ const loadConfigPromise = service.loadConfig();
29
+ const req = httpMock.expectOne('./config/config.json');
30
+ expect(req.request.method).toBe('GET');
31
+ req.flush(mockConfig);
32
+
33
+ await loadConfigPromise;
34
+ expect(service.getConfig()).toEqual(mockConfig);
35
+ });
36
+
37
+ it('should handle error when loading config', async () => {
38
+ const consoleSpy = spyOn(console, 'error');
39
+
40
+ const loadConfigPromise = service.loadConfig();
41
+ const req = httpMock.expectOne('./config/config.json');
42
+ req.error(new ErrorEvent('Network error'));
43
+
44
+ await loadConfigPromise;
45
+ expect(consoleSpy).toHaveBeenCalled();
46
+ expect(service.getConfig()).toBeUndefined();
47
+ });
48
+ });
@@ -0,0 +1,39 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { HttpBackend, HttpClient } from '@angular/common/http';
3
+ import { firstValueFrom } from 'rxjs';
4
+
5
+ @Injectable({
6
+ providedIn: 'root'
7
+ })
8
+ export class AppConfigService {
9
+
10
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
+ private config: any;
12
+
13
+ private http: HttpClient;
14
+
15
+ /**
16
+ * We are not injecting HttpClient, because if you inject HttpClient then angular first resolve all the HTTP_INTERCEPTORS,
17
+ * and when you provide MsalInterceptor, this makes angular to load MsalService and other component used by Msalinterceptor load before APP_INITIALIZER.
18
+ * To resolve this issue we need to by pass HTTP_INTERCEPTORS, so for this we can use HttpBackend handler, and then create local instance of HttpClient.
19
+ * This will bypass the HTTP_INTERCEPTORS, while getting config file.
20
+ * More info: https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/1403
21
+ */
22
+ constructor(private readonly httpHandler: HttpBackend) {
23
+ this.http = new HttpClient(this.httpHandler);
24
+ }
25
+
26
+ async loadConfig(): Promise<void> {
27
+ return firstValueFrom(this.http.get('./config/config.json'))
28
+ .then((config) => {
29
+ this.config = config;
30
+ })
31
+ .catch((err) => {
32
+ console.error(err);
33
+ });
34
+ }
35
+
36
+ getConfig() {
37
+ return this.config;
38
+ }
39
+ }
@@ -0,0 +1,94 @@
1
+ import { HTTP_INTERCEPTORS } from '@angular/common/http';
2
+ import {
3
+ IPublicClientApplication,
4
+ PublicClientApplication,
5
+ InteractionType,
6
+ BrowserCacheLocation,
7
+ LogLevel,
8
+ } from '@azure/msal-browser';
9
+ import {
10
+ MsalInterceptor,
11
+ MSAL_INSTANCE,
12
+ MsalInterceptorConfiguration,
13
+ MsalGuardConfiguration,
14
+ MSAL_GUARD_CONFIG,
15
+ MSAL_INTERCEPTOR_CONFIG,
16
+ MsalService,
17
+ MsalGuard,
18
+ MsalBroadcastService,
19
+ } from '@azure/msal-angular';
20
+ import { AppConfigService } from './services/app-config.service';
21
+
22
+ export function loggerCallback(logLevel: LogLevel, message: string) {
23
+ console.log(message);
24
+ }
25
+
26
+ export function MSALInstanceFactory(config: AppConfigService): IPublicClientApplication {
27
+ return new PublicClientApplication({
28
+ auth: {
29
+ clientId: config.getConfig()?.msalConfig?.auth?.clientId,
30
+ authority: config.getConfig()?.msalConfig?.auth?.authority,
31
+ redirectUri: '/'
32
+ },
33
+ cache: {
34
+ cacheLocation: BrowserCacheLocation.LocalStorage,
35
+ },
36
+ system: {
37
+ allowNativeBroker: false, // Disables WAM Broker
38
+ loggerOptions: {
39
+ loggerCallback,
40
+ logLevel: LogLevel.Warning,
41
+ piiLoggingEnabled: false,
42
+ },
43
+ },
44
+ });
45
+ }
46
+
47
+ export function MSALInterceptorConfigFactory(config: AppConfigService): MsalInterceptorConfiguration {
48
+ const protectedResourceMap = new Map<string, string[]>();
49
+ protectedResourceMap.set(
50
+ config.getConfig()?.apiConfig?.uri,
51
+ config.getConfig()?.apiConfig?.scopes
52
+ );
53
+
54
+ return {
55
+ interactionType: InteractionType.Redirect,
56
+ protectedResourceMap,
57
+ };
58
+ }
59
+
60
+ export function MSALGuardConfigFactory(config: AppConfigService): MsalGuardConfiguration {;
61
+ return {
62
+ interactionType: InteractionType.Redirect,
63
+ authRequest: {
64
+ scopes: [...config.getConfig()?.apiConfig?.scopes || []],
65
+ },
66
+ loginFailedRoute: '/login-failed',
67
+ };
68
+ }
69
+
70
+ export const msalProviders = [
71
+ {
72
+ provide: HTTP_INTERCEPTORS,
73
+ useClass: MsalInterceptor,
74
+ multi: true,
75
+ },
76
+ {
77
+ provide: MSAL_INSTANCE,
78
+ useFactory: MSALInstanceFactory,
79
+ deps: [AppConfigService]
80
+ },
81
+ {
82
+ provide: MSAL_GUARD_CONFIG,
83
+ useFactory: MSALGuardConfigFactory,
84
+ deps: [AppConfigService]
85
+ },
86
+ {
87
+ provide: MSAL_INTERCEPTOR_CONFIG,
88
+ useFactory: MSALInterceptorConfigFactory,
89
+ deps: [AppConfigService]
90
+ },
91
+ MsalService,
92
+ MsalGuard,
93
+ MsalBroadcastService,
94
+ ];