@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.
- package/README.md +131 -0
- package/fesm2022/opendevstack-ngx-appshell.mjs +727 -0
- package/fesm2022/opendevstack-ngx-appshell.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/components/appshell-breadcrumb/appshell-breadcrumb.component.d.ts +7 -0
- package/lib/components/appshell-chip/appshell-chip.component.d.ts +6 -0
- package/lib/components/appshell-filters/appshell-filters.component.d.ts +12 -0
- package/lib/components/appshell-header/appshell-header.component.d.ts +24 -0
- package/lib/components/appshell-icon/appshell-icon.component.d.ts +12 -0
- package/lib/components/appshell-layout/appshell-layout.component.d.ts +25 -0
- package/lib/components/appshell-page-header/appshell-page-header.component.d.ts +18 -0
- package/lib/components/appshell-platform-header/appshell-platform-header.component.d.ts +37 -0
- package/lib/components/appshell-platform-layout/appshell-platform-layout.component.d.ts +30 -0
- package/lib/components/appshell-product-card/appshell-product-card.component.d.ts +23 -0
- package/lib/components/appshell-product-card-v2/appshell-product-card-v2.component.d.ts +16 -0
- package/lib/components/appshell-select/appshell-select.component.d.ts +9 -0
- package/lib/components/appshell-sidebar-menu/appshell-sidebar-menu.component.d.ts +12 -0
- package/lib/components/appshell-toast/appshell-toast.component.d.ts +9 -0
- package/lib/components/appshell-toasts/appshell-toasts.component.d.ts +14 -0
- package/lib/components/index.d.ts +15 -0
- package/lib/directives/appshell-link.directive.d.ts +15 -0
- package/lib/directives/index.d.ts +1 -0
- package/lib/models/appshell-button.d.ts +5 -0
- package/lib/models/appshell-filter.d.ts +4 -0
- package/lib/models/appshell-link.d.ts +6 -0
- package/lib/models/appshell-links-group.d.ts +5 -0
- package/lib/models/appshell-notification.d.ts +10 -0
- package/lib/models/appshell-picker.d.ts +9 -0
- package/lib/models/appshell-product.d.ts +12 -0
- package/lib/models/appshell-tag.d.ts +4 -0
- package/lib/models/appshell-toast.d.ts +6 -0
- package/lib/models/appshell-user.d.ts +5 -0
- package/lib/models/index.d.ts +10 -0
- package/lib/screens/appshell-notifications-screen/appshell-notifications-screen.component.d.ts +23 -0
- package/lib/screens/appshell-product-catalog-screen/appshell-product-catalog-screen.component.d.ts +16 -0
- package/lib/screens/appshell-product-view-screen/appshell-product-view-screen.component.d.ts +19 -0
- package/lib/screens/index.d.ts +3 -0
- package/lib/services/appshell-toast.service.d.ts +12 -0
- package/lib/services/icon-registry.service.d.ts +14 -0
- package/lib/services/index.d.ts +2 -0
- package/opendevstack-ngx-appshell-19.0.5.tgz +0 -0
- package/package.json +44 -0
- package/public-api.d.ts +5 -0
- package/schematics/azure-login/files/app-config/config.json.template +12 -0
- package/schematics/azure-login/files/app-config-service/app-config.service.spec.ts.template +48 -0
- package/schematics/azure-login/files/app-config-service/app-config.service.ts.template +39 -0
- package/schematics/azure-login/files/azure-config/azure.config.ts.template +94 -0
- package/schematics/azure-login/files/azure-service/azure.service.spec.ts.template +311 -0
- package/schematics/azure-login/files/azure-service/azure.service.ts.template +161 -0
- package/schematics/azure-login/index.d.ts +2 -0
- package/schematics/azure-login/index.js +325 -0
- package/schematics/azure-login/index.js.map +1 -0
- package/schematics/azure-login/schema.json +8 -0
- package/schematics/collection.json +19 -0
- package/schematics/nats-notifications/files/nats-service/nats.service.spec.ts.template +473 -0
- package/schematics/nats-notifications/files/nats-service/nats.service.ts.template +255 -0
- package/schematics/nats-notifications/files/notifications-screen/notifications-screen.component.html.template +7 -0
- package/schematics/nats-notifications/files/notifications-screen/notifications-screen.component.spec.ts.template +152 -0
- package/schematics/nats-notifications/files/notifications-screen/notifications-screen.component.ts.template +61 -0
- package/schematics/nats-notifications/index.d.ts +2 -0
- package/schematics/nats-notifications/index.js +502 -0
- package/schematics/nats-notifications/index.js.map +1 -0
- package/schematics/nats-notifications/schema.json +8 -0
- package/schematics/ng-add/files/_fonts.scss +85 -0
- package/schematics/ng-add/files/styles.scss +47 -0
- package/schematics/ng-add/index.d.ts +2 -0
- package/schematics/ng-add/index.js +442 -0
- package/schematics/ng-add/index.js.map +1 -0
- package/styles/appshell-typography-config.scss +19 -0
- package/styles/appshell.theme.scss +75 -0
- 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,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,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';
|
package/lib/screens/appshell-notifications-screen/appshell-notifications-screen.component.d.ts
ADDED
|
@@ -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
|
+
}
|
package/lib/screens/appshell-product-catalog-screen/appshell-product-catalog-screen.component.d.ts
ADDED
|
@@ -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,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
|
+
}
|
|
Binary file
|
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
|
+
}
|
package/public-api.d.ts
ADDED
|
@@ -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
|
+
];
|