@abgov/nx-adsp 12.4.0 → 12.5.0
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/generators.json +6 -0
- package/package.json +1 -1
- package/src/generators/angular-app/angular-app.js +22 -7
- package/src/generators/angular-app/angular-app.js.map +1 -1
- package/src/generators/angular-app/files/nginx.conf__tmpl__ +14 -7
- package/src/generators/angular-app/files/src/app/app.component.css__tmpl__ +10 -54
- package/src/generators/angular-app/files/src/app/app.component.html__tmpl__ +18 -49
- package/src/generators/angular-app/files/src/app/app.component.spec.ts__tmpl__ +22 -27
- package/src/generators/angular-app/files/src/app/app.component.ts__tmpl__ +60 -20
- package/src/generators/angular-app/files/src/app/app.config.ts__tmpl__ +27 -0
- package/src/generators/angular-app/files/src/app/app.routes.ts__tmpl__ +10 -31
- package/src/generators/angular-app/files/src/app/home/home.component.html__tmpl__ +1 -3
- package/src/generators/angular-app/files/src/app/home/home.component.ts__tmpl__ +9 -23
- package/src/generators/angular-app/files/src/app/protected/protected.component.html__tmpl__ +2 -2
- package/src/generators/angular-app/files/src/app/protected/protected.component.spec.ts__tmpl__ +27 -43
- package/src/generators/angular-app/files/src/app/protected/protected.component.ts__tmpl__ +15 -15
- package/src/generators/angular-app/files/src/app/services/auth-guard.service.ts__tmpl__ +12 -21
- package/src/generators/angular-app/files/src/environments/environment.ts__tmpl__ +2 -11
- package/src/generators/angular-app/files/src/index.html__tmpl__ +3 -9
- package/src/generators/angular-app/files/src/main.ts__tmpl__ +8 -12
- package/src/generators/angular-app/files/src/silent-check-sso.html__tmpl__ +5 -0
- package/src/generators/angular-app/files/src/styles.css__tmpl__ +2 -2
- package/src/generators/mean/mean.d.ts +3 -0
- package/src/generators/mean/mean.js +30 -0
- package/src/generators/mean/mean.js.map +1 -0
- package/src/generators/mean/mean.spec.ts +38 -0
- package/src/generators/mean/schema.d.ts +11 -0
- package/src/generators/mean/schema.json +26 -0
- package/src/generators/mern/mern.js +5 -21
- package/src/generators/mern/mern.js.map +1 -1
- package/src/generators/mern/schema.d.ts +0 -4
- package/src/generators/react-app/files/nginx.conf__tmpl__ +18 -7
- package/src/generators/react-app/react-app.js +6 -0
- package/src/generators/react-app/react-app.js.map +1 -1
- package/src/generators/angular-app/files/src/app/app.module.ts__tmpl__ +0 -47
- package/src/generators/angular-app/files/src/app/auth-callback/auth-callback.component.css__tmpl__ +0 -13
- package/src/generators/angular-app/files/src/app/auth-callback/auth-callback.component.html__tmpl__ +0 -12
- package/src/generators/angular-app/files/src/app/auth-callback/auth-callback.component.spec.ts__tmpl__ +0 -33
- package/src/generators/angular-app/files/src/app/auth-callback/auth-callback.component.ts__tmpl__ +0 -48
- package/src/generators/angular-app/files/src/app/auth.interceptor.ts__tmpl__ +0 -24
- package/src/generators/angular-app/files/src/app/logout/logout.component.html__tmpl__ +0 -1
- package/src/generators/angular-app/files/src/app/logout/logout.component.ts__tmpl__ +0 -9
- package/src/generators/angular-app/files/src/app/services/auth.service.ts__tmpl__ +0 -57
- package/src/generators/angular-app/files/src/app/tenant.service.ts__tmpl__ +0 -19
- package/src/generators/angular-app/files/src/environments/config.ts__tmpl__ +0 -21
- /package/src/generators/angular-app/files/{src → public}/assets/banner.jpg +0 -0
- /package/src/generators/angular-app/files/{src → public}/assets/github-1.svg +0 -0
- /package/src/generators/angular-app/files/{src → public}/favicon.ico +0 -0
package/generators.json
CHANGED
|
@@ -43,6 +43,12 @@
|
|
|
43
43
|
"factory": "./src/generators/angular-app/angular-app",
|
|
44
44
|
"schema": "./src/generators/angular-app/schema.json",
|
|
45
45
|
"description": "Generator that creates a Angular based frontend application."
|
|
46
|
+
},
|
|
47
|
+
"mean": {
|
|
48
|
+
"factory": "./src/generators/mean/mean",
|
|
49
|
+
"schema": "./src/generators/mean/schema.json",
|
|
50
|
+
"description": "Generator that creates a MEAN fullstack solution.",
|
|
51
|
+
"hidden": true
|
|
46
52
|
}
|
|
47
53
|
}
|
|
48
54
|
}
|
package/package.json
CHANGED
|
@@ -56,6 +56,7 @@ function removeFiles(host, options) {
|
|
|
56
56
|
}
|
|
57
57
|
function default_1(host, options) {
|
|
58
58
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
59
|
+
var _a, _b;
|
|
59
60
|
const normalizedOptions = yield normalizeOptions(host, options);
|
|
60
61
|
const { applicationGenerator: initAngular } = yield Promise.resolve().then(() => require('@nx/angular/generators'));
|
|
61
62
|
yield initAngular(host, {
|
|
@@ -64,17 +65,31 @@ function default_1(host, options) {
|
|
|
64
65
|
linter: 'none',
|
|
65
66
|
directory: `apps/${options.name}`
|
|
66
67
|
});
|
|
67
|
-
(0, devkit_1.addDependenciesToPackageJson)(host, {
|
|
68
|
-
'@abgov/angular-components': '
|
|
69
|
-
'@abgov/
|
|
70
|
-
'
|
|
71
|
-
|
|
68
|
+
(0, devkit_1.addDependenciesToPackageJson)(host, {
|
|
69
|
+
'@abgov/angular-components': '5.2.1',
|
|
70
|
+
'@abgov/design-tokens': '1.8.0',
|
|
71
|
+
'@abgov/ui-components-common': '^2.0.0',
|
|
72
|
+
'@abgov/web-components': '1.39.3',
|
|
73
|
+
'keycloak-angular': '^19.0.2',
|
|
74
|
+
'keycloak-js': '^23.0.7',
|
|
75
|
+
'zone.js': '~0.15.0',
|
|
76
|
+
}, {});
|
|
72
77
|
const addedProxy = addFiles(host, normalizedOptions);
|
|
73
|
-
|
|
78
|
+
// @nx/angular generates app.ts/html/css/spec.ts (new naming) and nx-welcome.ts;
|
|
79
|
+
// our templates use app.component.* and don't use nx-welcome.
|
|
80
|
+
for (const file of ['app.ts', 'app.html', 'app.css', 'app.spec.ts', 'nx-welcome.ts']) {
|
|
81
|
+
host.delete(`${normalizedOptions.projectRoot}/src/app/${file}`);
|
|
82
|
+
}
|
|
74
83
|
const layout = (0, devkit_1.getWorkspaceLayout)(host);
|
|
75
84
|
const config = (0, devkit_1.readProjectConfiguration)(host, options.name);
|
|
76
|
-
|
|
85
|
+
// Remove the generated fileReplacements for production — single environment.ts
|
|
86
|
+
// is pre-populated from tenant config at generation time.
|
|
87
|
+
if ((_b = (_a = config.targets.build.configurations) === null || _a === void 0 ? void 0 : _a.production) === null || _b === void 0 ? void 0 : _b.fileReplacements) {
|
|
88
|
+
delete config.targets.build.configurations.production.fileReplacements;
|
|
89
|
+
}
|
|
90
|
+
config.targets.build.options = Object.assign(Object.assign({}, config.targets.build.options), { polyfills: ['zone.js'], assets: [
|
|
77
91
|
...config.targets.build.options.assets,
|
|
92
|
+
`${normalizedOptions.projectRoot}/src/silent-check-sso.html`,
|
|
78
93
|
{
|
|
79
94
|
glob: 'nginx.conf',
|
|
80
95
|
input: `${layout.appsDir}/${options.name}`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"angular-app.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/angular-app/angular-app.ts"],"names":[],"mappings":";;AAkGA,
|
|
1
|
+
{"version":3,"file":"angular-app.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/angular-app/angular-app.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,25 +1,32 @@
|
|
|
1
1
|
events {
|
|
2
|
-
worker_connections
|
|
2
|
+
worker_connections 1024;
|
|
3
3
|
}
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
http {
|
|
5
6
|
sendfile on;
|
|
6
7
|
include mime.types;
|
|
7
8
|
default_type application/octet-stream;
|
|
8
9
|
|
|
10
|
+
gzip on;
|
|
11
|
+
gzip_types text/plain text/css application/javascript application/json image/svg+xml font/woff2;
|
|
12
|
+
gzip_min_length 1000;
|
|
13
|
+
|
|
9
14
|
server {
|
|
10
|
-
|
|
11
15
|
listen 8080;
|
|
12
16
|
root /opt/app-root/src;
|
|
13
17
|
index index.html;
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
|
20
|
+
add_header X-Content-Type-Options "nosniff" always;
|
|
21
|
+
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
22
|
+
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
23
|
+
|
|
24
|
+
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
|
17
25
|
expires 30d;
|
|
18
26
|
add_header Cache-Control "public, no-transform";
|
|
19
|
-
}
|
|
27
|
+
}
|
|
20
28
|
|
|
21
29
|
location / {
|
|
22
|
-
gzip on;
|
|
23
30
|
try_files $uri /index.html;
|
|
24
31
|
}
|
|
25
32
|
<% nginxProxies.forEach(function(nginxProxy){ %>
|
|
@@ -1,36 +1,16 @@
|
|
|
1
|
-
.
|
|
2
|
-
|
|
3
|
-
margin: 0 auto;
|
|
4
|
-
padding: 0;
|
|
1
|
+
.app {
|
|
2
|
+
margin: 0;
|
|
5
3
|
}
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
padding: 3rem 1rem;
|
|
11
|
-
width: 640px;
|
|
12
|
-
}
|
|
5
|
+
main {
|
|
6
|
+
display: grid;
|
|
7
|
+
grid-template-columns: repeat(6, auto);
|
|
13
8
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
@media (min-width: 1024px) {
|
|
22
|
-
.container {
|
|
23
|
-
padding: 3rem 1rem;
|
|
24
|
-
margin: 0 auto;
|
|
25
|
-
width: 1024px;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
@media (min-width: 1280px) {
|
|
29
|
-
.container {
|
|
30
|
-
padding: 3rem 1rem;
|
|
31
|
-
margin: 0 auto;
|
|
32
|
-
width: 1280px;
|
|
33
|
-
}
|
|
9
|
+
|
|
10
|
+
section {
|
|
11
|
+
grid-column: 2 / span 2;
|
|
12
|
+
margin-top: 40px;
|
|
13
|
+
margin-bottom: 40px;
|
|
34
14
|
}
|
|
35
15
|
|
|
36
16
|
.nextSteps {
|
|
@@ -42,27 +22,3 @@
|
|
|
42
22
|
margin-bottom: 0;
|
|
43
23
|
line-height: 50px;
|
|
44
24
|
}
|
|
45
|
-
|
|
46
|
-
.nextSteps li button {
|
|
47
|
-
margin: 20px 0 0 10px;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
.footer {
|
|
52
|
-
background-color: #f1f1f1;
|
|
53
|
-
padding-top: 56px;
|
|
54
|
-
padding-bottom: 56px;
|
|
55
|
-
padding-left: 150px;
|
|
56
|
-
padding-right: 150px;
|
|
57
|
-
display: flex;
|
|
58
|
-
flex-direction: row;
|
|
59
|
-
flex-wrap: wrap;
|
|
60
|
-
border-bottom: 16px solid #0081a2;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
@media (max-width: 767px) {
|
|
64
|
-
/* On small screens, the nav menu spans the full width of the screen. Leave a space for it. */
|
|
65
|
-
.body-content {
|
|
66
|
-
padding-top: 50px;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
@@ -1,58 +1,27 @@
|
|
|
1
1
|
<div class="app">
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
<goab-microsite-header type="alpha"></goab-microsite-header>
|
|
3
|
+
<goab-app-header url="/" heading="<%= projectName %>">
|
|
4
|
+
<goab-button-group alignment="end">
|
|
5
|
+
@if (userName) { <span>{{ userName }}</span> }
|
|
6
|
+
@if (!isLoggedIn) {
|
|
7
|
+
<goab-button type="tertiary" (onClick)="login()">Sign in</goab-button>
|
|
8
|
+
} @else {
|
|
9
|
+
<goab-button type="tertiary" (onClick)="logout()">Sign out</goab-button>
|
|
10
|
+
}
|
|
11
|
+
</goab-button-group>
|
|
12
|
+
</goab-app-header>
|
|
13
|
+
<goab-hero-banner #heroBanner heading="<%= projectName %>"></goab-hero-banner>
|
|
14
|
+
<main>
|
|
10
15
|
<section>
|
|
11
16
|
<h2>Welcome to {{ title }}!</h2>
|
|
12
|
-
<p>
|
|
13
|
-
Don't panic. Start editing the project to build your digital service.
|
|
14
|
-
</p>
|
|
17
|
+
<p>Don't panic. Start editing the project to build your digital service.</p>
|
|
15
18
|
<h3>A few things you might want to do next:</h3>
|
|
16
19
|
<ul class="nextSteps">
|
|
17
|
-
<li>
|
|
18
|
-
<li>
|
|
19
|
-
|
|
20
|
-
enabling CORS on the API.
|
|
21
|
-
</li>
|
|
22
|
-
<li>Add requests to public API resources:</li>
|
|
23
|
-
<li>Add requests to private API resources:</li>
|
|
20
|
+
<li>Register the '<%= projectName %>' client in your realm and set CLIENT_SECRET.</li>
|
|
21
|
+
<li>Add requests to public API resources: {{ publicResource }}</li>
|
|
22
|
+
<li>Add requests to private API resources: {{ privateResource }}</li>
|
|
24
23
|
</ul>
|
|
25
24
|
</section>
|
|
26
|
-
<
|
|
27
|
-
<div class="row">
|
|
28
|
-
<h3><a routerLink="/">Home</a> | <a routerLink="/protected">Admin Area</a></h3>
|
|
29
|
-
<div *ngIf="isLoggedIn(); else elseBlock">
|
|
30
|
-
<goa-button (click)="logout()">
|
|
31
|
-
Sign Out
|
|
32
|
-
</goa-button>
|
|
33
|
-
</div>
|
|
34
|
-
<ng-template #elseBlock>
|
|
35
|
-
<goa-button (click)="login()">
|
|
36
|
-
Sign In
|
|
37
|
-
</goa-button>
|
|
38
|
-
</ng-template>
|
|
39
|
-
<div class="col-sm-12 body-content">
|
|
40
|
-
<router-outlet></router-outlet>
|
|
41
|
-
</div>
|
|
42
|
-
</div>
|
|
43
|
-
</div>
|
|
25
|
+
<router-outlet></router-outlet>
|
|
44
26
|
</main>
|
|
45
|
-
<footer class="footer">
|
|
46
|
-
<div class="goa-socialconnect">
|
|
47
|
-
<div class="goa-title">Connect with us on</div>
|
|
48
|
-
<ul>
|
|
49
|
-
<div>
|
|
50
|
-
<img src="./assets/github-1.svg" height="15px" />
|
|
51
|
-
<a href="https://github.com/abgov" rel="noreferrer" target="_blank">
|
|
52
|
-
GitHub
|
|
53
|
-
</a>
|
|
54
|
-
</div>
|
|
55
|
-
</ul>
|
|
56
|
-
</div>
|
|
57
|
-
</footer>
|
|
58
27
|
</div>
|
|
@@ -1,44 +1,39 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ElementRef } from '@angular/core';
|
|
2
|
+
import { TestBed } from '@angular/core/testing';
|
|
3
|
+
import { provideRouter } from '@angular/router';
|
|
4
|
+
import { GoabAppHeader, GoabButton, GoabButtonGroup, GoabHeroBanner, GoabMicrositeHeader } from '@abgov/angular-components';
|
|
5
|
+
import Keycloak from 'keycloak-js';
|
|
2
6
|
import { AppComponent } from './app.component';
|
|
3
|
-
import { AngularComponentsModule } from '@abgov/angular-components';
|
|
4
|
-
import { RouterTestingModule } from '@angular/router/testing';
|
|
5
|
-
import {
|
|
6
|
-
BrowserDynamicTestingModule,
|
|
7
|
-
platformBrowserDynamicTesting
|
|
8
|
-
} from "@angular/platform-browser-dynamic/testing";
|
|
9
|
-
|
|
10
7
|
|
|
11
8
|
describe('AppComponent', () => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
const keycloakMock = {
|
|
10
|
+
authenticated: false,
|
|
11
|
+
tokenParsed: null,
|
|
12
|
+
login: jasmine.createSpy('login'),
|
|
13
|
+
logout: jasmine.createSpy('logout'),
|
|
14
|
+
};
|
|
17
15
|
|
|
18
|
-
|
|
16
|
+
beforeEach(async () => {
|
|
19
17
|
await TestBed.configureTestingModule({
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
imports: [AppComponent, GoabAppHeader, GoabButton, GoabButtonGroup, GoabHeroBanner, GoabMicrositeHeader],
|
|
19
|
+
providers: [
|
|
20
|
+
provideRouter([]),
|
|
21
|
+
{ provide: Keycloak, useValue: keycloakMock },
|
|
22
|
+
{ provide: ElementRef, useValue: { nativeElement: { querySelector: () => null } } },
|
|
23
|
+
],
|
|
22
24
|
}).compileComponents();
|
|
23
25
|
});
|
|
24
26
|
|
|
25
27
|
it('should create the app', () => {
|
|
26
28
|
const fixture = TestBed.createComponent(AppComponent);
|
|
27
|
-
|
|
28
|
-
expect(app).toBeTruthy();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it(`should have as title '<%= projectName %>'`, () => {
|
|
32
|
-
const fixture = TestBed.createComponent(AppComponent);
|
|
33
|
-
const app = fixture.componentInstance;
|
|
34
|
-
expect(app.title).toEqual('<%= projectName %>');
|
|
29
|
+
expect(fixture.componentInstance).toBeTruthy();
|
|
35
30
|
});
|
|
36
31
|
|
|
37
|
-
it('should
|
|
32
|
+
it('should have welcome heading', () => {
|
|
38
33
|
const fixture = TestBed.createComponent(AppComponent);
|
|
39
34
|
fixture.detectChanges();
|
|
40
|
-
const compiled = fixture.nativeElement;
|
|
41
|
-
expect(compiled.querySelector('h2')
|
|
35
|
+
const compiled = fixture.nativeElement as HTMLElement;
|
|
36
|
+
expect(compiled.querySelector('h2')?.textContent).toContain(
|
|
42
37
|
'Welcome to <%= projectName %>!'
|
|
43
38
|
);
|
|
44
39
|
});
|
|
@@ -1,36 +1,76 @@
|
|
|
1
|
-
import { Component, OnDestroy, OnInit } from '@angular/core';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
1
|
+
import { AfterViewInit, Component, ElementRef, inject, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
|
2
|
+
import { HttpClient } from '@angular/common/http';
|
|
3
|
+
import { RouterOutlet } from '@angular/router';
|
|
4
|
+
import {
|
|
5
|
+
GoabAppHeader,
|
|
6
|
+
GoabButton,
|
|
7
|
+
GoabButtonGroup,
|
|
8
|
+
GoabHeroBanner,
|
|
9
|
+
GoabMicrositeHeader,
|
|
10
|
+
} from '@abgov/angular-components';
|
|
11
|
+
import Keycloak from 'keycloak-js';
|
|
12
|
+
import { getAccessToken } from './user.slice';
|
|
5
13
|
|
|
6
14
|
@Component({
|
|
7
|
-
selector: '<%= projectName %>-
|
|
15
|
+
selector: '<%= projectName %>-root',
|
|
16
|
+
standalone: true,
|
|
17
|
+
imports: [RouterOutlet, GoabAppHeader, GoabButton, GoabButtonGroup, GoabHeroBanner, GoabMicrositeHeader],
|
|
8
18
|
templateUrl: './app.component.html',
|
|
9
|
-
|
|
19
|
+
styleUrl: './app.component.css',
|
|
10
20
|
})
|
|
21
|
+
export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
22
|
+
title = '<%= projectName %>';
|
|
11
23
|
|
|
12
|
-
|
|
13
|
-
title = "<%= projectName %>";
|
|
24
|
+
@ViewChild('heroBanner', { read: ElementRef, static: false }) heroBannerRef!: ElementRef;
|
|
14
25
|
|
|
15
|
-
|
|
26
|
+
private http = inject(HttpClient);
|
|
27
|
+
private keycloak = inject(Keycloak);
|
|
28
|
+
private heroObserver?: MutationObserver;
|
|
16
29
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
30
|
+
publicResource = 'Not retrieved';
|
|
31
|
+
privateResource = 'Not retrieved';
|
|
32
|
+
|
|
33
|
+
get isLoggedIn(): boolean { return this.keycloak.authenticated ?? false; }
|
|
34
|
+
get userName(): string { return (this.keycloak.tokenParsed?.['name'] as string) ?? ''; }
|
|
20
35
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
this.
|
|
36
|
+
ngOnInit() {
|
|
37
|
+
this.http.get<{ message: string }>('/api/v1/public').subscribe({
|
|
38
|
+
next: (data) => (this.publicResource = data.message),
|
|
39
|
+
error: () => (this.publicResource = 'Error loading data'),
|
|
40
|
+
});
|
|
41
|
+
if (this.isLoggedIn) {
|
|
42
|
+
getAccessToken().then((token) => {
|
|
43
|
+
this.http.get<{ message: string }>('/api/v1/private', {
|
|
44
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
45
|
+
}).subscribe({
|
|
46
|
+
next: (data) => (this.privateResource = data.message),
|
|
47
|
+
error: () => (this.privateResource = 'Error loading data'),
|
|
48
|
+
});
|
|
49
|
+
});
|
|
24
50
|
}
|
|
25
51
|
}
|
|
26
52
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
53
|
+
ngAfterViewInit() {
|
|
54
|
+
const host = this.heroBannerRef?.nativeElement;
|
|
55
|
+
if (!host) return;
|
|
56
|
+
const setBackground = (inner: Element) => {
|
|
57
|
+
(inner as any).backgroundurl = '/assets/banner.jpg';
|
|
58
|
+
this.heroObserver?.disconnect();
|
|
59
|
+
};
|
|
60
|
+
const existing = host.querySelector('goa-hero-banner');
|
|
61
|
+
if (existing) {
|
|
62
|
+
setBackground(existing);
|
|
63
|
+
} else {
|
|
64
|
+
this.heroObserver = new MutationObserver(() => {
|
|
65
|
+
const inner = host.querySelector('goa-hero-banner');
|
|
66
|
+
if (inner) setBackground(inner);
|
|
67
|
+
});
|
|
68
|
+
this.heroObserver.observe(host, { childList: true, subtree: true });
|
|
30
69
|
}
|
|
31
70
|
}
|
|
32
71
|
|
|
33
|
-
|
|
72
|
+
ngOnDestroy() { this.heroObserver?.disconnect(); }
|
|
34
73
|
|
|
35
|
-
|
|
74
|
+
login() { this.keycloak.login(); }
|
|
75
|
+
logout() { this.keycloak.logout({ redirectUri: window.location.origin }); }
|
|
36
76
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
|
|
2
|
+
import { provideRouter } from '@angular/router';
|
|
3
|
+
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
|
4
|
+
import { includeBearerTokenInterceptor, provideKeycloak } from 'keycloak-angular';
|
|
5
|
+
|
|
6
|
+
import { routes } from './app.routes';
|
|
7
|
+
import { environment } from '../environments/environment';
|
|
8
|
+
|
|
9
|
+
export const appConfig: ApplicationConfig = {
|
|
10
|
+
providers: [
|
|
11
|
+
provideZoneChangeDetection({ eventCoalescing: true }),
|
|
12
|
+
provideRouter(routes),
|
|
13
|
+
provideHttpClient(withInterceptors([includeBearerTokenInterceptor])),
|
|
14
|
+
provideKeycloak({
|
|
15
|
+
config: {
|
|
16
|
+
url: environment.access.url,
|
|
17
|
+
realm: environment.access.realm,
|
|
18
|
+
clientId: environment.access.client_id,
|
|
19
|
+
},
|
|
20
|
+
initOptions: {
|
|
21
|
+
onLoad: 'check-sso',
|
|
22
|
+
pkceMethod: 'S256',
|
|
23
|
+
silentCheckSsoRedirectUri: `${window.location.origin}/silent-check-sso.html`,
|
|
24
|
+
},
|
|
25
|
+
}),
|
|
26
|
+
],
|
|
27
|
+
};
|
|
@@ -1,34 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { Routes, RouterModule } from '@angular/router';
|
|
4
|
-
import { HomeComponent } from './home/home.component';
|
|
1
|
+
import { Routes } from '@angular/router';
|
|
2
|
+
import { createAuthGuard } from 'keycloak-angular';
|
|
5
3
|
import { ProtectedComponent } from './protected/protected.component';
|
|
6
|
-
import { AuthGuardService } from './services/auth-guard.service';
|
|
7
|
-
import { AuthCallbackComponent } from './auth-callback/auth-callback.component';
|
|
8
4
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
path: 'protected',
|
|
17
|
-
component: ProtectedComponent,
|
|
18
|
-
canActivate: [AuthGuardService],
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
path: 'auth-callback',
|
|
22
|
-
component: AuthCallbackComponent,
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
path: 'signout/callback',
|
|
26
|
-
component: LogoutComponent,
|
|
27
|
-
},
|
|
28
|
-
];
|
|
5
|
+
const authGuard = createAuthGuard(async (_route, _state, { authenticated, keycloak }) => {
|
|
6
|
+
if (authenticated) return true;
|
|
7
|
+
await keycloak.login({ redirectUri: window.location.href });
|
|
8
|
+
return false;
|
|
9
|
+
});
|
|
29
10
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
})
|
|
34
|
-
export class AppRoutingModule {}
|
|
11
|
+
export const routes: Routes = [
|
|
12
|
+
{ path: 'protected', component: ProtectedComponent, canActivate: [authGuard] },
|
|
13
|
+
];
|
|
@@ -1,33 +1,19 @@
|
|
|
1
|
-
import { Component, OnInit } from '@angular/core';
|
|
1
|
+
import { Component, inject, OnInit, signal } from '@angular/core';
|
|
2
2
|
import { HttpClient } from '@angular/common/http';
|
|
3
3
|
|
|
4
4
|
@Component({
|
|
5
|
-
selector: '<%= projectName %>-
|
|
5
|
+
selector: '<%= projectName %>-home',
|
|
6
|
+
standalone: true,
|
|
6
7
|
templateUrl: 'home.component.html',
|
|
7
8
|
})
|
|
8
9
|
export class HomeComponent implements OnInit {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
private getHealthUrl = `${this.configData().tenantApi.host}/health`;
|
|
13
|
-
|
|
14
|
-
getHealth() {
|
|
15
|
-
const uptimePromise = this.http.get(this.getHealthUrl);
|
|
16
|
-
|
|
17
|
-
uptimePromise.subscribe(
|
|
18
|
-
(data: any) => {
|
|
19
|
-
this.uptime = data.uptime;
|
|
20
|
-
},
|
|
21
|
-
(err) => console.error(err),
|
|
22
|
-
() => console.log('done loading uptime')
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
configData () {
|
|
27
|
-
return JSON.parse(localStorage.getItem('envData') || "\"\"");
|
|
28
|
-
}
|
|
10
|
+
private http = inject(HttpClient);
|
|
11
|
+
publicMessage = signal('Not retrieved');
|
|
29
12
|
|
|
30
13
|
ngOnInit() {
|
|
31
|
-
this.
|
|
14
|
+
this.http.get<{ message: string }>('/api/v1/public').subscribe({
|
|
15
|
+
next: (data) => this.publicMessage.set(data.message),
|
|
16
|
+
error: () => this.publicMessage.set('Error loading data'),
|
|
17
|
+
});
|
|
32
18
|
}
|
|
33
19
|
}
|