Skip to content

Commit

Permalink
feat: sfera playground (#143)
Browse files Browse the repository at this point in the history
  • Loading branch information
mghilardelli authored Jul 29, 2024
1 parent d6504ab commit 87c1bd7
Show file tree
Hide file tree
Showing 40 changed files with 966 additions and 296 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-webapp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ jobs:
needs: lint
env:
IMAGE_REPO: ghcr.io/${{ github.repository }}/webapp
IMAGE_TAG: SNAPSHOT
IMAGE_TAG: main
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ch.sbb.playgroundbackend.controller;

import ch.sbb.playgroundbackend.auth.TenantConfig.Tenant;
import ch.sbb.playgroundbackend.auth.TenantService;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.jwt.Jwt;
Expand All @@ -23,11 +24,13 @@ public String info(@AuthenticationPrincipal Jwt jwt) {
jwt.getClaims().toString());
}


@GetMapping("/admin/info")
public String admin() {
return "Welcome admin";
}


@GetMapping("/admin/tenant")
public Tenant tenant(@AuthenticationPrincipal Jwt jwt) {
return tenantService.getByIssuerUri(jwt.getIssuer().toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import jakarta.xml.bind.JAXBException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;

Expand All @@ -18,8 +19,9 @@ public class SferaHandler {
private static final Logger log = LoggerFactory.getLogger(SferaHandler.class);

private final StaticSferaService staticSferaService;

public String replyTopic;
@Value("${spring.profiles.active}")
private String profile;

public SferaHandler(StaticSferaService staticSferaService) {
this.staticSferaService = staticSferaService;
Expand Down Expand Up @@ -104,6 +106,7 @@ private String replyTopic(String topic) {
String companyCode = topicParts[3];
String trainIdentifier = topicParts[4];
String clientId = topicParts[5];
return "90940/2/G2B/" + companyCode + "/" + trainIdentifier + "/" + clientId;
String env = this.profile.equals("local") ? "local/" : "";
return env + "90940/2/G2B/" + companyCode + "/" + trainIdentifier + "/" + clientId;
}
}
7 changes: 5 additions & 2 deletions webapp/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
"node_modules/@sbb-esta/angular/typography.css",
"src/styles.scss"
],
"allowedCommonJsDependencies": [
"mqtt-browser"
],
"scripts": []
},
"configurations": {
Expand All @@ -41,8 +44,8 @@
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
"maximumWarning": "1mb",
"maximumError": "2mb"
},
{
"type": "anyComponentStyle",
Expand Down
92 changes: 84 additions & 8 deletions webapp/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"@angular/platform-browser-dynamic": "^17.2.0",
"@angular/router": "^17.2.0",
"@sbb-esta/angular": "^17.8.2",
"angular-oauth2-oidc": "^17.0.2",
"angular-auth-oidc-client": "18.0.1",
"angular-server-side-configuration": "^17.0.5",
"ngx-mqtt": "^17.0.0",
"rxjs": "~7.8.0",
Expand All @@ -48,6 +48,7 @@
"@angular-eslint/template-parser": "17.2.1",
"@angular/cli": "^17.2.2",
"@angular/compiler-cli": "^17.2.0",
"@angular/localize": "^17.2.3",
"@types/jasmine": "~5.1.0",
"@typescript-eslint/eslint-plugin": "6.19.0",
"@typescript-eslint/parser": "6.19.0",
Expand Down
61 changes: 60 additions & 1 deletion webapp/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1 +1,60 @@
<app-mqtt-playground></app-mqtt-playground>
<sbb-header-lean [label]="title" [subtitle]="'Version ' + version" collapseBreakpoint="mobile">
<sbb-header-environment>{{ environmentLabel }}</sbb-header-environment>
<sbb-usermenu [menu]="menu" [userName]="userData().userData?.preferred_username"
[displayName]="userData().userData ? organisation()?.name : undefined" (loginRequest)="login()">
<sbb-icon svgIcon="kom:user-small" *sbbIcon></sbb-icon>
</sbb-usermenu>
<sbb-menu #menu="sbbMenu">
<button sbb-menu-item (click)="logout()">
<sbb-icon svgIcon="kom:exit-small" class="sbb-icon-fit"></sbb-icon>
<span i18n>Logout</span>
</button>
</sbb-menu>
<svg brand style="width: 0"><!-- Optional --></svg>
</sbb-header-lean>
@if (userData().userData) {
<sbb-icon-sidebar-container class="sbb-icon-sidebar-after-header">
<sbb-icon-sidebar expanded>
<a
sbbIconSidebarItem
i18n-label
label="SFERA"
routerLink="/sfera"
routerLinkActive="sbb-active"
[routerLinkActiveOptions]="{
paths: 'exact',
fragment: 'ignored',
queryParams: 'ignored',
matrixParams: 'ignored',
}"
>
<sbb-icon svgIcon="kom:railway-switch-small"></sbb-icon>
</a>
<a
sbbIconSidebarItem
i18n-label
label="MQTT"
routerLink="/mqtt"
routerLinkActive="sbb-active"
>
<sbb-icon svgIcon="kom:arrows-up-down-small"></sbb-icon>
</a>
<a
sbbIconSidebarItem
i18n-label
label="Auth insights"
routerLink="/auth-insights"
routerLinkActive="sbb-active"
>
<sbb-icon svgIcon="kom:user-key-small"></sbb-icon>
</a>
</sbb-icon-sidebar>
<sbb-icon-sidebar-content role="main" class="app-main-content">
<router-outlet></router-outlet>
</sbb-icon-sidebar-content>
</sbb-icon-sidebar-container>
} @else {
<div class="after-header app-main-content">
<router-outlet></router-outlet>
</div>
}
10 changes: 10 additions & 0 deletions webapp/src/app/app.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.app-main-content {
padding: 0 1em;
}

.after-header {
position: absolute;
top: var(--sbb-header-lean-height);
left: 0;
right: 0;
}
65 changes: 57 additions & 8 deletions webapp/src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,74 @@
import { TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { AuthService } from "./auth.service";
import { AuthService, Tenant } from "./auth.service";
import { MqService } from "./mq.service";
import { OidcSecurityService, UserDataResult } from "angular-auth-oidc-client";
import { signal } from "@angular/core";
import { of } from "rxjs";
import { SbbIconTestingModule } from "@sbb-esta/angular/icon/testing";
import { NoopAnimationsModule } from "@angular/platform-browser/animations";
import { By } from "@angular/platform-browser";
import { SbbMenuItem } from "@sbb-esta/angular/menu";
import { RouterTestingModule } from "@angular/router/testing";

const mockAuth: Partial<AuthService> = {};
const mockAuth: Partial<AuthService> = {
tenant: () => of({name: 'Organisation'} as Tenant)
};
const mockOidc: Partial<OidcSecurityService> = {
userData: signal({userData: {name: 'User'}} as UserDataResult),
logoffLocalMultiple: () => Promise.resolve(true),
};
const mockMq: Partial<MqService> = {};

describe('AppComponent', () => {
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [AppComponent],
imports: [NoopAnimationsModule, RouterTestingModule, SbbIconTestingModule, AppComponent,],
providers: [
{provide: AuthService, useValue: mockAuth},
{provide: MqService, useValue: mockMq}
{provide: OidcSecurityService, useValue: mockOidc},
{provide: MqService, useValue: mockMq},
]
}).compileComponents();
});

beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
fixture.detectChanges();
})

it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
expect(component).toBeTruthy();
});

it('should render title', () => {
expect(
fixture.nativeElement.querySelector('.sbb-header-lean-titlebox > span').textContent,
).toContain('DAS playground');
});

it('should render organisation', () => {
expect(
fixture.nativeElement.querySelector('.sbb-usermenu-user-info-display-name').textContent,
).toContain('Organisation');
});

it('should logout', () => {
const logoutSpy = spyOn(mockOidc as OidcSecurityService, 'logoffLocalMultiple');

// Open user menu
const usermenuOpenButton = fixture.debugElement.query(By.css('.sbb-menu-trigger-usermenu'));
usermenuOpenButton.nativeElement.click();
fixture.detectChanges();

// Logout
const logoutButton = fixture.debugElement.query(By.directive(SbbMenuItem));
logoutButton.nativeElement.click();

expect(logoutSpy).toHaveBeenCalled();
});
});
Loading

0 comments on commit 87c1bd7

Please sign in to comment.