diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts
index 5d3715b7a9..4a570113ba 100644
--- a/frontend/src/app/app-routing.module.ts
+++ b/frontend/src/app/app-routing.module.ts
@@ -20,10 +20,6 @@ const appRoutes: Routes = [
path: 'landing',
loadChildren: './modules/landing/landing.module#LandingModule'
},
- {
- path: 'metricFinder',
- loadChildren: './modules/metric-finder/metric-finder.module#MetricFinderModule'
- },
{
path: 'aggregation',
loadChildren: './modules/aggregation/aggregation.module#AggregationModule'
@@ -41,7 +37,7 @@ const appRoutes: Routes = [
loadChildren: './modules/landing/landing.module#LandingModule',
pathMatch: 'full'
},
- {path: '**', component: NotFoundComponent}];
+ {path: '**', component: NotFoundComponent, data: {title: 'frontend.de.iteratec.osm.error.notFound.title'}}];
@NgModule({
imports: [
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.spec.ts b/frontend/src/app/global.module.spec.ts
index 111c41b388..6ca22e9774 100644
--- a/frontend/src/app/global.module.spec.ts
+++ b/frontend/src/app/global.module.spec.ts
@@ -1,23 +1,28 @@
-import {TranslateService} from "@ngx-translate/core";
-import {TestBed} from "@angular/core/testing";
-import {OsmLangService} from "./services/osm-lang.service";
-import {GlobalModule} from "./global.module";
+import {TranslateService} from '@ngx-translate/core';
+import {TestBed} from '@angular/core/testing';
+import {OsmLangService} from './services/osm-lang.service';
+import {GlobalModule} from './global.module';
+import {TitleService} from './services/title.service';
+import {RouterTestingModule} from '@angular/router/testing';
describe('GlobalModule', () => {
let globalModule: GlobalModule;
- let osmLangServiceSpy = jasmine.createSpyObj('OsmLangService',
+ const osmLangServiceSpy = jasmine.createSpyObj('OsmLangService',
['getOsmLang']);
- let translateServiceSpy = jasmine.createSpyObj('TranslateService',
+ const translateServiceSpy = jasmine.createSpyObj('TranslateService',
['getDefaultLang', 'setDefaultLang', 'use', 'addLangs']);
beforeEach(() => {
TestBed.configureTestingModule({
+ imports: [
+ RouterTestingModule
+ ],
providers: [
{provide: TranslateService, useValue: translateServiceSpy},
{provide: OsmLangService, useValue: osmLangServiceSpy}
]
});
- globalModule = new GlobalModule(TestBed.get(OsmLangService), TestBed.get(TranslateService))
+ globalModule = new GlobalModule(TestBed.get(OsmLangService), TestBed.get(TranslateService), TestBed.get(TitleService));
});
it('sets en as default lang', () => {
@@ -32,23 +37,26 @@ describe('GlobalModule', () => {
osmLangServiceSpy.getOsmLang.and.returnValue('de');
globalModule = new GlobalModule(
TestBed.get(OsmLangService),
- TestBed.get(TranslateService)
+ TestBed.get(TranslateService),
+ TestBed.get(TitleService)
);
expect(getMostRecentCallsArgs(translateServiceSpy.use)).toEqual(['de']);
osmLangServiceSpy.getOsmLang.and.returnValue('en');
globalModule = new GlobalModule(
TestBed.get(OsmLangService),
- TestBed.get(TranslateService)
+ TestBed.get(TranslateService),
+ TestBed.get(TitleService)
);
expect(getMostRecentCallsArgs(translateServiceSpy.use)).toEqual(['en']);
});
it('default lang is used if osm lang is not supported', () => {
osmLangServiceSpy.getOsmLang.and.returnValue('not_supported_lang');
- let defaultLang = 'en';
- translateServiceSpy.getDefaultLang.and.returnValue(defaultLang)
+ const defaultLang = 'en';
+ translateServiceSpy.getDefaultLang.and.returnValue(defaultLang);
globalModule = new GlobalModule(
TestBed.get(OsmLangService),
- TestBed.get(TranslateService)
+ TestBed.get(TranslateService),
+ TestBed.get(TitleService)
);
expect(getMostRecentCallsArgs(translateServiceSpy.use)).toEqual([defaultLang]);
});
diff --git a/frontend/src/app/global.module.ts b/frontend/src/app/global.module.ts
index bd43c9eae6..321f6ab630 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 {TitleService} from './services/title.service';
// AoT requires an exported function for factories
export function createTranslateLoader(http: HttpClient) {
@@ -31,18 +30,24 @@ export function createTranslateLoader(http: HttpClient) {
OsmLangService,
ApplicationService,
ResultSelectionService,
- ResultSelectionStore,
- BarchartDataService,
- AggregationChartDataService
+ ResultSelectionStore
],
})
export class GlobalModule {
supportedLangs: string[] = ['en', 'de'];
- constructor(private osmLangService: OsmLangService, private translateService: TranslateService) {
+ constructor(private osmLangService: OsmLangService,
+ private translateService: TranslateService,
+ private titleService: TitleService
+ ) {
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()
+ );
+
+ titleService.initRouteEventListener();
}
}
diff --git a/frontend/src/app/modules/aggregation/aggregation.component.html b/frontend/src/app/modules/aggregation/aggregation.component.html
index 3daf4e88a9..ba487c94a8 100644
--- a/frontend/src/app/modules/aggregation/aggregation.component.html
+++ b/frontend/src/app/modules/aggregation/aggregation.component.html
@@ -4,31 +4,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/frontend/src/app/modules/aggregation/aggregation.component.spec.ts b/frontend/src/app/modules/aggregation/aggregation.component.spec.ts
index 8e5c668cf1..5f32ea14e7 100644
--- a/frontend/src/app/modules/aggregation/aggregation.component.spec.ts
+++ b/frontend/src/app/modules/aggregation/aggregation.component.spec.ts
@@ -19,7 +19,7 @@ describe('AggregationComponent', () => {
imports: [
SharedModule,
SharedMocksModule,
- ResultSelectionModule,
+ ResultSelectionModule
],
providers: [
BarchartDataService,
diff --git a/frontend/src/app/modules/aggregation/aggregation.component.ts b/frontend/src/app/modules/aggregation/aggregation.component.ts
index 4ec0c51549..695a424734 100644
--- a/frontend/src/app/modules/aggregation/aggregation.component.ts
+++ b/frontend/src/app/modules/aggregation/aggregation.component.ts
@@ -15,24 +15,14 @@ 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) {
}
ngOnInit() {
this.showChart = false;
+ this.initDataObservables();
if (this.resultSelectionStore.validQuery) {
this.getBarchartData();
}
@@ -45,4 +35,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/aggregation/aggregation.module.ts b/frontend/src/app/modules/aggregation/aggregation.module.ts
index 7daff6f29d..9669074978 100644
--- a/frontend/src/app/modules/aggregation/aggregation.module.ts
+++ b/frontend/src/app/modules/aggregation/aggregation.module.ts
@@ -10,7 +10,8 @@ import {AggregationChartDataService} from './services/aggregation-chart-data.ser
import {FormsModule} from '@angular/forms';
const AggregationRoutes: Routes = [
- {path: 'show', component: AggregationComponent},
+ {path: 'show', component: AggregationComponent, data: {title: 'frontend.de.iteratec.osm.aggregation.title'}},
+ {path: '**', redirectTo: 'show', pathMatch: 'full'}
];
@NgModule({
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..d76e41620f 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,13 @@ 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';
@Component({
selector: 'osm-application-dashboard',
@@ -33,7 +33,7 @@ export class ApplicationDashboardComponent implements OnDestroy {
private route: ActivatedRoute,
private router: Router,
private applicationService: ApplicationService,
- private performanceAspectService: PerformanceAspectService
+ private performanceAspectService: PerformanceAspectService,
) {
this.pages$ = this.applicationService.aspectMetrics$;
this.applications$ = applicationService.applications$.pipe(
@@ -42,7 +42,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 +56,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 +65,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/application-dashboard/application-dashboard.module.ts b/frontend/src/app/modules/application-dashboard/application-dashboard.module.ts
index fc6891d1a2..d0e1732569 100644
--- a/frontend/src/app/modules/application-dashboard/application-dashboard.module.ts
+++ b/frontend/src/app/modules/application-dashboard/application-dashboard.module.ts
@@ -2,20 +2,20 @@ import {NgModule} from '@angular/core';
import {ApplicationDashboardComponent} from './application-dashboard.component';
import {ApplicationSelectComponent} from './components/application-select/application-select.component';
import {PageComponent} from './components/page/page.component';
-import {RouterModule, Routes} from "@angular/router";
+import {RouterModule, Routes} from '@angular/router';
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 {SharedModule} from "../shared/shared.module";
-import {HttpClientModule} from "@angular/common/http";
+import {CsiInfoComponent} from './components/csi-info/csi-info.component';
+import {SharedModule} from '../shared/shared.module';
+import {HttpClientModule} from '@angular/common/http';
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 {ResultSelectionModule} from "../result-selection/result-selection.module";
+import {GraphiteIntegrationComponent} from './components/application-job-status/graphite-integration/graphite-integration.component';
+import {FormsModule, ReactiveFormsModule} from '@angular/forms';
+import {ResultSelectionModule} from '../result-selection/result-selection.module';
const DashboardRoutes: Routes = [
- {path: '', component: ApplicationDashboardComponent},
- {path: ':applicationId', component: ApplicationDashboardComponent}
+ {path: '', component: ApplicationDashboardComponent, data: {title: 'frontend.de.iteratec.osm.applicationDashboard.title'}},
+ {path: ':applicationId', component: ApplicationDashboardComponent, data: {title: 'frontend.de.iteratec.osm.applicationDashboard.title'}}
];
@NgModule({
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..b908c78125 100644
--- a/frontend/src/app/modules/aspect-configuration/aspect-configuration.component.ts
+++ b/frontend/src/app/modules/aspect-configuration/aspect-configuration.component.ts
@@ -26,7 +26,8 @@ export class AspectConfigurationComponent implements OnInit {
private route: ActivatedRoute,
private applicationService: ApplicationService,
private aspectConfService: AspectConfigurationService,
- private perfAspectService: PerformanceAspectService) {
+ private perfAspectService: PerformanceAspectService
+ ) {
this.application$ = applicationService.selectedApplication$;
this.page$ = aspectConfService.selectedPage$;
this.performanceAspects$ = aspectConfService.extendedAspects$;
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..2e09661bcd 100644
--- a/frontend/src/app/modules/aspect-configuration/aspect-configuration.module.ts
+++ b/frontend/src/app/modules/aspect-configuration/aspect-configuration.module.ts
@@ -1,16 +1,15 @@
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}
+ {path: ':applicationId/:pageId', component: AspectConfigurationComponent, data: {title: 'frontend.de.iteratec.osm.performance-aspect.configuration.overview.title'}},
+ {path: 'edit/:applicationId/:pageId/:browserId/:aspectType', component: EditAspectMetricsComponent, data: {title: 'frontend.de.iteratec.osm.performance-aspect.configuration.edit.title'}}
];
@NgModule({
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..c9a162bfd0 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,22 +2,23 @@ {{ '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/distribution/distribution.component.html b/frontend/src/app/modules/distribution/distribution.component.html
index 6d166a9816..68eb8bb67b 100644
--- a/frontend/src/app/modules/distribution/distribution.component.html
+++ b/frontend/src/app/modules/distribution/distribution.component.html
@@ -5,31 +5,5 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/frontend/src/app/modules/distribution/distribution.component.ts b/frontend/src/app/modules/distribution/distribution.component.ts
index 1a221c6536..2861a65786 100644
--- a/frontend/src/app/modules/distribution/distribution.component.ts
+++ b/frontend/src/app/modules/distribution/distribution.component.ts
@@ -1,4 +1,4 @@
-import { Component } from '@angular/core';
+import {Component} from '@angular/core';
import {DistributionDataDTO, DistributionData} from './models/distribution-data.model';
import {URL} from '../../enums/url.enum';
import {ResultSelectionStore} from '../result-selection/services/result-selection.store';
@@ -15,7 +15,8 @@ export class DistributionComponent {
showChartCard = false;
results$ = new BehaviorSubject(new DistributionData());
- constructor(private violinChartService: ViolinchartDataService, private resultSelectionStore: ResultSelectionStore) {
+ constructor(private violinChartService: ViolinchartDataService,
+ private resultSelectionStore: ResultSelectionStore) {
}
getDistributionChartData() {
diff --git a/frontend/src/app/modules/distribution/distribution.module.ts b/frontend/src/app/modules/distribution/distribution.module.ts
index 6576eb47e8..44d6f9562a 100644
--- a/frontend/src/app/modules/distribution/distribution.module.ts
+++ b/frontend/src/app/modules/distribution/distribution.module.ts
@@ -9,7 +9,7 @@ import {ViolinChartComponent} from './components/violin-chart/violin-chart.compo
import {FormsModule} from '@angular/forms';
const DistributionRoutes: Routes = [
- {path: 'show', component: DistributionComponent},
+ {path: 'show', component: DistributionComponent, data: {title: 'frontend.de.iteratec.osm.distribution.title'}},
{path: '**', redirectTo: 'show', pathMatch: 'full'}
];
diff --git a/frontend/src/app/modules/landing/landing.component.ts b/frontend/src/app/modules/landing/landing.component.ts
index 7a07cd9b3e..6872e5e8e7 100644
--- a/frontend/src/app/modules/landing/landing.component.ts
+++ b/frontend/src/app/modules/landing/landing.component.ts
@@ -1,9 +1,9 @@
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';
@Component({
@@ -16,7 +16,7 @@ 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) {
@@ -26,21 +26,24 @@ export class LandingComponent {
);
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/landing/landing.module.ts b/frontend/src/app/modules/landing/landing.module.ts
index ebdc5c55ad..86744acfa4 100644
--- a/frontend/src/app/modules/landing/landing.module.ts
+++ b/frontend/src/app/modules/landing/landing.module.ts
@@ -1,15 +1,15 @@
import {NgModule} from '@angular/core';
import {LandingComponent} from './landing.component';
-import {RouterModule} from "@angular/router";
-import {SharedModule} from "../shared/shared.module";
+import {RouterModule} from '@angular/router';
+import {SharedModule} from '../shared/shared.module';
import {ContinueSetupComponent} from './components/continue-setup/continue-setup.component';
@NgModule({
imports: [
RouterModule.forChild([
- {path: '', component: LandingComponent},
- {path: 'index', component: LandingComponent},
- {path: 'continueSetup', component: ContinueSetupComponent}
+ {path: '', component: LandingComponent, data: {title: 'frontend.de.iteratec.osm.landing.title'}},
+ {path: 'index', component: LandingComponent, data: {title: 'frontend.de.iteratec.osm.landing.title'}},
+ {path: 'continueSetup', component: ContinueSetupComponent, data: {title: 'frontend.de.iteratec.osm.landing.incomplete-setup-title'}}
]),
SharedModule
],
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 @@
- 0">
+ 0"
+ [metric]="selectedMetric"
+ [results]="testResults$ | async">
-
+
-
+
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/queue-dashboard/queue-dashboard.component.spec.ts b/frontend/src/app/modules/queue-dashboard/queue-dashboard.component.spec.ts
index ef80f0cfea..15210e9a8e 100644
--- a/frontend/src/app/modules/queue-dashboard/queue-dashboard.component.spec.ts
+++ b/frontend/src/app/modules/queue-dashboard/queue-dashboard.component.spec.ts
@@ -1,13 +1,13 @@
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
-import {QueueDashboardComponent} from "./queue-dashboard.component";
-import {SharedMocksModule} from "../../testing/shared-mocks.module";
-import {QueueDashboardService, ServerInfo} from "./services/queue-dashboard.service";
-import {LocationInfoListComponent} from "./components/location-info-list/location-info-list.component";
-import {OsmLangService} from "../../services/osm-lang.service";
-import {GrailsBridgeService} from "../../services/grails-bridge.service";
+import {QueueDashboardComponent} from './queue-dashboard.component';
+import {SharedMocksModule} from '../../testing/shared-mocks.module';
+import {QueueDashboardService, ServerInfo} from './services/queue-dashboard.service';
+import {LocationInfoListComponent} from './components/location-info-list/location-info-list.component';
+import {OsmLangService} from '../../services/osm-lang.service';
+import {GrailsBridgeService} from '../../services/grails-bridge.service';
-describe("QueueDashboardComponent", () => {
+describe('QueueDashboardComponent', () => {
let component: QueueDashboardComponent;
let fixture: ComponentFixture;
let queueDashboardService: QueueDashboardService;
@@ -28,7 +28,7 @@ describe("QueueDashboardComponent", () => {
OsmLangService,
GrailsBridgeService
]
- }).compileComponents()
+ }).compileComponents();
}));
beforeEach( () => {
@@ -37,14 +37,14 @@ describe("QueueDashboardComponent", () => {
fixture.detectChanges();
mockserver = [{
- label:"prod.server02.wpt.iteratec.de",
- baseUrl:"http://prod.server02.wpt.iteratec.de/",
- id:11
+ label: 'prod.server02.wpt.iteratec.de',
+ baseUrl: 'http://prod.server02.wpt.iteratec.de/',
+ id: 11
},
{
- label:"dev.server02.wpt.iteratec.de",
- baseUrl:"http://dev.server02.wpt.iteratec.de/",
- id:1
+ label: 'dev.server02.wpt.iteratec.de',
+ baseUrl: 'http://dev.server02.wpt.iteratec.de/',
+ id: 1
}
];
@@ -54,18 +54,18 @@ describe("QueueDashboardComponent", () => {
eventResultLastHour: 0,
eventsNextHour: 2,
executingJobs: [
- [{jobConfigLabel: "label",
- date: "2018-10-14 14:00:16.0",
- wptServerBaseUrl: "url",
+ [{jobConfigLabel: 'label',
+ date: '2018-10-14 14:00:16.0',
+ wptServerBaseUrl: 'url',
testId: 55,
- jobResultStatus: {name: "WAITING"}}]
+ jobResultStatus: {name: 'WAITING'}}]
],
- id: "Dulles_GalaxyS5:undefined",
+ id: 'Dulles_GalaxyS5:undefined',
jobResultsLastHour: 0,
jobs: 2,
jobsNextHour: 1,
- label: "Dulles_GalaxyS5",
- lastHealthCheckDate: "2018-10-15 15:00:16.0",
+ label: 'Dulles_GalaxyS5',
+ lastHealthCheckDate: '2018-10-15 15:00:16.0',
pendingJobs: 2,
runningJobs: 0}];
});
@@ -76,7 +76,7 @@ describe("QueueDashboardComponent", () => {
it('should be able to call the queueDashboardService method from the QueueDashboardService', () => {
queueDashboardService = TestBed.get(QueueDashboardService);
- spyOn(queueDashboardService, "getActiveWptServer");
+ spyOn(queueDashboardService, 'getActiveWptServer');
new QueueDashboardComponent(queueDashboardService);
expect(queueDashboardService.getActiveWptServer).toHaveBeenCalled();
});
@@ -97,15 +97,15 @@ describe("QueueDashboardComponent", () => {
queueDashboardService.activeServers$.next(mockserver);
fixture.detectChanges();
- const datatableEl: HTMLCollection = fixture.nativeElement.querySelectorAll("#data-table-id");
+ const datatableEl: HTMLCollection = fixture.nativeElement.querySelectorAll('#data-table-id');
expect(datatableEl.length).toEqual(0);
- const buttons : HTMLButtonElement = fixture.nativeElement.querySelectorAll("#load-data-button");
+ const buttons: HTMLButtonElement = fixture.nativeElement.querySelectorAll('#load-data-button');
buttons[0].click();
buttons[1].click();
fixture.detectChanges();
- const datatableEl2: HTMLCollection = fixture.nativeElement.querySelectorAll("#data-table-id");
+ const datatableEl2: HTMLCollection = fixture.nativeElement.querySelectorAll('#data-table-id');
expect(datatableEl2.length).toBeGreaterThan(0);
});
@@ -115,10 +115,10 @@ describe("QueueDashboardComponent", () => {
queueDashboardService.activeServers$.next(mockserver);
fixture.detectChanges();
- const datarows : HTMLCollection = fixture.nativeElement.querySelectorAll(".queueRow");
+ const datarows: HTMLCollection = fixture.nativeElement.querySelectorAll('.queueRow');
expect(datarows.length).toEqual(0);
- fixture.nativeElement.querySelectorAll(".card").forEach(card => {
+ fixture.nativeElement.querySelectorAll('.card').forEach(card => {
card.isOpened = true;
card.isLoaded = true;
});
@@ -131,7 +131,7 @@ describe("QueueDashboardComponent", () => {
fixture.detectChanges();
- const datarows2 : HTMLCollection = fixture.nativeElement.querySelectorAll(".queueRow");
+ const datarows2: HTMLCollection = fixture.nativeElement.querySelectorAll('.queueRow');
expect(datarows2).toBeTruthy();
expect(datarows2[0].firstElementChild.textContent ).toEqual(mockinformation[0].id);
});
diff --git a/frontend/src/app/modules/queue-dashboard/queue-dashboard.component.ts b/frontend/src/app/modules/queue-dashboard/queue-dashboard.component.ts
index e256bffa8c..d58b8df68e 100644
--- a/frontend/src/app/modules/queue-dashboard/queue-dashboard.component.ts
+++ b/frontend/src/app/modules/queue-dashboard/queue-dashboard.component.ts
@@ -1,30 +1,27 @@
-import {
- Component
-} from '@angular/core';
+import {Component} from '@angular/core';
import {Observable} from 'rxjs';
-import {QueueDashboardService} from "./services/queue-dashboard.service";
-import {WptServerDTO} from "./models/WptServerDTO";
-import {ServerInfo} from "./services/queue-dashboard.service";
+import {QueueDashboardService, ServerInfo} from './services/queue-dashboard.service';
+import {WptServerDTO} from './models/WptServerDTO';
@Component({
- selector: 'app-queue-dashboard',
+ selector: 'osm-app-queue-dashboard',
templateUrl: './queue-dashboard.component.html',
styleUrls: ['./queue-dashboard.component.scss']
})
export class QueueDashboardComponent {
- private queueService: QueueDashboardService;
wptServer$: Observable>;
serverInfo$: Observable;
+ private queueService: QueueDashboardService;
- constructor( queueService: QueueDashboardService) {
+ constructor(queueService: QueueDashboardService) {
this.queueService = queueService;
this.wptServer$ = this.queueService.activeServers$;
this.serverInfo$ = this.queueService.serverInfo$;
this.queueService.getActiveWptServer();
}
- loadQueueContent( id: number){
+ loadQueueContent(id: number) {
this.queueService.getInfoTableForWptServer(id);
}
}
diff --git a/frontend/src/app/modules/queue-dashboard/queue-dashboard.module.ts b/frontend/src/app/modules/queue-dashboard/queue-dashboard.module.ts
index 146042da8a..b24be62154 100644
--- a/frontend/src/app/modules/queue-dashboard/queue-dashboard.module.ts
+++ b/frontend/src/app/modules/queue-dashboard/queue-dashboard.module.ts
@@ -1,18 +1,18 @@
import {LOCALE_ID, NgModule} from '@angular/core';
import {QueueDashboardComponent} from './queue-dashboard.component';
import {SharedModule} from '../shared/shared.module';
-import {RouterModule, Routes} from "@angular/router";
-import {QueueDashboardService} from "./services/queue-dashboard.service";
-import {HttpClientModule} from "@angular/common/http";
-import {LocationInfoListComponent} from "./components/location-info-list/location-info-list.component";
-import {OsmLangService} from "../../services/osm-lang.service";
+import {RouterModule, Routes} from '@angular/router';
+import {QueueDashboardService} from './services/queue-dashboard.service';
+import {HttpClientModule} from '@angular/common/http';
+import {LocationInfoListComponent} from './components/location-info-list/location-info-list.component';
+import {OsmLangService} from '../../services/osm-lang.service';
import { registerLocaleData } from '@angular/common';
import localeDe from '@angular/common/locales/de';
registerLocaleData(localeDe, 'de');
const QueueRoutes: Routes = [
- {path: '', component: QueueDashboardComponent},
+ {path: '', component: QueueDashboardComponent, data: {title: 'frontend.de.iteratec.osm.queueDashboard.title'}},
];
@NgModule({
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/frontend/src/app/modules/result-selection/result-selection.component.html b/frontend/src/app/modules/result-selection/result-selection.component.html
index 8b13789179..d6a454a44d 100644
--- a/frontend/src/app/modules/result-selection/result-selection.component.html
+++ b/frontend/src/app/modules/result-selection/result-selection.component.html
@@ -1 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/app/modules/result-selection/result-selection.component.spec.ts b/frontend/src/app/modules/result-selection/result-selection.component.spec.ts
index 85f1f6c5f2..0617286526 100644
--- a/frontend/src/app/modules/result-selection/result-selection.component.spec.ts
+++ b/frontend/src/app/modules/result-selection/result-selection.component.spec.ts
@@ -1,17 +1,19 @@
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {ResultSelectionComponent} from './result-selection.component';
-import {TimeFrameComponent} from "./components/time-frame/time-frame.component";
+import {TimeFrameComponent} from './components/time-frame/time-frame.component';
import {ApplicationComponent} from './components/application/application.component';
-import {SharedMocksModule} from "../../testing/shared-mocks.module";
-import {ResultSelectionService} from "./services/result-selection.service";
-import {OsmLangService} from "../../services/osm-lang.service";
-import {GrailsBridgeService} from "../../services/grails-bridge.service";
-import {MeasurandsComponent} from "./components/measurands/measurands.component";
-import {MeasurandSelectComponent} from "./components/measurands/measurand-select/measurand-select.component";
-import {PageLocationConnectivityComponent} from "./components/page-location-connectivity/page-location-connectivity.component";
-import {ResultSelectionStore} from "./services/result-selection.store";
-import {SelectionDataComponent} from "./components/page-location-connectivity/selection-data/selection-data.component";
+import {SharedMocksModule} from '../../testing/shared-mocks.module';
+import {ResultSelectionService} from './services/result-selection.service';
+import {OsmLangService} from '../../services/osm-lang.service';
+import {GrailsBridgeService} from '../../services/grails-bridge.service';
+import {MeasurandsComponent} from './components/measurands/measurands.component';
+import {MeasurandSelectComponent} from './components/measurands/measurand-select/measurand-select.component';
+import {PageLocationConnectivityComponent} from './components/page-location-connectivity/page-location-connectivity.component';
+import {ResultSelectionStore} from './services/result-selection.store';
+import {SelectionDataComponent} from './components/page-location-connectivity/selection-data/selection-data.component';
+import {ResetComponent} from './components/reset/reset.component';
+import {SubmitComponent} from './components/submit/submit.component';
describe('ResultSelectionComponent', () => {
let component: ResultSelectionComponent;
@@ -26,7 +28,9 @@ describe('ResultSelectionComponent', () => {
PageLocationConnectivityComponent,
SelectionDataComponent,
MeasurandsComponent,
- MeasurandSelectComponent
+ MeasurandSelectComponent,
+ ResetComponent,
+ SubmitComponent
],
imports: [
SharedMocksModule
diff --git a/frontend/src/app/modules/result-selection/result-selection.component.ts b/frontend/src/app/modules/result-selection/result-selection.component.ts
index 297b537c4a..1ac6164734 100644
--- a/frontend/src/app/modules/result-selection/result-selection.component.ts
+++ b/frontend/src/app/modules/result-selection/result-selection.component.ts
@@ -1,4 +1,4 @@
-import {Component} from '@angular/core';
+import {Component, EventEmitter, Input, Output} from '@angular/core';
@Component({
selector: 'osm-result-selection',
@@ -7,6 +7,28 @@ import {Component} from '@angular/core';
})
export class ResultSelectionComponent {
+ @Output() submit: EventEmitter = new EventEmitter();
+
+ @Input() applicationsRequired = false;
+ @Input() measurandsRequired = false;
+ @Input() pagesRequired = false;
+
+ @Input() timeFrameAggregation = false;
+ @Input() timeFrameComparative = false;
+
+ @Input() multipleMeasurands = false;
+
+ @Input() page = false;
+ @Input() measuredStep = false;
+
+ @Input() browser = false;
+ @Input() location = false;
+
+ @Input() connectivity = false;
+
constructor() { }
+ emitSubmitEvent(): void {
+ this.submit.emit();
+ }
}
diff --git a/frontend/src/app/modules/result-selection/result-selection.module.ts b/frontend/src/app/modules/result-selection/result-selection.module.ts
index 887359ee55..e394af4540 100644
--- a/frontend/src/app/modules/result-selection/result-selection.module.ts
+++ b/frontend/src/app/modules/result-selection/result-selection.module.ts
@@ -1,20 +1,20 @@
import {NgModule} from '@angular/core';
import {ResultSelectionComponent} from './result-selection.component';
-import {ResultSelectionService} from "./services/result-selection.service";
-import {MeasurandSelectComponent} from "./components/measurands/measurand-select/measurand-select.component";
-import {SharedModule} from "../shared/shared.module";
+import {ResultSelectionService} from './services/result-selection.service';
+import {MeasurandSelectComponent} from './components/measurands/measurand-select/measurand-select.component';
+import {SharedModule} from '../shared/shared.module';
import {TimeFrameComponent} from './components/time-frame/time-frame.component';
-import {FormsModule, ReactiveFormsModule} from "@angular/forms";
+import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {MeasurandsComponent} from './components/measurands/measurands.component';
import {OWL_DATE_TIME_FORMATS, OwlDateTimeModule, OwlNativeDateTimeModule} from 'ng-pick-datetime';
-import {NgSelectModule} from "@ng-select/ng-select";
+import {NgSelectModule} from '@ng-select/ng-select';
import {ApplicationComponent} from './components/application/application.component';
import {SelectionDataComponent} from './components/page-location-connectivity/selection-data/selection-data.component';
-import {ResultSelectionStore} from "./services/result-selection.store";
-import {PageLocationConnectivityComponent} from "./components/page-location-connectivity/page-location-connectivity.component";
-import { ResetComponent } from './components/reset/reset.component';
-import { SubmitComponent } from './components/submit/submit.component';
-import { ChartSwitchMenuComponent } from '../shared/components/chart-switch-menu/chart-switch-menu.component';
+import {ResultSelectionStore} from './services/result-selection.store';
+import {PageLocationConnectivityComponent} from './components/page-location-connectivity/page-location-connectivity.component';
+import {ResetComponent} from './components/reset/reset.component';
+import {SubmitComponent} from './components/submit/submit.component';
+import {ChartSwitchMenuComponent} from '../shared/components/chart-switch-menu/chart-switch-menu.component';
export const TIME_FORMAT = {
fullPickerInput: {year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit'},
@@ -42,7 +42,10 @@ export const TIME_FORMAT = {
SubmitComponent,
ChartSwitchMenuComponent
],
- exports: [TimeFrameComponent, ApplicationComponent, MeasurandsComponent, PageLocationConnectivityComponent, ResetComponent, SubmitComponent, ChartSwitchMenuComponent],
+ exports: [
+ ChartSwitchMenuComponent,
+ ResultSelectionComponent
+ ],
providers: [
{
provide: OWL_DATE_TIME_FORMATS,
@@ -51,7 +54,7 @@ export const TIME_FORMAT = {
ResultSelectionService,
ResultSelectionStore
],
- entryComponents: [
- ]
+ entryComponents: []
})
-export class ResultSelectionModule { }
+export class ResultSelectionModule {
+}
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..4009bdb3d8 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.distribution.title',
+ 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/modules/time-series/time-series.component.html b/frontend/src/app/modules/time-series/time-series.component.html
index c4124ab210..c07502fda5 100644
--- a/frontend/src/app/modules/time-series/time-series.component.html
+++ b/frontend/src/app/modules/time-series/time-series.component.html
@@ -1,38 +1,12 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/frontend/src/app/modules/time-series/time-series.module.ts b/frontend/src/app/modules/time-series/time-series.module.ts
index d0814fb7bd..715276adec 100644
--- a/frontend/src/app/modules/time-series/time-series.module.ts
+++ b/frontend/src/app/modules/time-series/time-series.module.ts
@@ -10,7 +10,8 @@ import {LineChartDataService} from './services/line-chart-data.service';
import {FormsModule} from '@angular/forms';
const TimeSeriesRoutes: Routes = [
- {path: 'showAll', component: TimeSeriesComponent},
+ {path: 'showAll', component: TimeSeriesComponent, data: {title: 'frontend.de.iteratec.osm.timeSeries.title'}},
+ {path: '**', redirectTo: 'showAll', pathMatch: 'full'}
];
@NgModule({
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..ce283f0510
--- /dev/null
+++ b/frontend/src/app/services/title.service.spec.ts
@@ -0,0 +1,17 @@
+import {TestBed} from '@angular/core/testing';
+
+import {TitleService} from './title.service';
+import {SharedMocksModule} from '../testing/shared-mocks.module';
+
+describe('TitleService', () => {
+ beforeEach(() => TestBed.configureTestingModule({
+ imports: [
+ SharedMocksModule
+ ]
+ }));
+
+ 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..6d68c641e9
--- /dev/null
+++ b/frontend/src/app/services/title.service.ts
@@ -0,0 +1,59 @@
+import {Injectable} from '@angular/core';
+import {TranslateService} from '@ngx-translate/core';
+import {Title} from '@angular/platform-browser';
+import {Subscription} from 'rxjs';
+import {filter, map} from 'rxjs/operators';
+import {ActivatedRoute, NavigationEnd, Router} from '@angular/router';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class TitleService {
+
+ private static APP_TITLE = 'OpenSpeedMonitor';
+
+ constructor(private router: Router,
+ private activatedRoute: ActivatedRoute,
+ private translateService: TranslateService,
+ private titleService: Title) {
+ }
+
+ initRouteEventListener(): void {
+ this.router.events.pipe(
+ filter(event => event instanceof NavigationEnd),
+ map(() => {
+ let child = this.activatedRoute.firstChild;
+ while (child.firstChild) {
+ child = child.firstChild;
+ }
+ if (child.snapshot.data['title']) {
+ return child.snapshot.data['title'];
+ }
+ return TitleService.APP_TITLE;
+ })
+ ).subscribe((title: string) => {
+ this.setDocumentTitle(title);
+ });
+ }
+
+ private setDocumentTitle(title: string): void {
+ if (title === TitleService.APP_TITLE) {
+ this.titleService.setTitle(TitleService.APP_TITLE);
+ } else {
+ this.setTranslatedTitle(title);
+ }
+ }
+
+ private setTranslatedTitle(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 ce15ce5239..920450459d 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.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.
@@ -1247,17 +1248,19 @@ 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.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.distribution.description=The webpagetest raw data of the respective interval is the basis for the displayed distribution.
frontend.de.iteratec.osm.resultSelection.show=Show
frontend.de.iteratec.osm.resultSelection.warning.longProcessingTime=The request will take a long time (too much data selected).
frontend.de.iteratec.osm.resultSelection.warning.longProcessingTime.confirm=Are you sure?
@@ -1267,8 +1270,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
@@ -1304,6 +1305,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.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
@@ -1313,9 +1315,12 @@ frontend.de.iteratec.osm.timeSeries.chart.label.timestamp=Timestamp:
frontend.de.iteratec.osm.timeSeries.chart.label.testAgent=Test agent:
frontend.de.iteratec.osm.timeSeries.chart.settings.minimum=min
frontend.de.iteratec.osm.timeSeries.chart.settings.maximum=max
+frontend.de.iteratec.osm.distribution.title=Distribution Chart
+frontend.de.iteratec.osm.distribution.description=The webpagetest raw data of the respective interval is the basis for the displayed distribution.
frontend.de.iteratec.osm.distribution.chart.settings.maximum=Maximum value
frontend.de.iteratec.osm.distribution.chart.settings.filter=Filter
frontend.de.iteratec.osm.distribution.chart.settings.sort=Sort
frontend.de.iteratec.osm.distribution.chart.settings.sort.desc=Descending Median
frontend.de.iteratec.osm.distribution.chart.settings.sort.asc=Ascending Median
frontend.de.iteratec.osm.distribution.chart.settings.customerJourney=Customer Journey
+frontend.de.iteratec.osm.error.notFound.title=Page Not Found
diff --git a/grails-app/i18n/messages_de.properties b/grails-app/i18n/messages_de.properties
index 47d1773b2d..cbdd6d2bcc 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.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.
@@ -1222,16 +1223,18 @@ 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.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.distribution.description=Den dargestellten Verteilungen der Seiten liegen jeweils die Webpagetest-Rohdaten des entprechenden Intervals zugrunde.
frontend.de.iteratec.osm.resultSelection.show=Anzeigen
frontend.de.iteratec.osm.resultSelection.warning.longProcessingTime=Die Anfrage wird lange dauern (zu viele Daten ausgewählt).
frontend.de.iteratec.osm.resultSelection.warning.longProcessingTime.confirm=Sind Sie sicher?
@@ -1241,8 +1244,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
@@ -1278,6 +1279,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.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
@@ -1287,9 +1289,12 @@ frontend.de.iteratec.osm.timeSeries.chart.label.timestamp=Zeitstempel:
frontend.de.iteratec.osm.timeSeries.chart.label.testAgent=Testagent:
frontend.de.iteratec.osm.timeSeries.chart.settings.minimum=min
frontend.de.iteratec.osm.timeSeries.chart.settings.maximum=max
+frontend.de.iteratec.osm.distribution.title=Verteilungsdiagramm
+frontend.de.iteratec.osm.distribution.description=Den dargestellten Verteilungen der Seiten liegen jeweils die Webpagetest-Rohdaten des entprechenden Intervals zugrunde.
frontend.de.iteratec.osm.distribution.chart.settings.maximum=Maximalwert
frontend.de.iteratec.osm.distribution.chart.settings.filter=Filtern
frontend.de.iteratec.osm.distribution.chart.settings.sort=Sortierung
frontend.de.iteratec.osm.distribution.chart.settings.sort.desc=Absteigender Median
frontend.de.iteratec.osm.distribution.chart.settings.sort.asc=Aufsteigender Median
frontend.de.iteratec.osm.distribution.chart.settings.customerJourney=Customer Journey
+frontend.de.iteratec.osm.error.notFound.title=Seite nicht gefunden
diff --git a/grails-app/views/_menu/_navbar.gsp b/grails-app/views/_menu/_navbar.gsp
index 80d9af43ce..d4212997c8 100644
--- a/grails-app/views/_menu/_navbar.gsp
+++ b/grails-app/views/_menu/_navbar.gsp
@@ -32,7 +32,7 @@