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 @@ - + - + - + 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 @@