Skip to content

Commit f4d7958

Browse files
committed
Add standalone mode
1 parent 5153b01 commit f4d7958

22 files changed

+254
-69
lines changed

angular.json

+11
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,14 @@
107107
},
108108
"es5": {
109109
"tsConfig": "tsconfig.app.es5.json"
110+
},
111+
"standalone": {
112+
"fileReplacements": [
113+
{
114+
"replace": "src/environments/environment.ts",
115+
"with": "src/environments/environment.standalone.ts"
116+
}
117+
]
110118
}
111119
},
112120
"defaultConfiguration": ""
@@ -125,6 +133,9 @@
125133
},
126134
"es5": {
127135
"buildTarget": "netzgrafik-frontend:build:es5"
136+
},
137+
"standalone": {
138+
"buildTarget": "netzgrafik-frontend:build:standalone"
128139
}
129140
}
130141
},

package-lock.json

+17
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
"ng": "ng",
44
"start": "ng serve",
55
"start:local": "ng serve --configuration=local",
6+
"start:standalone": "ng serve --configuration=standalone",
67
"e2e:browserstack": "ng e2e -c browserstack",
78
"e2e:puppeteer": "ng e2e -c puppeteer",
89
"build": "ng run netzgrafik-frontend:ngsscbuild",
10+
"build:standalone": "ng build --configuration=standalone",
911
"test": "ng test -c ci",
1012
"lint": "ng lint",
1113
"e2e": "ng e2e",
@@ -24,6 +26,7 @@
2426
"@angular/common": "^17.0.5",
2527
"@angular/compiler": "^17.0.5",
2628
"@angular/core": "^17.0.5",
29+
"@angular/elements": "^17.1.0",
2730
"@angular/forms": "^17.0.5",
2831
"@angular/localize": "^17.0.5",
2932
"@angular/platform-browser": "^17.0.5",

src/app/app.component.html

+11-3
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,17 @@
3030
</button>
3131
</sbb-menu>
3232
</sbb-header-lean>
33-
<sbb-navigation-bar class="noprint"></sbb-navigation-bar>
33+
<ng-container *ngIf="!disableBackend">
34+
<sbb-navigation-bar class="noprint"></sbb-navigation-bar>
35+
</ng-container>
3436
<router-outlet *ngIf="authenticated | async; else loading"></router-outlet>
3537
<ng-template #loading>
36-
<sbb-loading-indicator mode="big"></sbb-loading-indicator>
37-
<div class="login-message">Sie werden angemeldet...</div>
38+
<ng-container *ngIf="!disableBackend">
39+
<sbb-loading-indicator mode="big"></sbb-loading-indicator>
40+
<div class="login-message">Sie werden angemeldet...</div>
41+
</ng-container>
42+
<ng-container *ngIf="disableBackend">
43+
<sbb-netzgrafik-editor></sbb-netzgrafik-editor>
44+
</ng-container>
3845
</ng-template>
46+

src/app/app.component.ts

+35-4
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,66 @@
1-
import {Component} from "@angular/core";
1+
import {Component, Input, Output} from "@angular/core";
22
import {AuthService} from "./services/auth/auth.service";
3+
import {TrainrunService} from "./services/data/trainrun.service";
4+
import {TrainrunSectionService} from "./services/data/trainrunsection.service";
5+
import {DataService} from "./services/data/data.service";
36
import {environment} from "../environments/environment";
47
import packageJson from "../../package.json";
58
import {Observable} from "rxjs";
69
import {ProjectDto} from "./api/generated";
10+
import {NetzgrafikDto} from "./data-structures/business.data.structures";
711

812
@Component({
913
selector: "sbb-root",
1014
templateUrl: "./app.component.html",
1115
styleUrls: ["./app.component.scss"],
1216
})
1317
export class AppComponent {
18+
readonly disableBackend = environment.disableBackend;
19+
1420
version = packageJson.version;
1521
environmentLabel = environment.label;
1622
authenticated: Promise<unknown>;
1723

1824
projectInMenu: Observable<ProjectDto | null>;
1925

2026
get userName() {
27+
if (this.disableBackend) {
28+
return undefined;
29+
}
2130
return this.authService.claims?.name;
2231
}
2332

2433
get email() {
34+
if (this.disableBackend) {
35+
return undefined;
36+
}
2537
return this.authService.claims?.email;
2638
}
2739

28-
constructor(private authService: AuthService) {
29-
this.authenticated = authService.initialized;
40+
constructor(private authService: AuthService, private dataService: DataService, private trainrunService: TrainrunService, private trainrunSectionService: TrainrunSectionService) {
41+
42+
if (!this.disableBackend) {
43+
this.authenticated = authService.initialized;
44+
}
3045
}
3146

3247
logout() {
33-
this.authService.logOut();
48+
if (!this.disableBackend) {
49+
this.authService.logOut();
50+
}
51+
}
52+
53+
@Input()
54+
get netzgrafikDto() {
55+
return this.dataService.getNetzgrafikDto();
3456
}
57+
set netzgrafikDto(netzgrafikDto: NetzgrafikDto) {
58+
this.dataService.loadNetzgrafikDto(netzgrafikDto);
59+
}
60+
61+
@Output()
62+
trainrunOperation = this.trainrunService.operation;
63+
64+
@Output()
65+
trainrunSectionOperation = this.trainrunSectionService.operation;
3566
}

src/app/app.module.ts

+16-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import {NgModule} from "@angular/core";
1+
import {NgModule, Injector, ApplicationRef, DoBootstrap} from "@angular/core";
22
import {NgxEditorModule} from "ngx-editor";
33
import {BrowserModule} from "@angular/platform-browser";
4+
import {createCustomElement} from "@angular/elements";
45
import {HTTP_INTERCEPTORS, HttpClientModule} from "@angular/common/http";
56
import {OAuthModule} from "angular-oauth2-oidc";
67
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
@@ -203,7 +204,7 @@ import {ActionMenuComponent} from "./view/action-menu/action-menu/action-menu.co
203204
// and you send a request to these, the access token is appended.
204205
// Documentation:
205206
// https://manfredsteyer.github.io/angular-oauth2-oidc/docs/additional-documentation/working-with-httpinterceptors.html
206-
allowedUrls: [environment.backendUrl],
207+
allowedUrls: environment.backendUrl ? [environment.backendUrl] : [],
207208
sendAccessToken: true,
208209
},
209210
}),
@@ -230,10 +231,20 @@ import {ActionMenuComponent} from "./view/action-menu/action-menu/action-menu.co
230231
SbbBreadcrumbModule,
231232
SbbAutocompleteModule,
232233
],
233-
bootstrap: [AppComponent],
234+
bootstrap: environment.customElement ? [] : [AppComponent],
234235
providers: [
235-
{provide: BASE_PATH, useValue: environment.backendUrl},
236+
... environment.backendUrl ? [{provide: BASE_PATH, useValue: environment.backendUrl}] : [],
236237
{provide: HTTP_INTERCEPTORS, useClass: HttpErrorInterceptor, multi: true},
237238
],
238239
})
239-
export class AppModule {}
240+
241+
export class AppModule implements DoBootstrap {
242+
constructor(private injector: Injector) {}
243+
244+
ngDoBootstrap(appRef: ApplicationRef) {
245+
if (environment.customElement) {
246+
const element = createCustomElement(AppComponent, {injector: this.injector});
247+
customElements.define("sbb-root", element);
248+
}
249+
}
250+
}

src/app/models/operation.model.ts

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import {Trainrun} from "./trainrun.model";
2+
import {TrainrunSection} from "./trainrunsection.model";
3+
4+
enum OperationType {
5+
create = "create",
6+
update = "update",
7+
delete = "delete"
8+
}
9+
10+
export abstract class Operation{
11+
type: string;
12+
}
13+
14+
export class CreateTrainrunOperation extends Operation {
15+
readonly trainrunSection: TrainrunSection;
16+
17+
constructor(trainrunSection: TrainrunSection){
18+
super();
19+
this.type = OperationType.create;
20+
this.trainrunSection = trainrunSection;
21+
}
22+
}
23+
24+
export class UpdateTrainrunSectionsOperation extends Operation {
25+
readonly trainrunSections: TrainrunSection[];
26+
27+
constructor(trainrunSections: TrainrunSection[]){
28+
super();
29+
this.type = OperationType.update;
30+
this.trainrunSections = trainrunSections;
31+
}
32+
}
33+
34+
export class DeleteTrainrunOperation extends Operation {
35+
readonly trainrun: Trainrun;
36+
37+
constructor(trainrun: Trainrun){
38+
super();
39+
this.type = OperationType.delete;
40+
this.trainrun = trainrun;
41+
}
42+
}

src/app/netzgrafik-application/netzgrafik-application.component.html

+20-18
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
1-
<sbb-icon-sidebar-container>
2-
<sbb-icon-sidebar [(expanded)]="expanded">
1+
<sbb-icon-sidebar-container [attr.style]="getSidebarContainerStyle()">
2+
<sbb-icon-sidebar [(expanded)]="expanded" >
33
<!--<a sbbIconSidebarItem label="Varianten" (click)="onVariantenClicked()" class="sbb-active">-->
4-
<a
5-
sbbIconSidebarItem
6-
label="Varianten"
7-
[class]="getVariantsActivatedTag()"
8-
(click)="onVariantenClicked()"
9-
>
10-
<sbb-icon
11-
*ngIf="getVariantIsWritable()"
12-
svgIcon="document-standard-small"
13-
></sbb-icon>
14-
<sbb-icon
15-
*ngIf="!getVariantIsWritable()"
16-
svgIcon="folder-lock-small"
17-
style="color: #c60018"
18-
></sbb-icon>
19-
</a>
4+
<ng-container *ngIf="!disableBackend">
5+
<a
6+
sbbIconSidebarItem
7+
label="Varianten"
8+
[class]="getVariantsActivatedTag()"
9+
(click)="onVariantenClicked()"
10+
>
11+
<sbb-icon
12+
*ngIf="getVariantIsWritable()"
13+
svgIcon="document-standard-small"
14+
></sbb-icon>
15+
<sbb-icon
16+
*ngIf="!getVariantIsWritable()"
17+
svgIcon="folder-lock-small"
18+
style="color: #c60018"
19+
></sbb-icon>
20+
</a>
21+
</ng-container>
2022
<a
2123
sbbIconSidebarItem
2224
label="Filter"

src/app/netzgrafik-application/netzgrafik-application.component.scss

-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
sbb-icon-sidebar-container {
2-
top: 85px;
3-
}
4-
51
::ng-deep a.SideBarMainIcon {
62
background: whitesmoke;
73
}

src/app/netzgrafik-application/netzgrafik-application.component.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {DomSanitizer} from "@angular/platform-browser";
1212
import {EditorMode} from "../view/editor-menu/editor-mode";
1313
import {UndoService} from "../services/data/undo.service";
1414
import {EditorView} from "../view/editor-main-view/data-views/editor.view";
15+
import {NetzgrafikDefault} from "../sample-netzgrafik/netzgrafik.default";
16+
import {environment} from "../../environments/environment";
1517

1618
export enum IconSidebarMode {
1719
VARIANTEN = "varianten",
@@ -29,6 +31,8 @@ export class NetzgrafikApplicationComponent {
2931
mode = IconSidebarMode.NONE;
3032
expanded = false;
3133

34+
readonly disableBackend = environment.disableBackend;
35+
3236
private readonly destroyed = new Subject<void>();
3337

3438
constructor(
@@ -48,13 +52,24 @@ export class NetzgrafikApplicationComponent {
4852
.subscribe((params) => {
4953
uiInteractionService.setEditorMode(EditorMode.NetzgrafikEditing);
5054
uiInteractionService.showNetzgrafik();
51-
versionControlService.load(params.getVariantId(), true);
55+
try {
56+
versionControlService.load(params.getVariantId(), true);
57+
} catch (e) {
58+
versionControlService.loadNetzgrafikDTO(NetzgrafikDefault.getDefaultNetzgrafik());
59+
}
5260
uiInteractionService.setViewboxProperties(
5361
EditorView.svgName,
5462
uiInteractionService.getDefaultViewProperties());
5563
});
5664
}
5765

66+
getSidebarContainerStyle(): string {
67+
if (this.disableBackend) {
68+
return "top: 53px;";
69+
}
70+
return "top: 85px;";
71+
}
72+
5873
getVariantIsWritable(): boolean {
5974
if (this.versionControlService.variant === null) {
6075
return true;

src/app/services/auth/auth.service.ts

+23-21
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,29 @@ export class AuthService {
3030
private router: Router,
3131
location: Location,
3232
) {
33-
this.oauthService.configure(environment.authConfig);
34-
this.oauthService.setupAutomaticSilentRefresh();
35-
// If the user should not be forcefully logged in (e.g. if you have pages, which can be
36-
// accessed anonymously), change loadDiscoveryDocumentAndLogin to
37-
// loadDiscoveryDocumentAndTryLogin and have a login functionality in the
38-
// template of the component injecting the AuthService which calls the login() method.
39-
this.initialized = this.oauthService
40-
.loadDiscoveryDocumentAndLogin({state: location.path()})
41-
// If the user is not logged in, he will be forwarded to the identity provider
42-
// and this promise will not resolve. After being redirected from the identity
43-
// provider, the login promise will return true.
44-
.then((v) => (v ? true : new Promise(() => {})));
45-
// Redirect the user to the url configured with state above or in a separate login call.
46-
this.oauthService.events
47-
.pipe(first((e) => e.type === "token_received"))
48-
.subscribe(() => {
49-
const state = decodeURIComponent(this.oauthService.state || "");
50-
if (state && state !== "/") {
51-
this.router.navigate([state]);
52-
}
53-
});
33+
if (!environment.disableBackend) {
34+
this.oauthService.configure(environment.authConfig);
35+
this.oauthService.setupAutomaticSilentRefresh();
36+
// If the user should not be forcefully logged in (e.g. if you have pages, which can be
37+
// accessed anonymously), change loadDiscoveryDocumentAndLogin to
38+
// loadDiscoveryDocumentAndTryLogin and have a login functionality in the
39+
// template of the component injecting the AuthService which calls the login() method.
40+
this.initialized = this.oauthService
41+
.loadDiscoveryDocumentAndLogin({state: location.path()})
42+
// If the user is not logged in, he will be forwarded to the identity provider
43+
// and this promise will not resolve. After being redirected from the identity
44+
// provider, the login promise will return true.
45+
.then((v) => (v ? true : new Promise(() => {})));
46+
// Redirect the user to the url configured with state above or in a separate login call.
47+
this.oauthService.events
48+
.pipe(first((e) => e.type === "token_received"))
49+
.subscribe(() => {
50+
const state = decodeURIComponent(this.oauthService.state || "");
51+
if (state && state !== "/") {
52+
this.router.navigate([state]);
53+
}
54+
});
55+
}
5456
}
5557

5658
logOut() {

0 commit comments

Comments
 (0)