Skip to content

Commit

Permalink
Merge pull request #217 from amosproj/refactor/xd-100
Browse files Browse the repository at this point in the history
Refactor/xd 100
  • Loading branch information
IngoSternberg authored Jun 29, 2024
2 parents 0905eeb + 13f0a42 commit 22f46c2
Show file tree
Hide file tree
Showing 20 changed files with 189 additions and 196 deletions.
15 changes: 3 additions & 12 deletions apps/frontend/src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ export const APP_ROUTES: Route[] = [
path: '',
component: HeaderComponent,
data: {
breadcrumbs: {
label: 'Home',
url: '/',
},
breadcrumb: 'Home',
title: 'Home Page',
subtitle: '',
},
Expand All @@ -23,10 +20,7 @@ export const APP_ROUTES: Route[] = [
{
path: 'facilities',
data: {
breadcrumbs: {
label: 'Facilities',
url: 'facilities',
},
breadcrumb: 'Facilities',
title: 'Facilities Dashboard',
subtitle: 'List of all Facilities',
},
Expand All @@ -36,10 +30,7 @@ export const APP_ROUTES: Route[] = [
{
path: 'cases',
data: {
breadcrumbs: {
label: 'Cases',
url: 'cases',
},
breadcrumb: 'Cases',
title: 'Cases',
subtitle: '',
},
Expand Down
66 changes: 29 additions & 37 deletions apps/frontend/src/app/components/header/header.component.html
Original file line number Diff line number Diff line change
@@ -1,43 +1,35 @@
<ix-application class="h-screen !z-0">
<ix-application-header name="Xcelerator Demo App">
<button class="placeholder-logo" slot="logo" [routerLink]="['/']">
<img
src="https://cdn.c2comms.cloud/images/logo-collection/2.1/sie-logo-white-rgb.svg"
class="h-5"
alt="Siemens logo"
/>
</button>
<ix-button class="mt-1" variant="secondary" ghost>
Powered by Siemens Xcelerator
</ix-button>
<ix-avatar username="John Doe" extra="Administrator"> </ix-avatar>
</ix-application-header>
<ix-application-header name="Xcelerator Demo App">
<button class="placeholder-logo" slot="logo" [routerLink]="['/']">
<img
src="https://cdn.c2comms.cloud/images/logo-collection/2.1/sie-logo-white-rgb.svg"
class="h-5"
alt="Siemens logo"
/>
</button>
<ix-button class="mt-1" variant="secondary" ghost>
Powered by Siemens Xcelerator
</ix-button>
<ix-avatar username="John Doe" extra="Administrator"> </ix-avatar>
</ix-application-header>

<ix-breadcrumb visibleItemCount="3" class="ml-8">
@for (breadcrumb of breadcrumbs(); track breadcrumb.url) {
<ix-breadcrumb-item
[routerLink]="[breadcrumb.url]"
[label]="breadcrumb.label"
></ix-breadcrumb-item>
}
</ix-breadcrumb>
<ix-breadcrumb visibleItemCount="3" class="ml-8">
@for (breadcrumb of breadcrumbs(); track breadcrumb; let i=$index; let length=$count) {
<ix-breadcrumb-item
[label]="breadcrumb"
[routerLink]="cutUrl(length - i - 1)"
></ix-breadcrumb-item>
}
</ix-breadcrumb>

<ix-content-header
class="pl-4 pt-4"
[hasBackButton]="backButtonPresent()"
[headerTitle]="title()"
[headerSubtitle]="subtitle()"
(backButtonClick)="goBack()"
></ix-content-header>
<ix-menu>
<ix-menu-item icon="building1" [routerLink]="['/facilities']">Facilities</ix-menu-item>
<ix-menu-item icon="tasks-open" [routerLink]="['/cases']">Cases</ix-menu-item>

<ix-menu>
<ix-menu-item icon="building1" [routerLink]="['/facilities']">Facilities</ix-menu-item>
<ix-menu-item icon="tasks-open" [routerLink]="['/cases']">Cases</ix-menu-item>
<ix-menu-about>
<app-legal-information></app-legal-information>
</ix-menu-about>
</ix-menu>

<ix-menu-about>
<app-legal-information></app-legal-information>
</ix-menu-about>
</ix-menu>

<router-outlet></router-outlet>
<router-outlet></router-outlet>
</ix-application>
11 changes: 5 additions & 6 deletions apps/frontend/src/app/components/header/header.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ActivatedRoute, NavigationEnd, Router, RouterEvent } from '@angular/router';
import { ReplaySubject } from 'rxjs';

import { HeaderComponent, IBreadcrumbData } from './header.component';
import { HeaderComponent } from './header.component';

const HEADER_ROUTES = {
root: {
snapshot: {
data: {
breadcrumbs: { label: 'Layer 1', url: '/layer1' } as IBreadcrumbData,
breadcrumb: 'Layer 1',
},
},
firstChild: {
snapshot: {
data: {
breadcrumbs: { label: 'Layer 2', url: '/layer2' } as IBreadcrumbData,
breadcrumb: 'Layer 2',
},
},
},
Expand All @@ -30,6 +30,7 @@ describe('HeaderComponent', () => {
beforeEach(async () => {
routerMock = {
events: eventsSubject.asObservable(),
url: '/Layer1/Layer2',
} as unknown as Router;

await TestBed.configureTestingModule({
Expand Down Expand Up @@ -71,8 +72,6 @@ describe('HeaderComponent', () => {
eventsSubject.next(new NavigationEnd(1, '', ''));

const breadcrumbs = component.breadcrumbs();
expect(breadcrumbs.length).toBe(2);
expect(breadcrumbs[0]).toEqual({ label: 'Layer 1', url: '/layer1' });
expect(breadcrumbs[1]).toEqual({ label: 'Layer 2', url: '/layer2' });
expect(breadcrumbs).toEqual([ 'Layer 1', 'Layer 2' ]);
});
});
127 changes: 44 additions & 83 deletions apps/frontend/src/app/components/header/header.component.ts
Original file line number Diff line number Diff line change
@@ -1,108 +1,69 @@
import { CommonModule } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
computed,
inject,
ViewEncapsulation,
ChangeDetectionStrategy,
Component,
computed,
inject,
ViewEncapsulation,
} from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { ActivatedRoute, NavigationEnd, Router, RouterLink, RouterOutlet } from '@angular/router';
import { IxModule } from '@siemens/ix-angular';
import { find } from 'lodash';
import { filter } from 'rxjs';

import { LegalInformationComponent } from './legal-information/legal-information.component';

/**
* Breadcrumb data interface
*/
export interface IBreadcrumbData {
label: string;
url: string;
}

/**
* Header component
*/
@Component({
selector: 'app-header',
standalone: true,
imports: [ CommonModule, IxModule, RouterLink, RouterOutlet, LegalInformationComponent ],
templateUrl: './header.component.html',
styleUrl: './header.component.scss',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'app-header',
standalone: true,
imports: [ CommonModule, IxModule, RouterLink, RouterOutlet, LegalInformationComponent ],
templateUrl: './header.component.html',
styleUrl: './header.component.scss',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HeaderComponent {
private readonly _activatedRoute: ActivatedRoute = inject(ActivatedRoute);
private readonly _router: Router = inject(Router);

readonly routerEvents = toSignal(
this._router.events.pipe(filter((e) => e instanceof NavigationEnd)),
{ initialValue: null },
);

readonly breadcrumbs = computed(() => {
this.routerEvents();
return HeaderComponent.buildBreadcrumbRecursively(this._activatedRoute.root);
});

readonly title = computed(() => {
this.routerEvents();
let currentRoute = this._activatedRoute.root;
while (currentRoute.firstChild) {
currentRoute = currentRoute.firstChild;
}
return currentRoute.snapshot.data['title'];
});

readonly subtitle = computed(() => {
this.routerEvents();
let curentRoute = this._activatedRoute.root;
while (curentRoute.firstChild) {
curentRoute = curentRoute.firstChild;
}
return curentRoute.snapshot.data['subtitle'];
});
private readonly _activatedRoute: ActivatedRoute = inject(ActivatedRoute);
private readonly _router: Router = inject(Router);

readonly backButtonPresent = computed(() => {
const breadcrumbs = this.breadcrumbs();
let tempHeader = '';
if (breadcrumbs.length > 0) {
tempHeader = breadcrumbs[breadcrumbs.length - 1].label;
}
readonly routerEvents = toSignal(
this._router.events.pipe(filter((e) => e instanceof NavigationEnd)),
{ initialValue: null },
);

if (tempHeader === 'Home') {
return false;
}
readonly breadcrumbs = computed(() => {
this.routerEvents();

return true;
});
const breadcrumbs = [];
let currentRoute = this._activatedRoute.root;
while (currentRoute.firstChild) {
const breadcrumb = currentRoute.snapshot.data['breadcrumb'];
if(breadcrumb && breadcrumbs[breadcrumbs.length - 1] !== breadcrumb)
breadcrumbs.push(breadcrumb)

/**
* Build breadcrumbs recursively
* @param route
* @param breadcrumbs
*/
static buildBreadcrumbRecursively(
route: ActivatedRoute,
breadcrumbs: IBreadcrumbData[] = [],
): IBreadcrumbData[] {
const breadcrumbData = route.snapshot.data['breadcrumbs'] as IBreadcrumbData;
currentRoute = currentRoute.firstChild;
}

if (breadcrumbData && !find(breadcrumbs, breadcrumbData)) {
breadcrumbs.push(breadcrumbData);
}
const breadcrumb = currentRoute.snapshot.data['breadcrumb'];
if(breadcrumb && breadcrumbs[breadcrumbs.length - 1] !== breadcrumb)
breadcrumbs.push(breadcrumb)

if (route.firstChild == null) {
return breadcrumbs;
}
return breadcrumbs;
});

return this.buildBreadcrumbRecursively(route.firstChild, breadcrumbs);
}
/**
* from the right cut the current url until a '/' is reached n times
* So for /cases/10/abc, goBack(1) yields /cases/10
*
* @param n
*/
cutUrl(n: number) {
const currentUrl = this._router.url;
const urlSegments = currentUrl.split('/');
return urlSegments.slice(0, urlSegments.length - n).join('/');
}

goBack() {
this._router.navigate([ this._router.url.split('/').slice(0, -1).join('/') ]);
}
}
5 changes: 5 additions & 0 deletions apps/frontend/src/app/pages/home/home.component.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
<ix-content-header
class="pl-8 pt-4"
headerTitle="Home Page"
></ix-content-header>

<ix-content class="p-8 ml-5 items-center">
<div class="flex items-center gap-x-36">
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { ICaseParams } from '@frontend/cases/shared/models';
import { firstValueFrom, of } from 'rxjs';

import { XdCasesRequestService } from '../../infrastructure/cases-request.service';
import { XdBrowseFacadesService } from './browse.facades';
import { XdCasesFacade } from './cases.facade';

describe('XdBrowseFacadesService', () => {
let service: XdBrowseFacadesService;
describe('XdCasesFacade', () => {
let facade: XdCasesFacade;
let casesRequestService: XdCasesRequestService;

beforeEach(() => {
Expand All @@ -17,22 +17,22 @@ describe('XdBrowseFacadesService', () => {

TestBed.configureTestingModule({
providers: [
XdBrowseFacadesService,
XdCasesFacade,
{ provide: XdCasesRequestService, useValue: timeseriesRequestServiceMock },
],
});

service = TestBed.inject(XdBrowseFacadesService);
facade = TestBed.inject(XdCasesFacade);
casesRequestService = TestBed.inject(XdCasesRequestService);
});

it('should be created', () => {
expect(service).toBeTruthy();
expect(facade).toBeTruthy();
});

describe('getAllTimeseries', () => {
it('should call getAllTimeseries of TimeseriesRequestService', async () => {
const response = await firstValueFrom(service.getAllCases());
const response = await firstValueFrom(facade.getAllCases());

expect(casesRequestService.getAllCases).toHaveBeenCalledTimes(1);
expect(response).toEqual([]);
Expand All @@ -43,7 +43,7 @@ describe('XdBrowseFacadesService', () => {
it('should call getTimeSeries of TimeseriesRequestService with correct parameters', async () => {
const params: ICaseParams = { id: 1 } as ICaseParams;

const response = await firstValueFrom(service.getTimeSeries(params));
const response = await firstValueFrom(facade.getTimeSeries(params));

expect(casesRequestService.getTimeSeries).toHaveBeenCalledWith(params);
expect(response).toEqual({});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { XdCasesRequestService } from '../../infrastructure/cases-request.servic
* Browse facades service.
*/
@Injectable({ providedIn: 'root' })
export class XdBrowseFacadesService {
export class XdCasesFacade {
private readonly _scanService = inject(XdCasesRequestService);

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from './browse.facades';
export * from './cases.facade';
Loading

0 comments on commit 22f46c2

Please sign in to comment.