From d0625b4a7b5258e3c6854b1c80fb2573dbdffe4f Mon Sep 17 00:00:00 2001 From: Daniel Steger Date: Mon, 25 May 2020 10:27:45 +0200 Subject: [PATCH 01/10] Added Title in global module. Refactored. --- frontend/src/app/app.module.ts | 12 ++-- frontend/src/app/global.module.ts | 27 ++++---- .../aggregation/aggregation.component.ts | 41 +++++++---- .../application/application.component.ts | 23 ++++--- .../measurands/measurands.component.ts | 59 +++++++++------- .../page-location-connectivity.component.ts | 10 ++- .../components/submit/submit.component.ts | 14 ++-- .../time-frame/time-frame.component.ts | 68 +++++++++++-------- grails-app/i18n/messages.properties | 4 ++ grails-app/i18n/messages_de.properties | 3 + 10 files changed, 159 insertions(+), 102 deletions(-) diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 95fbfff9c1..d5cb0b8daa 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -1,11 +1,11 @@ import {BrowserModule} from '@angular/platform-browser'; import {ApplicationRef, Injector, NgModule, NgModuleFactory, SystemJsNgModuleLoader, Type} from '@angular/core'; -import {AppRoutingModule} from "./app-routing.module"; +import {AppRoutingModule} from './app-routing.module'; import {APP_BASE_HREF} from '@angular/common'; -import {NotFoundComponent} from "./not-found.component"; -import {APP_COMPONENT_SELECTOR, AppComponent} from "./app.component"; -import {GlobalModule} from "./global.module"; -import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; +import {NotFoundComponent} from './not-found.component'; +import {APP_COMPONENT_SELECTOR, AppComponent} from './app.component'; +import {GlobalModule} from './global.module'; +import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; @NgModule({ @@ -17,7 +17,7 @@ import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; GlobalModule ], providers: [SystemJsNgModuleLoader, - {provide: APP_BASE_HREF, useValue: '/',} + {provide: APP_BASE_HREF, useValue: '/'} ], entryComponents: [ AppComponent diff --git a/frontend/src/app/global.module.ts b/frontend/src/app/global.module.ts index bd43c9eae6..ae22c66953 100644 --- a/frontend/src/app/global.module.ts +++ b/frontend/src/app/global.module.ts @@ -1,14 +1,13 @@ import {NgModule} from '@angular/core'; -import {HttpClient, HttpClientModule} from "@angular/common/http"; -import {GrailsBridgeService} from "./services/grails-bridge.service"; -import {TranslateLoader, TranslateModule, TranslateService} from "@ngx-translate/core"; -import {TranslateHttpLoader} from "@ngx-translate/http-loader"; -import {OsmLangService} from "./services/osm-lang.service"; -import {ApplicationService} from "./services/application.service"; -import {ResultSelectionService} from "./modules/result-selection/services/result-selection.service"; -import {ResultSelectionStore} from "./modules/result-selection/services/result-selection.store"; -import {BarchartDataService} from "./modules/aggregation/services/barchart-data.service"; -import {AggregationChartDataService} from "./modules/aggregation/services/aggregation-chart-data.service"; +import {HttpClient, HttpClientModule} from '@angular/common/http'; +import {GrailsBridgeService} from './services/grails-bridge.service'; +import {TranslateLoader, TranslateModule, TranslateService} from '@ngx-translate/core'; +import {TranslateHttpLoader} from '@ngx-translate/http-loader'; +import {OsmLangService} from './services/osm-lang.service'; +import {ApplicationService} from './services/application.service'; +import {ResultSelectionService} from './modules/result-selection/services/result-selection.service'; +import {ResultSelectionStore} from './modules/result-selection/services/result-selection.store'; +import {Title} from '@angular/platform-browser'; // AoT requires an exported function for factories export function createTranslateLoader(http: HttpClient) { @@ -32,8 +31,7 @@ export function createTranslateLoader(http: HttpClient) { ApplicationService, ResultSelectionService, ResultSelectionStore, - BarchartDataService, - AggregationChartDataService + Title ], }) export class GlobalModule { @@ -43,6 +41,9 @@ export class GlobalModule { translateService.addLangs(this.supportedLangs); translateService.setDefaultLang('en'); - translateService.use(this.supportedLangs.includes(this.osmLangService.getOsmLang()) ? this.osmLangService.getOsmLang() : translateService.getDefaultLang()); + translateService.use(this.supportedLangs.includes(this.osmLangService.getOsmLang()) ? + this.osmLangService.getOsmLang() : + translateService.getDefaultLang() + ); } } diff --git a/frontend/src/app/modules/aggregation/aggregation.component.ts b/frontend/src/app/modules/aggregation/aggregation.component.ts index 4ec0c51549..1b568dc995 100644 --- a/frontend/src/app/modules/aggregation/aggregation.component.ts +++ b/frontend/src/app/modules/aggregation/aggregation.component.ts @@ -3,6 +3,8 @@ import {BarchartDataService} from './services/barchart-data.service'; import {ResultSelectionStore} from '../result-selection/services/result-selection.store'; import {BehaviorSubject} from 'rxjs'; import {AggregationChartDataService} from './services/aggregation-chart-data.service'; +import {Title} from '@angular/platform-browser'; +import {TranslateService} from '@ngx-translate/core'; @Component({ selector: 'osm-aggregation', @@ -15,24 +17,23 @@ export class AggregationComponent implements OnInit { barchartMedianData$: BehaviorSubject = new BehaviorSubject([]); showChart = false; - constructor( - private barchartDataService: BarchartDataService, - private resultSelectionStore: ResultSelectionStore, - private aggregationChartDataService: AggregationChartDataService - ) { - this.aggregationChartDataService.barchartAverageData$.subscribe((data) => { - this.barchartAverageData$.next(data); - }); - this.aggregationChartDataService.barchartMedianData$.subscribe((data) => { - this.barchartMedianData$.next(data); - }); - this.resultSelectionStore.dataAvailable$.subscribe((dataAvailable: boolean) => { - this.showChart = this.showChart && dataAvailable; - }); + constructor(private barchartDataService: BarchartDataService, + private resultSelectionStore: ResultSelectionStore, + private aggregationChartDataService: AggregationChartDataService, + private titleService: Title, + private translateService: TranslateService) { } ngOnInit() { + this.translateService.get('frontend.de.iteratec.osm.aggregation.aggregationTitle') + .subscribe((title: string) => { + if (title) { + this.titleService.setTitle(this.translateService.instant('frontend.de.iteratec.osm.aggregation.aggregationTitle')); + } + // this.titleService.setTitle(title); + }); this.showChart = false; + this.initDataObservables(); if (this.resultSelectionStore.validQuery) { this.getBarchartData(); } @@ -45,4 +46,16 @@ export class AggregationComponent implements OnInit { this.resultSelectionStore.remainingResultSelection ); } + + private initDataObservables(): void { + this.aggregationChartDataService.barchartAverageData$.subscribe((data) => { + this.barchartAverageData$.next(data); + }); + this.aggregationChartDataService.barchartMedianData$.subscribe((data) => { + this.barchartMedianData$.next(data); + }); + this.resultSelectionStore.dataAvailable$.subscribe((dataAvailable: boolean) => { + this.showChart = this.showChart && dataAvailable; + }); + } } diff --git a/frontend/src/app/modules/result-selection/components/application/application.component.ts b/frontend/src/app/modules/result-selection/components/application/application.component.ts index d447ee9830..168d8f2456 100644 --- a/frontend/src/app/modules/result-selection/components/application/application.component.ts +++ b/frontend/src/app/modules/result-selection/components/application/application.component.ts @@ -3,7 +3,7 @@ import {SelectableApplication} from 'src/app/models/application.model'; import {ResultSelectionStore} from '../../services/result-selection.store'; import {ResultSelectionCommandParameter} from '../../models/result-selection-command.model'; import {UiComponent} from '../../../../enums/ui-component.enum'; -import {ActivatedRoute} from '@angular/router'; +import {ResponseWithLoadingState} from '../../../../models/response-with-loading-state.model'; @Component({ selector: 'osm-result-selection-application', @@ -21,19 +21,14 @@ export class ApplicationComponent implements OnInit { selectedTag = ''; unfilteredSelectedApplications: number[] = []; - constructor(private resultSelectionStore: ResultSelectionStore, private route: ActivatedRoute) { - this.resultSelectionStore.applications$.subscribe(applications => { - this.updateApplicationsAndTags(applications.data); - }); + constructor(private resultSelectionStore: ResultSelectionStore) { } - private static sortByName(applications: SelectableApplication[]): SelectableApplication[] { - return applications.sort((a, b) => { - return a.name.localeCompare(b.name); + ngOnInit() { + this.resultSelectionStore.applications$.subscribe((applications: ResponseWithLoadingState) => { + this.updateApplicationsAndTags(applications.data); }); - } - ngOnInit() { this.resultSelectionStore.registerComponent(UiComponent.APPLICATION); this.resultSelectionStore.reset$.subscribe(() => this.resetResultSelection()); if (this.resultSelectionStore.resultSelectionCommand.jobGroupIds) { @@ -69,7 +64,7 @@ export class ApplicationComponent implements OnInit { private updateApplications(applications: SelectableApplication[]): void { if (applications != null && applications.length > 0) { - this.applications = ApplicationComponent.sortByName(applications); + this.applications = this.sortByName(applications); } else { this.applications = []; } @@ -134,4 +129,10 @@ export class ApplicationComponent implements OnInit { } } } + + private sortByName(applications: SelectableApplication[]): SelectableApplication[] { + return applications.sort((a, b) => { + return a.name.localeCompare(b.name); + }); + } } diff --git a/frontend/src/app/modules/result-selection/components/measurands/measurands.component.ts b/frontend/src/app/modules/result-selection/components/measurands/measurands.component.ts index ac86f552e4..754f7bdfaf 100644 --- a/frontend/src/app/modules/result-selection/components/measurands/measurands.component.ts +++ b/frontend/src/app/modules/result-selection/components/measurands/measurands.component.ts @@ -39,39 +39,19 @@ export class MeasurandsComponent implements OnInit { @Input() addingMeasurandsDisabled$: BehaviorSubject = new BehaviorSubject(false); constructor(private resultSelectionStore: ResultSelectionStore, private performanceAspectService: PerformanceAspectService) { - this.aspectTypes$ = this.performanceAspectService.aspectTypes$; - this.loadTimes$ = this.resultSelectionStore.loadTimes$; - this.userTimings$ = this.resultSelectionStore.userTimings$; - this.heroTimings$ = this.resultSelectionStore.heroTimings$; - this.requestCounts$ = this.resultSelectionStore.requestCounts$; - this.requestSizes$ = this.resultSelectionStore.requestSizes$; - this.percentages$ = this.resultSelectionStore.percentages$; - - this.measurands$.next({ - ...this.measurands$.getValue(), - data: [ - this.loadTimes$, - this.userTimings$, - this.heroTimings$, - this.requestCounts$, - this.requestSizes$, - this.percentages$ - ] - }); - this.getDefaultValue(); } ngOnInit() { + this.initObservables(); this.resultSelectionStore.registerComponent(UiComponent.MEASURAND); this.loadingState().subscribe(next => { this.measurands$.next({...this.measurands$.getValue(), isLoading: next}); }); + if (this.resultSelectionStore.validQuery) { - this.loadResultSelection(); + this.initByUrlQuery(); } else { - this.defaultValue$ - .pipe(takeWhile((measurand: Measurand) => measurand === undefined, true)) - .subscribe((measurand: Measurand) => this.setDefaultValue(measurand)); + this.initWithStartValue(); } } @@ -111,6 +91,29 @@ export class MeasurandsComponent implements OnInit { } } + private initObservables(): void { + this.aspectTypes$ = this.performanceAspectService.aspectTypes$; + this.loadTimes$ = this.resultSelectionStore.loadTimes$; + this.userTimings$ = this.resultSelectionStore.userTimings$; + this.heroTimings$ = this.resultSelectionStore.heroTimings$; + this.requestCounts$ = this.resultSelectionStore.requestCounts$; + this.requestSizes$ = this.resultSelectionStore.requestSizes$; + this.percentages$ = this.resultSelectionStore.percentages$; + + this.measurands$.next({ + ...this.measurands$.getValue(), + data: [ + this.loadTimes$, + this.userTimings$, + this.heroTimings$, + this.requestCounts$, + this.requestSizes$, + this.percentages$ + ] + }); + this.getDefaultValue(); + } + private loadingState(): Observable { return combineLatest( this.aspectTypes$, @@ -126,7 +129,7 @@ export class MeasurandsComponent implements OnInit { ); } - private loadResultSelection(): void { + private initByUrlQuery(): void { let allMeasurands: SelectableMeasurand[]; let performanceAspects: PerformanceAspectType[]; const finishedLoading$: Subject = new Subject(); @@ -163,6 +166,12 @@ export class MeasurandsComponent implements OnInit { }); } + private initWithStartValue(): void { + this.defaultValue$ + .pipe(takeWhile((measurand: Measurand) => measurand === undefined, true)) + .subscribe((measurand: Measurand) => this.setDefaultValue(measurand)); + } + private setResultSelection(): void { this.resultSelectionStore.setRemainingResultSelectionEnums( this.selectedMeasurands.filter((item: Measurand) => { diff --git a/frontend/src/app/modules/result-selection/components/page-location-connectivity/page-location-connectivity.component.ts b/frontend/src/app/modules/result-selection/components/page-location-connectivity/page-location-connectivity.component.ts index 3cf2966ef1..89dfe33905 100644 --- a/frontend/src/app/modules/result-selection/components/page-location-connectivity/page-location-connectivity.component.ts +++ b/frontend/src/app/modules/result-selection/components/page-location-connectivity/page-location-connectivity.component.ts @@ -31,12 +31,18 @@ export class PageLocationConnectivityComponent implements OnInit { @Input() pageRequired = false; constructor(private resultSelectionService: ResultSelectionService, private resultSelectionStore: ResultSelectionStore) { + } + + ngOnInit(): void { this.eventsAndPages$ = this.resultSelectionStore.eventsAndPages$; this.locationsAndBrowsers$ = this.resultSelectionStore.locationsAndBrowsers$; this.connectivities$ = this.resultSelectionStore.connectivities$; + + this.registerComponentsInStore(); + this.setActiveTab(); } - ngOnInit(): void { + private registerComponentsInStore(): void { if (this.showMeasuredStepSelection || this.showPageSelection) { this.resultSelectionStore.registerComponent(UiComponent.PAGE); } @@ -46,7 +52,9 @@ export class PageLocationConnectivityComponent implements OnInit { if (this.showConnectivitySelection) { this.resultSelectionStore.registerComponent(UiComponent.CONNECTIVITY); } + } + private setActiveTab(): void { if (this.showPageSelection) { this.activeTab = ActiveTab.PageAndEvent; } else if (!this.showPageSelection && this.showBrowserSelection) { diff --git a/frontend/src/app/modules/result-selection/components/submit/submit.component.ts b/frontend/src/app/modules/result-selection/components/submit/submit.component.ts index f67c723b86..506da9854b 100644 --- a/frontend/src/app/modules/result-selection/components/submit/submit.component.ts +++ b/frontend/src/app/modules/result-selection/components/submit/submit.component.ts @@ -23,11 +23,19 @@ export class SubmitComponent implements OnInit { @Output() submit: EventEmitter = new EventEmitter(); constructor(private resultSelectionStore: ResultSelectionStore) { + } + + ngOnInit() { this.resultCount$ = this.resultSelectionStore.resultCount$; this.dataAvailable$ = this.resultSelectionStore.dataAvailable$; + this.observeIfSelected(); } - ngOnInit() { + show(): void { + this.submit.emit(); + } + + private observeIfSelected(): void { this.resultSelectionStore._resultSelectionCommand$.subscribe((next: ResultSelectionCommand) => { if (next.jobGroupIds) { this.applicationsSelected$.next(next.jobGroupIds.length > 0); @@ -49,8 +57,4 @@ export class SubmitComponent implements OnInit { } }); } - - show(): void { - this.submit.emit(); - } } diff --git a/frontend/src/app/modules/result-selection/components/time-frame/time-frame.component.ts b/frontend/src/app/modules/result-selection/components/time-frame/time-frame.component.ts index fe1b09c38d..26633f161f 100644 --- a/frontend/src/app/modules/result-selection/components/time-frame/time-frame.component.ts +++ b/frontend/src/app/modules/result-selection/components/time-frame/time-frame.component.ts @@ -48,38 +48,18 @@ export class TimeFrameComponent implements OnInit { CalendarType: typeof CalendarType = CalendarType; - constructor(private resultSelectionStore: ResultSelectionStore, dateTimeAdapter: DateTimeAdapter, osmLangService: OsmLangService) { - if (osmLangService.getOsmLang() === 'en') { - dateTimeAdapter.setLocale('en-GB'); - } else { - dateTimeAdapter.setLocale(osmLangService.getOsmLang()); - } + constructor(private resultSelectionStore: ResultSelectionStore, + private dateTimeAdapter: DateTimeAdapter, + private osmLangService: OsmLangService) { } ngOnInit() { - if (this.resultSelectionStore.validQuery) { - this.selectedDates = [ - this.resultSelectionStore.resultSelectionCommand.from, - this.resultSelectionStore.resultSelectionCommand.to - ]; - if (this.resultSelectionStore.remainingResultSelection.fromComparative - && this.resultSelectionStore.remainingResultSelection.toComparative) { - this.comparativeSelectionActive = true; - this.selectedComparativeDates = [ - this.resultSelectionStore.remainingResultSelection.fromComparative, - this.resultSelectionStore.remainingResultSelection.toComparative - ]; - } - this.selectTimeFrame(); + this.setCalendarLanguage(); + if (this.resultSelectionStore.validQuery) { + this.initByUrlQuery(); } else { - const defaultFrom = new Date(); - const defaultTo = new Date(); - defaultFrom.setDate(defaultTo.getDate() - 3); - this.selectedDates = [defaultFrom, defaultTo]; - this.timeFrameInSeconds = TIME_FRAME_IN_SECONDS.THREE_DAYS; - - this.resultSelectionStore.setResultSelectionCommandTimeFrame(this.selectedDates); + this.initWithStartValues(); } if (this.showAggregation) { @@ -196,6 +176,40 @@ export class TimeFrameComponent implements OnInit { this.resultSelectionStore.setRemainingResultSelectionInterval(this.aggregationIntervalInSeconds); } + private setCalendarLanguage(): void { + if (this.osmLangService.getOsmLang() === 'en') { + this.dateTimeAdapter.setLocale('en-GB'); + } else { + this.dateTimeAdapter.setLocale(this.osmLangService.getOsmLang()); + } + } + + private initByUrlQuery(): void { + this.selectedDates = [ + this.resultSelectionStore.resultSelectionCommand.from, + this.resultSelectionStore.resultSelectionCommand.to + ]; + if (this.resultSelectionStore.remainingResultSelection.fromComparative + && this.resultSelectionStore.remainingResultSelection.toComparative) { + this.comparativeSelectionActive = true; + this.selectedComparativeDates = [ + this.resultSelectionStore.remainingResultSelection.fromComparative, + this.resultSelectionStore.remainingResultSelection.toComparative + ]; + } + this.selectTimeFrame(); + } + + private initWithStartValues(): void { + const defaultFrom = new Date(); + const defaultTo = new Date(); + defaultFrom.setDate(defaultTo.getDate() - 3); + this.selectedDates = [defaultFrom, defaultTo]; + this.timeFrameInSeconds = TIME_FRAME_IN_SECONDS.THREE_DAYS; + + this.resultSelectionStore.setResultSelectionCommandTimeFrame(this.selectedDates); + } + private setDatesFromTimeFrame(): void { const to = new Date(); const from = new Date(to.getTime() - this.timeFrameInSeconds * 1000); diff --git a/grails-app/i18n/messages.properties b/grails-app/i18n/messages.properties index 6e27837cbd..d7b7d489a1 100644 --- a/grails-app/i18n/messages.properties +++ b/grails-app/i18n/messages.properties @@ -1151,6 +1151,7 @@ frontend.de.iteratec.osm.queueDashboard.location-info-list.lastDate.label=Date o frontend.de.iteratec.osm.queueDashboard.location-info-list.status.label=Status frontend.de.iteratec.osm.queueDashboard.location-info-list.started.label=Launched frontend.de.iteratec.osm.queueDashboard.location-info-list.since=Since +frontend.de.iteratec.osm.landing.documentTitle=Home frontend.de.iteratec.osm.landing.yourApplications=Your applications frontend.de.iteratec.osm.landing.setupNewMeasurement=Setup new measurement frontend.de.iteratec.osm.landing.nothingSetUp=Nothing set up yet. @@ -1251,6 +1252,7 @@ frontend.default.button.cancel.label=Cancel frontend.de.iteratec.osm.application-title=Application frontend.back.label=Back to frontend.de.iteratec.osm.dashboard=Dashboard +frontend.de.iteratec.osm.aggregation.documentTitle=Aggregation frontend.de.iteratec.osm.aggregation.title=Aggregation frontend.de.iteratec.osm.aggregation.description=The webpagetest raw data of the respective interval is the basis for the displayed mean values. frontend.de.iteratec.osm.distributionChart.description=The webpagetest raw data of the respective interval is the basis for the displayed distribution. @@ -1301,6 +1303,7 @@ frontend.de.iteratec.chart.contextMenu.deselectPoint=Deselect Point frontend.de.iteratec.chart.contextMenu.deselectAllPoints=Deselect all Points frontend.de.iteratec.chart.errorHeader=Error frontend.de.iteratec.chart.datapointSelection.error.multipleServer=Comparison of the filmstrips is only possible for measurements on the same server. +frontend.de.iteratec.osm.timeSeries.documentTitle=Time Series frontend.de.iteratec.osm.timeSeries.chart.label.measurand=Measurand frontend.de.iteratec.osm.timeSeries.chart.label.application=Application frontend.de.iteratec.osm.timeSeries.chart.label.measuredEvent=Measured step @@ -1308,3 +1311,4 @@ frontend.de.iteratec.osm.timeSeries.chart.label.location=Location frontend.de.iteratec.osm.timeSeries.chart.label.connectivity=Connectivity frontend.de.iteratec.osm.timeSeries.chart.label.timestamp=Timestamp: frontend.de.iteratec.osm.timeSeries.chart.label.testAgent=Test agent: +frontend.de.iteratec.osm.startPage.documentTitle diff --git a/grails-app/i18n/messages_de.properties b/grails-app/i18n/messages_de.properties index 06f545c738..b8aafa494d 100644 --- a/grails-app/i18n/messages_de.properties +++ b/grails-app/i18n/messages_de.properties @@ -1129,6 +1129,7 @@ frontend.de.iteratec.osm.queueDashboard.location-info-list.lastDate.label=Stand frontend.de.iteratec.osm.queueDashboard.location-info-list.status.label=Status frontend.de.iteratec.osm.queueDashboard.location-info-list.started.label=Gestartet frontend.de.iteratec.osm.queueDashboard.location-info-list.since=Seit +frontend.de.iteratec.osm.landing.documentTitle=Startseite frontend.de.iteratec.osm.landing.yourApplications=Ihre Anwendungen frontend.de.iteratec.osm.landing.setupNewMeasurement=Neue Messung einrichten frontend.de.iteratec.osm.landing.nothingSetUp=Es wurde noch nichts eingerichtet. @@ -1225,6 +1226,7 @@ frontend.default.button.cancel.label=Abbrechen frontend.de.iteratec.osm.application-title=Anwendung frontend.back.label=Zurück zu frontend.de.iteratec.osm.dashboard=Dashboard +frontend.de.iteratec.osm.aggregation.documentTitle=Aggregation frontend.de.iteratec.osm.aggregation.title=Aggregation frontend.de.iteratec.osm.aggregation.description=Den dargestellten Durchschnittswerten der Seiten liegen jeweils die Webpagetest-Rohdaten des entprechenden Intervals zugrunde. frontend.de.iteratec.osm.distributionChart.description=Den dargestellten Verteilungen der Seiten liegen jeweils die Webpagetest-Rohdaten des entprechenden Intervals zugrunde. @@ -1275,6 +1277,7 @@ frontend.de.iteratec.chart.contextMenu.deselectPoint=Punkt abwählen frontend.de.iteratec.chart.contextMenu.deselectAllPoints=Alle Punkte abwählen frontend.de.iteratec.chart.errorHeader=Fehler frontend.de.iteratec.chart.datapointSelection.error.multipleServer=Vergleich der Filmstreifen ist nur für Messungen des gleichen Servers möglich. +frontend.de.iteratec.osm.timeSeries.documentTitle=Zeitreihen frontend.de.iteratec.osm.timeSeries.chart.label.measurand=Messgröße frontend.de.iteratec.osm.timeSeries.chart.label.application=Anwendung frontend.de.iteratec.osm.timeSeries.chart.label.measuredEvent=Messschritt From 5c82ac90111ad5de4f9babb09c8509d48f0ec605 Mon Sep 17 00:00:00 2001 From: Daniel Steger Date: Tue, 26 May 2020 17:00:23 +0200 Subject: [PATCH 02/10] Added TitleService --- frontend/src/app/global.module.ts | 4 +- .../aggregation/aggregation.component.ts | 14 ++---- .../application-dashboard.component.spec.ts | 26 +++++------ .../application-dashboard.component.ts | 37 ++++++++------- .../aspect-configuration.component.html | 2 +- .../aspect-configuration.component.ts | 6 ++- .../aspect-configuration.module.ts | 7 ++- .../aspect-metrics.component.ts | 20 ++++---- .../edit-aspect-metrics.component.html | 4 +- .../edit-aspect-metrics.component.ts | 3 ++ .../app/modules/landing/landing.component.ts | 35 ++++++++------ .../metric-finder.component.html | 9 ++-- .../metric-finder/metric-finder.component.ts | 8 ++-- .../chart-switch-menu.component.ts | 46 +++++++++++++++---- .../src/app/services/title.service.spec.ts | 12 +++++ frontend/src/app/services/title.service.ts | 24 ++++++++++ grails-app/i18n/messages.properties | 15 +++--- grails-app/i18n/messages_de.properties | 14 +++--- grails-app/views/_menu/_navbar.gsp | 4 +- 19 files changed, 179 insertions(+), 111 deletions(-) create mode 100644 frontend/src/app/services/title.service.spec.ts create mode 100644 frontend/src/app/services/title.service.ts diff --git a/frontend/src/app/global.module.ts b/frontend/src/app/global.module.ts index ae22c66953..e0f5d35532 100644 --- a/frontend/src/app/global.module.ts +++ b/frontend/src/app/global.module.ts @@ -7,7 +7,6 @@ import {OsmLangService} from './services/osm-lang.service'; import {ApplicationService} from './services/application.service'; import {ResultSelectionService} from './modules/result-selection/services/result-selection.service'; import {ResultSelectionStore} from './modules/result-selection/services/result-selection.store'; -import {Title} from '@angular/platform-browser'; // AoT requires an exported function for factories export function createTranslateLoader(http: HttpClient) { @@ -30,8 +29,7 @@ export function createTranslateLoader(http: HttpClient) { OsmLangService, ApplicationService, ResultSelectionService, - ResultSelectionStore, - Title + ResultSelectionStore ], }) export class GlobalModule { diff --git a/frontend/src/app/modules/aggregation/aggregation.component.ts b/frontend/src/app/modules/aggregation/aggregation.component.ts index 1b568dc995..3201c24b2c 100644 --- a/frontend/src/app/modules/aggregation/aggregation.component.ts +++ b/frontend/src/app/modules/aggregation/aggregation.component.ts @@ -3,8 +3,7 @@ import {BarchartDataService} from './services/barchart-data.service'; import {ResultSelectionStore} from '../result-selection/services/result-selection.store'; import {BehaviorSubject} from 'rxjs'; import {AggregationChartDataService} from './services/aggregation-chart-data.service'; -import {Title} from '@angular/platform-browser'; -import {TranslateService} from '@ngx-translate/core'; +import {TitleService} from '../../services/title.service'; @Component({ selector: 'osm-aggregation', @@ -20,18 +19,11 @@ export class AggregationComponent implements OnInit { constructor(private barchartDataService: BarchartDataService, private resultSelectionStore: ResultSelectionStore, private aggregationChartDataService: AggregationChartDataService, - private titleService: Title, - private translateService: TranslateService) { + private titleService: TitleService) { } ngOnInit() { - this.translateService.get('frontend.de.iteratec.osm.aggregation.aggregationTitle') - .subscribe((title: string) => { - if (title) { - this.titleService.setTitle(this.translateService.instant('frontend.de.iteratec.osm.aggregation.aggregationTitle')); - } - // this.titleService.setTitle(title); - }); + this.titleService.setTitle('frontend.de.iteratec.osm.aggregation.title'); this.showChart = false; this.initDataObservables(); if (this.resultSelectionStore.validQuery) { diff --git a/frontend/src/app/modules/application-dashboard/application-dashboard.component.spec.ts b/frontend/src/app/modules/application-dashboard/application-dashboard.component.spec.ts index 28a18a2230..75dc651535 100644 --- a/frontend/src/app/modules/application-dashboard/application-dashboard.component.spec.ts +++ b/frontend/src/app/modules/application-dashboard/application-dashboard.component.spec.ts @@ -4,19 +4,19 @@ import {ApplicationDashboardComponent} from './application-dashboard.component'; import {PageComponent} from './components/page/page.component'; import {ApplicationSelectComponent} from './components/application-select/application-select.component'; import {CsiGraphComponent} from './components/csi-graph/csi-graph.component'; -import {PageMetricComponent} from "./components/page-metric/page-metric.component"; -import {CsiInfoComponent} from "./components/csi-info/csi-info.component"; -import {SharedMocksModule} from "../../testing/shared-mocks.module"; -import {ApplicationService} from "../../services/application.service"; -import {CsiValueBigComponent} from "../shared/components/csi-value/csi-value-big/csi-value-big.component"; -import {CsiValueBaseComponent} from "../shared/components/csi-value/csi-value-base.component"; -import {CsiValueMediumComponent} from "../shared/components/csi-value/csi-value-medium/csi-value-medium.component"; -import {ApplicationJobStatusComponent} from "./components/application-job-status/application-job-status.component"; -import {GraphiteIntegrationComponent} from "./components/application-job-status/graphite-integration/graphite-integration.component"; -import {FormsModule, ReactiveFormsModule} from "@angular/forms"; -import {MeasurandSelectComponent} from "../result-selection/components/measurands/measurand-select/measurand-select.component"; -import {ResultSelectionService} from "../result-selection/services/result-selection.service"; -import {GrailsBridgeService} from "../../services/grails-bridge.service"; +import {PageMetricComponent} from './components/page-metric/page-metric.component'; +import {CsiInfoComponent} from './components/csi-info/csi-info.component'; +import {SharedMocksModule} from '../../testing/shared-mocks.module'; +import {ApplicationService} from '../../services/application.service'; +import {CsiValueBigComponent} from '../shared/components/csi-value/csi-value-big/csi-value-big.component'; +import {CsiValueBaseComponent} from '../shared/components/csi-value/csi-value-base.component'; +import {CsiValueMediumComponent} from '../shared/components/csi-value/csi-value-medium/csi-value-medium.component'; +import {ApplicationJobStatusComponent} from './components/application-job-status/application-job-status.component'; +import {GraphiteIntegrationComponent} from './components/application-job-status/graphite-integration/graphite-integration.component'; +import {FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {MeasurandSelectComponent} from '../result-selection/components/measurands/measurand-select/measurand-select.component'; +import {ResultSelectionService} from '../result-selection/services/result-selection.service'; +import {GrailsBridgeService} from '../../services/grails-bridge.service'; describe('ApplicationDashboardComponent', () => { let component: ApplicationDashboardComponent; diff --git a/frontend/src/app/modules/application-dashboard/application-dashboard.component.ts b/frontend/src/app/modules/application-dashboard/application-dashboard.component.ts index 1d2be234e2..09466a919a 100644 --- a/frontend/src/app/modules/application-dashboard/application-dashboard.component.ts +++ b/frontend/src/app/modules/application-dashboard/application-dashboard.component.ts @@ -4,13 +4,14 @@ import {combineLatest, Observable, Subject} from 'rxjs'; import {filter, map, takeUntil} from 'rxjs/operators'; import {ApplicationService} from '../../services/application.service'; import {Application} from '../../models/application.model'; -import {PageMetricsDto} from "./models/page-metrics.model"; -import {ApplicationCsi, ApplicationCsiById} from "../../models/application-csi.model"; -import {Csi} from "../../models/csi.model"; -import {FailingJobStatistic} from "./models/failing-job-statistic.model"; -import {PerformanceAspectService} from "../../services/performance-aspect.service"; -import {PerformanceAspectType} from "../../models/perfomance-aspect.model"; -import {ResponseWithLoadingState} from "../../models/response-with-loading-state.model"; +import {PageMetricsDto} from './models/page-metrics.model'; +import {ApplicationCsi, ApplicationCsiById} from '../../models/application-csi.model'; +import {Csi} from '../../models/csi.model'; +import {FailingJobStatistic} from './models/failing-job-statistic.model'; +import {PerformanceAspectService} from '../../services/performance-aspect.service'; +import {PerformanceAspectType} from '../../models/perfomance-aspect.model'; +import {ResponseWithLoadingState} from '../../models/response-with-loading-state.model'; +import {TitleService} from '../../services/title.service'; @Component({ selector: 'osm-application-dashboard', @@ -33,8 +34,10 @@ export class ApplicationDashboardComponent implements OnDestroy { private route: ActivatedRoute, private router: Router, private applicationService: ApplicationService, - private performanceAspectService: PerformanceAspectService + private performanceAspectService: PerformanceAspectService, + private titleService: TitleService ) { + this.titleService.setTitle('frontend.de.iteratec.osm.applicationDashboard.title'); this.pages$ = this.applicationService.aspectMetrics$; this.applications$ = applicationService.applications$.pipe( filter(response => !response.isLoading && !!response.data), @@ -42,7 +45,8 @@ export class ApplicationDashboardComponent implements OnDestroy { ); this.applicationCsi$ = applicationService.selectSelectedApplicationCsi(); this.isLoading$ = combineLatest(applicationService.applicationCsiById$, applicationService.selectedApplication$) - .pipe(map(([applicationCsiById, selectedApplication]: [ApplicationCsiById, Application]) => applicationCsiById.isLoading && !applicationCsiById[selectedApplication.id])); + .pipe(map(([applicationCsiById, selectedApplication]: [ApplicationCsiById, Application]) => + applicationCsiById.isLoading && !applicationCsiById[selectedApplication.id])); this.recentCsiValue$ = this.applicationCsi$ .pipe(map((applicationCsi: ApplicationCsi) => applicationCsi.recentCsi())); this.hasConfiguration$ = this.applicationCsi$ @@ -55,14 +59,6 @@ export class ApplicationDashboardComponent implements OnDestroy { this.aspectTypes$ = this.performanceAspectService.aspectTypes$; } - private handleNavigation(applicationId: string, applications: Application[]) { - if (!applicationId) { - this.updateApplication(applications[0]); - return; - } - this.applicationService.setSelectedApplication(applicationId); - } - ngOnDestroy() { this.destroyed$.next(null); this.destroyed$.complete(); @@ -72,4 +68,11 @@ export class ApplicationDashboardComponent implements OnDestroy { this.router.navigate(['/applicationDashboard', application.id]); } + private handleNavigation(applicationId: string, applications: Application[]) { + if (!applicationId) { + this.updateApplication(applications[0]); + return; + } + this.applicationService.setSelectedApplication(applicationId); + } } diff --git a/frontend/src/app/modules/aspect-configuration/aspect-configuration.component.html b/frontend/src/app/modules/aspect-configuration/aspect-configuration.component.html index 7cf932571c..24eb32fec2 100644 --- a/frontend/src/app/modules/aspect-configuration/aspect-configuration.component.html +++ b/frontend/src/app/modules/aspect-configuration/aspect-configuration.component.html @@ -2,7 +2,7 @@

{{ 'frontend.de.iteratec.osm.performance-aspects' | translate }}: {{(applica - {{(page$ | async)?.name}}

- {{ 'frontend.back.label' | translate }} + {{ 'frontend.back.label.neuter' | translate }} {{(application$ | async)?.name}} {{ 'frontend.de.iteratec.osm.dashboard' | translate }} diff --git a/frontend/src/app/modules/aspect-configuration/aspect-configuration.component.ts b/frontend/src/app/modules/aspect-configuration/aspect-configuration.component.ts index 902f3f5510..24b3e58e2f 100644 --- a/frontend/src/app/modules/aspect-configuration/aspect-configuration.component.ts +++ b/frontend/src/app/modules/aspect-configuration/aspect-configuration.component.ts @@ -8,6 +8,7 @@ import {Application} from '../../models/application.model'; import {AspectConfigurationService} from './services/aspect-configuration.service'; import {PerformanceAspectService} from '../../services/performance-aspect.service'; import {ResponseWithLoadingState} from '../../models/response-with-loading-state.model'; +import {TitleService} from '../../services/title.service'; @Component({ selector: 'osm-aspect-configuration', @@ -26,7 +27,9 @@ export class AspectConfigurationComponent implements OnInit { private route: ActivatedRoute, private applicationService: ApplicationService, private aspectConfService: AspectConfigurationService, - private perfAspectService: PerformanceAspectService) { + private perfAspectService: PerformanceAspectService, + private titleService: TitleService + ) { this.application$ = applicationService.selectedApplication$; this.page$ = aspectConfService.selectedPage$; this.performanceAspects$ = aspectConfService.extendedAspects$; @@ -34,6 +37,7 @@ export class AspectConfigurationComponent implements OnInit { } ngOnInit() { + this.titleService.setTitle('frontend.de.iteratec.osm.performance-aspect.configuration.overview.title'); this.route.paramMap.subscribe((params: ParamMap) => { this.aspectConfService.loadApplication(params.get('applicationId')); this.aspectConfService.loadPage(params.get('pageId')); diff --git a/frontend/src/app/modules/aspect-configuration/aspect-configuration.module.ts b/frontend/src/app/modules/aspect-configuration/aspect-configuration.module.ts index b15dcd4216..2288964047 100644 --- a/frontend/src/app/modules/aspect-configuration/aspect-configuration.module.ts +++ b/frontend/src/app/modules/aspect-configuration/aspect-configuration.module.ts @@ -1,14 +1,13 @@ import {NgModule} from '@angular/core'; import {CommonModule} from '@angular/common'; import {AspectConfigurationComponent} from './aspect-configuration.component'; -import {RouterModule, Routes} from "@angular/router"; -import {SharedModule} from "../shared/shared.module"; +import {RouterModule, Routes} from '@angular/router'; +import {SharedModule} from '../shared/shared.module'; import {AspectMetricsComponent} from './components/aspect-metrics/aspect-metrics.component'; -import {MetricFinderModule} from "../metric-finder/metric-finder.module"; +import {MetricFinderModule} from '../metric-finder/metric-finder.module'; import {EditAspectMetricsComponent} from './components/edit-aspect-metrics/edit-aspect-metrics.component'; const routes: Routes = [ - {path: '', component: AspectConfigurationComponent}, {path: ':applicationId/:pageId', component: AspectConfigurationComponent}, {path: 'edit/:applicationId/:pageId/:browserId/:aspectType', component: EditAspectMetricsComponent} ]; diff --git a/frontend/src/app/modules/aspect-configuration/components/aspect-metrics/aspect-metrics.component.ts b/frontend/src/app/modules/aspect-configuration/components/aspect-metrics/aspect-metrics.component.ts index 171cd7ad9a..4b0d7d4ce2 100644 --- a/frontend/src/app/modules/aspect-configuration/components/aspect-metrics/aspect-metrics.component.ts +++ b/frontend/src/app/modules/aspect-configuration/components/aspect-metrics/aspect-metrics.component.ts @@ -3,12 +3,12 @@ import { ExtendedPerformanceAspect, PerformanceAspect, PerformanceAspectType -} from "../../../../models/perfomance-aspect.model"; -import {Observable} from "rxjs"; -import {Application} from "../../../../models/application.model"; -import {Page} from "../../../../models/page.model"; -import {AspectConfigurationService} from "../../services/aspect-configuration.service"; -import {map} from "rxjs/operators"; +} from '../../../../models/perfomance-aspect.model'; +import {Observable} from 'rxjs'; +import {Application} from '../../../../models/application.model'; +import {Page} from '../../../../models/page.model'; +import {AspectConfigurationService} from '../../services/aspect-configuration.service'; +import {map} from 'rxjs/operators'; @Component({ selector: 'osm-aspect-metrics', @@ -31,16 +31,16 @@ export class AspectMetricsComponent implements OnInit { ngOnInit() { this.aspectsToShow$ = this.aspectConfService.extendedAspects$.pipe( map((aspects: ExtendedPerformanceAspect[]) => { - return aspects.filter((aspect: ExtendedPerformanceAspect) => aspect.performanceAspectType.name == this.actualType.name) + return aspects.filter((aspect: ExtendedPerformanceAspect) => aspect.performanceAspectType.name === this.actualType.name); }) ); } getSelectedAspect(): PerformanceAspect { - if (typeof(this.application) === 'undefined') return null; + if (typeof(this.application) === 'undefined') { return null; } const matchingAspect: PerformanceAspect = this.aspectConfService.extendedAspects$.getValue().find((aspect: PerformanceAspect) => { - return aspect.applicationId == this.application.id && aspect.pageId == this.page.id && - aspect.browserId == this.browserId && aspect.performanceAspectType.name == this.actualType.name + return aspect.applicationId === this.application.id && aspect.pageId === this.page.id && + aspect.browserId === this.browserId && aspect.performanceAspectType.name === this.actualType.name; }); return matchingAspect; } diff --git a/frontend/src/app/modules/aspect-configuration/components/edit-aspect-metrics/edit-aspect-metrics.component.html b/frontend/src/app/modules/aspect-configuration/components/edit-aspect-metrics/edit-aspect-metrics.component.html index 8d5a6a02dc..2d14b16078 100644 --- a/frontend/src/app/modules/aspect-configuration/components/edit-aspect-metrics/edit-aspect-metrics.component.html +++ b/frontend/src/app/modules/aspect-configuration/components/edit-aspect-metrics/edit-aspect-metrics.component.html @@ -2,8 +2,8 @@

{{ 'frontend.de.iteratec.osm.performance-aspects' | translate }}: {{(applica - {{(page$ | async)?.name}}

- {{ 'frontend.back.label' | translate }} - {{ 'frontend.de.iteratec.osm.performance-aspect.configuration.link-title' | translate }} + {{ 'frontend.back.label.feminine' | translate }} + {{ 'frontend.de.iteratec.osm.performance-aspect.configuration.overview.link-title' | translate }}
diff --git a/frontend/src/app/modules/aspect-configuration/components/edit-aspect-metrics/edit-aspect-metrics.component.ts b/frontend/src/app/modules/aspect-configuration/components/edit-aspect-metrics/edit-aspect-metrics.component.ts index da37393eed..aace3c2cca 100644 --- a/frontend/src/app/modules/aspect-configuration/components/edit-aspect-metrics/edit-aspect-metrics.component.ts +++ b/frontend/src/app/modules/aspect-configuration/components/edit-aspect-metrics/edit-aspect-metrics.component.ts @@ -15,6 +15,7 @@ import {MetricFinderService} from '../../../metric-finder/services/metric-finder import {MetricFinderComponent} from '../../../metric-finder/metric-finder.component'; import {AspectMetricsComponent} from '../aspect-metrics/aspect-metrics.component'; import {GrailsBridgeService} from '../../../../services/grails-bridge.service'; +import {TitleService} from '../../../../services/title.service'; @Component({ selector: 'osm-edit-aspect-metrics', @@ -43,6 +44,7 @@ export class EditAspectMetricsComponent implements OnInit { private applicationService: ApplicationService, private aspectConfService: AspectConfigurationService, private metricFinderService: MetricFinderService, + private titleService: TitleService, grailsBridgeService: GrailsBridgeService ) { this.application$ = applicationService.selectedApplication$; @@ -54,6 +56,7 @@ export class EditAspectMetricsComponent implements OnInit { } ngOnInit() { + this.titleService.setTitle('frontend.de.iteratec.osm.performance-aspect.configuration.edit.title'); this.route.paramMap.subscribe((params: ParamMap) => { this.aspectConfService.loadApplication(params.get('applicationId')); this.aspectConfService.loadPage(params.get('pageId')); diff --git a/frontend/src/app/modules/landing/landing.component.ts b/frontend/src/app/modules/landing/landing.component.ts index 7a07cd9b3e..7bebb8f701 100644 --- a/frontend/src/app/modules/landing/landing.component.ts +++ b/frontend/src/app/modules/landing/landing.component.ts @@ -1,10 +1,11 @@ import {Component} from '@angular/core'; import {filter, map} from 'rxjs/operators'; -import {ApplicationService} from "../../services/application.service"; +import {ApplicationService} from '../../services/application.service'; import {combineLatest, Observable, of} from 'rxjs'; -import {ApplicationWithCsi} from "./models/application-with-csi.model"; -import {ResponseWithLoadingState} from "../../models/response-with-loading-state.model"; +import {ApplicationWithCsi} from './models/application-with-csi.model'; +import {ResponseWithLoadingState} from '../../models/response-with-loading-state.model'; import {FailingJob} from './models/failing-jobs.model'; +import {TitleService} from '../../services/title.service'; @Component({ selector: 'osm-landing', @@ -16,31 +17,35 @@ export class LandingComponent { showApplicationEmptyState$: Observable; hasData$: Observable; applications$: Observable; - failingJobs$: Observable<{[application: string]: FailingJob[]}>; + failingJobs$: Observable<{ [application: string]: FailingJob[] }>; isHealthy$: Observable = of(false); - constructor(private applicationService: ApplicationService) { + constructor(private applicationService: ApplicationService, private titleService: TitleService) { + this.titleService.setTitle('frontend.de.iteratec.osm.landing.title'); this.hasData$ = this.applicationService.applications$.pipe(map(response => this.dataHasLoaded(response))); this.showApplicationEmptyState$ = this.applicationService.applications$.pipe( map(response => this.dataHasLoaded(response) && response.data.length < 1), ); this.applications$ = combineLatest(this.applicationService.applications$, this.applicationService.applicationCsiById$).pipe( filter(([applications]) => !applications.isLoading && !!applications.data), - map(([applications, csiById]) => applications.data.map(app => new ApplicationWithCsi(app, csiById[app.id], csiById.isLoading)).sort(function (a, b) { - if (!b.recentCsi.csiDocComplete) { - return -1; - } else if(!a.recentCsi.csiDocComplete){ - return 1; - } else { - return b.recentCsi.csiDocComplete - a.recentCsi.csiDocComplete; - } - })) + map(([applications, csiById]) => applications.data + .map(app => new ApplicationWithCsi(app, csiById[app.id], csiById.isLoading)) + .sort(function (a, b) { + if (!b.recentCsi.csiDocComplete) { + return -1; + } else if (!a.recentCsi.csiDocComplete) { + return 1; + } else { + return b.recentCsi.csiDocComplete - a.recentCsi.csiDocComplete; + } + }) + ) ); this.applicationService.loadRecentCsiForApplications(); this.failingJobs$ = this.applicationService.failingJobs$; this.failingJobs$.subscribe(next => { - if (!next || !this.objectKeys(next).length) { + if (!next || !this.objectKeys(next).length) { this.isHealthy$ = of(true); } else { this.isHealthy$ = of(false); diff --git a/frontend/src/app/modules/metric-finder/metric-finder.component.html b/frontend/src/app/modules/metric-finder/metric-finder.component.html index 924b509795..40b1ba9b9f 100644 --- a/frontend/src/app/modules/metric-finder/metric-finder.component.html +++ b/frontend/src/app/modules/metric-finder/metric-finder.component.html @@ -1,6 +1,7 @@ - + - + - + diff --git a/frontend/src/app/modules/metric-finder/metric-finder.component.ts b/frontend/src/app/modules/metric-finder/metric-finder.component.ts index 5a85109684..0198980b26 100644 --- a/frontend/src/app/modules/metric-finder/metric-finder.component.ts +++ b/frontend/src/app/modules/metric-finder/metric-finder.component.ts @@ -32,9 +32,11 @@ export class MetricFinderComponent { } clearResults() { - this.lineChartCmp.clearSelection(); - this.lineChartCmp.clearResults(); - this.lineChartCmp.redraw(); + if (this.lineChartCmp) { + this.lineChartCmp.clearSelection(); + this.lineChartCmp.clearResults(); + this.lineChartCmp.redraw(); + } this.compFilmstripCmp.clearResults(); } } diff --git a/frontend/src/app/modules/shared/components/chart-switch-menu/chart-switch-menu.component.ts b/frontend/src/app/modules/shared/components/chart-switch-menu/chart-switch-menu.component.ts index 23231f3547..09eab65997 100644 --- a/frontend/src/app/modules/shared/components/chart-switch-menu/chart-switch-menu.component.ts +++ b/frontend/src/app/modules/shared/components/chart-switch-menu/chart-switch-menu.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit } from '@angular/core'; -import {ActivatedRoute, Router} from "@angular/router"; -import {ChartSwitchMenuEntry} from "../../../result-selection/models/chart-switch-menu-entry.model"; +import {ActivatedRoute, Router} from '@angular/router'; +import {ChartSwitchMenuEntry} from '../../../result-selection/models/chart-switch-menu-entry.model'; @Component({ selector: 'osm-menu', @@ -10,17 +10,43 @@ import {ChartSwitchMenuEntry} from "../../../result-selection/models/chart-switc export class ChartSwitchMenuComponent implements OnInit { chartSwitchMenu: ChartSwitchMenuEntry[] = [ - {baseUrl: "/eventResultDashboard/showAll", label: "frontend.de.iteratec.osm.results.timeSeries", icon: "fas fa-chart-line", devUrl: "/eventResultDashboardDev/showAll"}, - {baseUrl: "/aggregation/show", label: "frontend.de.iteratec.osm.results.aggregation", icon: "fas fa-chart-bar"}, - {baseUrl: "/distributionChart/show", label: "frontend.de.iteratec.osm.results.distribution", icon: "fas fa-chart-area", devUrl: "/distributionDev/show"}, - {baseUrl: "/pageComparison/show", label: "frontend.de.iteratec.osm.results.pageComparison", icon: "fas fa-balance-scale", }, - {baseUrl: "/detailAnalysis/show", label: "frontend.de.iteratec.osm.results.detailAnalysis", icon: "fas fa-chart-pie"}, - {baseUrl: "/tabularResultPresentation/listResults", label: "frontend.de.iteratec.osm.results.resultList", icon: "fas fa-th-list"} + { + baseUrl: '/eventResultDashboard/showAll', + label: 'frontend.de.iteratec.osm.timeSeries.title', + icon: 'fas fa-chart-line', + devUrl: '/eventResultDashboardDev/showAll' + }, + { + baseUrl: '/aggregation/show', + label: 'frontend.de.iteratec.osm.aggregation.title', + icon: 'fas fa-chart-bar' + }, + { + baseUrl: '/distributionChart/show', + label: 'frontend.de.iteratec.osm.results.distribution', + icon: 'fas fa-chart-area', + devUrl: '/distributionDev/show' + }, + { + baseUrl: '/pageComparison/show', + label: 'frontend.de.iteratec.osm.results.pageComparison', + icon: 'fas fa-balance-scale' + }, + { + baseUrl: '/detailAnalysis/show', + label: 'frontend.de.iteratec.osm.results.detailAnalysis', + icon: 'fas fa-chart-pie' + }, + { + baseUrl: '/tabularResultPresentation/listResults', + label: 'frontend.de.iteratec.osm.results.resultList', + icon: 'fas fa-th-list' + } ]; - queryString: string = ''; + queryString = ''; - constructor(private router: Router, private route: ActivatedRoute) { + constructor(public router: Router, private route: ActivatedRoute) { route.queryParams.subscribe(() => { this.queryString = window.location.search; }); diff --git a/frontend/src/app/services/title.service.spec.ts b/frontend/src/app/services/title.service.spec.ts new file mode 100644 index 0000000000..344243f8e6 --- /dev/null +++ b/frontend/src/app/services/title.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { TitleService } from './title.service'; + +describe('TitleService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: TitleService = TestBed.get(TitleService); + expect(service).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/services/title.service.ts b/frontend/src/app/services/title.service.ts new file mode 100644 index 0000000000..eed44d55f0 --- /dev/null +++ b/frontend/src/app/services/title.service.ts @@ -0,0 +1,24 @@ +import {Injectable} from '@angular/core'; +import {TranslateService} from '@ngx-translate/core'; +import {Title} from '@angular/platform-browser'; +import {Subscription} from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class TitleService { + + constructor(private translateService: TranslateService, private titleService: Title) { + } + + setTitle(titleKeyToTranslate: string): void { + const titleSubscription: Subscription = this.translateService.stream(titleKeyToTranslate).subscribe((title: string) => { + if (title !== titleKeyToTranslate) { + this.titleService.setTitle(title); + if (titleSubscription) { + titleSubscription.unsubscribe(); + } + } + }); + } +} diff --git a/grails-app/i18n/messages.properties b/grails-app/i18n/messages.properties index d7b7d489a1..c5b1009db1 100644 --- a/grails-app/i18n/messages.properties +++ b/grails-app/i18n/messages.properties @@ -1151,7 +1151,7 @@ frontend.de.iteratec.osm.queueDashboard.location-info-list.lastDate.label=Date o frontend.de.iteratec.osm.queueDashboard.location-info-list.status.label=Status frontend.de.iteratec.osm.queueDashboard.location-info-list.started.label=Launched frontend.de.iteratec.osm.queueDashboard.location-info-list.since=Since -frontend.de.iteratec.osm.landing.documentTitle=Home +frontend.de.iteratec.osm.landing.title=Home frontend.de.iteratec.osm.landing.yourApplications=Your applications frontend.de.iteratec.osm.landing.setupNewMeasurement=Setup new measurement frontend.de.iteratec.osm.landing.nothingSetUp=Nothing set up yet. @@ -1244,15 +1244,17 @@ frontend.de.iteratec.osm.performance-aspect.PAGE_IS_USABLE=Usable frontend.de.iteratec.osm.performance-aspect.PAGE_IS_USABLE.user-centric-question=Is it usable? frontend.de.iteratec.osm.performance-aspect.PAGE_IS_USABLE.description=Page is usable frontend.de.iteratec.osm.performance-aspect-metric=Aspect metric -frontend.de.iteratec.osm.performance-aspect.configuration.link-title=Overview aspect metrics +frontend.de.iteratec.osm.performance-aspect.configuration.overview.title=Aspect metrics +frontend.de.iteratec.osm.performance-aspect.configuration.overview.link-title=Overview of aspect metrics +frontend.de.iteratec.osm.performance-aspect.configuration.edit.title=Configuration of aspect metrics frontend.de.iteratec.osm.applicationDashboard.jobStatus.integrations=Integrations frontend.default.button.edit.label=Edit frontend.default.button.save.label=Save frontend.default.button.cancel.label=Cancel frontend.de.iteratec.osm.application-title=Application -frontend.back.label=Back to +frontend.back.label.feminine=Back to the +frontend.back.label.neuter=Back to the frontend.de.iteratec.osm.dashboard=Dashboard -frontend.de.iteratec.osm.aggregation.documentTitle=Aggregation frontend.de.iteratec.osm.aggregation.title=Aggregation frontend.de.iteratec.osm.aggregation.description=The webpagetest raw data of the respective interval is the basis for the displayed mean values. frontend.de.iteratec.osm.distributionChart.description=The webpagetest raw data of the respective interval is the basis for the displayed distribution. @@ -1266,8 +1268,6 @@ frontend.de.iteratec.osm.resultSelection.warning.noDataAvailable=No data availab frontend.de.iteratec.osm.resultSelection.warning.noApplicationSelected=No application selected. frontend.de.iteratec.osm.resultSelection.warning.noPageSelected=No page or measured step selected. frontend.de.iteratec.osm.resultSelection.warning.noMeasurandSelected=No measurand selected. -frontend.de.iteratec.osm.results.timeSeries=Time Series -frontend.de.iteratec.osm.results.aggregation=Aggregation frontend.de.iteratec.osm.results.distributionChart=Distribution Chart frontend.de.iteratec.osm.results.distribution=Distribution frontend.de.iteratec.osm.results.pageComparison=Page Comparison @@ -1303,7 +1303,7 @@ frontend.de.iteratec.chart.contextMenu.deselectPoint=Deselect Point frontend.de.iteratec.chart.contextMenu.deselectAllPoints=Deselect all Points frontend.de.iteratec.chart.errorHeader=Error frontend.de.iteratec.chart.datapointSelection.error.multipleServer=Comparison of the filmstrips is only possible for measurements on the same server. -frontend.de.iteratec.osm.timeSeries.documentTitle=Time Series +frontend.de.iteratec.osm.timeSeries.title=Time Series frontend.de.iteratec.osm.timeSeries.chart.label.measurand=Measurand frontend.de.iteratec.osm.timeSeries.chart.label.application=Application frontend.de.iteratec.osm.timeSeries.chart.label.measuredEvent=Measured step @@ -1311,4 +1311,3 @@ frontend.de.iteratec.osm.timeSeries.chart.label.location=Location frontend.de.iteratec.osm.timeSeries.chart.label.connectivity=Connectivity frontend.de.iteratec.osm.timeSeries.chart.label.timestamp=Timestamp: frontend.de.iteratec.osm.timeSeries.chart.label.testAgent=Test agent: -frontend.de.iteratec.osm.startPage.documentTitle diff --git a/grails-app/i18n/messages_de.properties b/grails-app/i18n/messages_de.properties index b8aafa494d..5fec00989b 100644 --- a/grails-app/i18n/messages_de.properties +++ b/grails-app/i18n/messages_de.properties @@ -1129,7 +1129,7 @@ frontend.de.iteratec.osm.queueDashboard.location-info-list.lastDate.label=Stand frontend.de.iteratec.osm.queueDashboard.location-info-list.status.label=Status frontend.de.iteratec.osm.queueDashboard.location-info-list.started.label=Gestartet frontend.de.iteratec.osm.queueDashboard.location-info-list.since=Seit -frontend.de.iteratec.osm.landing.documentTitle=Startseite +frontend.de.iteratec.osm.landing.title=Startseite frontend.de.iteratec.osm.landing.yourApplications=Ihre Anwendungen frontend.de.iteratec.osm.landing.setupNewMeasurement=Neue Messung einrichten frontend.de.iteratec.osm.landing.nothingSetUp=Es wurde noch nichts eingerichtet. @@ -1219,14 +1219,16 @@ frontend.de.iteratec.osm.performance-aspect.PAGE_IS_USABLE=Usable frontend.de.iteratec.osm.performance-aspect.PAGE_IS_USABLE.user-centric-question=Is it usable? frontend.de.iteratec.osm.performance-aspect.PAGE_IS_USABLE.description=Seite ist bedienbar frontend.de.iteratec.osm.performance-aspect-metric=Aspekt-Metrik -frontend.de.iteratec.osm.performance-aspect.configuration.link-title=Übersicht Aspekt-Metriken +frontend.de.iteratec.osm.performance-aspect.configuration.overview.title=Aspekt-Metriken +frontend.de.iteratec.osm.performance-aspect.configuration.overview.link-title=Übersicht der Aspekt-Metriken +frontend.de.iteratec.osm.performance-aspect.configuration.edit.title=Konfiguration der Aspekt-Metriken frontend.default.button.edit.label=Bearbeiten frontend.default.button.save.label=Speichern frontend.default.button.cancel.label=Abbrechen frontend.de.iteratec.osm.application-title=Anwendung -frontend.back.label=Zurück zu +frontend.back.label.feminine=Zurück zur +frontend.back.label.neuter=Zurück zum frontend.de.iteratec.osm.dashboard=Dashboard -frontend.de.iteratec.osm.aggregation.documentTitle=Aggregation frontend.de.iteratec.osm.aggregation.title=Aggregation frontend.de.iteratec.osm.aggregation.description=Den dargestellten Durchschnittswerten der Seiten liegen jeweils die Webpagetest-Rohdaten des entprechenden Intervals zugrunde. frontend.de.iteratec.osm.distributionChart.description=Den dargestellten Verteilungen der Seiten liegen jeweils die Webpagetest-Rohdaten des entprechenden Intervals zugrunde. @@ -1240,8 +1242,6 @@ frontend.de.iteratec.osm.resultSelection.warning.noDataAvailable=Für Ihre Auswa frontend.de.iteratec.osm.resultSelection.warning.noApplicationSelected=Keine Anwendung ausgewählt. frontend.de.iteratec.osm.resultSelection.warning.noPageSelected=Keine Seite oder Messschritt ausgewählt. frontend.de.iteratec.osm.resultSelection.warning.noMeasurandSelected=Keine Messgröße ausgewählt. -frontend.de.iteratec.osm.results.timeSeries=Zeitreihen -frontend.de.iteratec.osm.results.aggregation=Aggregation frontend.de.iteratec.osm.results.distributionChart=Verteilungsdiagramm frontend.de.iteratec.osm.results.distribution=Verteilungsdiagramm frontend.de.iteratec.osm.results.pageComparison=Seitenvergleich @@ -1277,7 +1277,7 @@ frontend.de.iteratec.chart.contextMenu.deselectPoint=Punkt abwählen frontend.de.iteratec.chart.contextMenu.deselectAllPoints=Alle Punkte abwählen frontend.de.iteratec.chart.errorHeader=Fehler frontend.de.iteratec.chart.datapointSelection.error.multipleServer=Vergleich der Filmstreifen ist nur für Messungen des gleichen Servers möglich. -frontend.de.iteratec.osm.timeSeries.documentTitle=Zeitreihen +frontend.de.iteratec.osm.timeSeries.title=Zeitreihen frontend.de.iteratec.osm.timeSeries.chart.label.measurand=Messgröße frontend.de.iteratec.osm.timeSeries.chart.label.application=Anwendung frontend.de.iteratec.osm.timeSeries.chart.label.measuredEvent=Messschritt diff --git a/grails-app/views/_menu/_navbar.gsp b/grails-app/views/_menu/_navbar.gsp index 80d9af43ce..364ed1cf50 100644 --- a/grails-app/views/_menu/_navbar.gsp +++ b/grails-app/views/_menu/_navbar.gsp @@ -32,7 +32,7 @@