Skip to content
Permalink
Browse files

Merge pull request #213 from iteratec/feature/integrateAspectConfWith…

…MetricFinder

Feature/integrate aspect conf with metric finder
  • Loading branch information...
nilskuhn committed Jun 11, 2019
2 parents fc87355 + 22ef27f commit 1428f0106ae853e2c34ac79c7423ce247665a64a
Showing with 823 additions and 558 deletions.
  1. +1 −1 frontend/src/app/models/perfomance-aspect.model.ts
  2. +19 −11 frontend/src/app/modules/application-dashboard/application-dashboard.component.html
  3. +3 −1 frontend/src/app/modules/application-dashboard/application-dashboard.component.spec.ts
  4. +4 −14 frontend/src/app/modules/application-dashboard/application-dashboard.component.ts
  5. +4 −4 frontend/src/app/modules/aspect-configuration/aspect-configuration.component.html
  6. +2 −1 frontend/src/app/modules/aspect-configuration/aspect-configuration.component.scss
  7. +1 −142 frontend/src/app/modules/aspect-configuration/aspect-configuration.component.spec.ts
  8. +13 −77 frontend/src/app/modules/aspect-configuration/aspect-configuration.component.ts
  9. +7 −3 frontend/src/app/modules/aspect-configuration/aspect-configuration.module.ts
  10. +19 −20 ...tend/src/app/modules/aspect-configuration/components/aspect-metrics/aspect-metrics.component.html
  11. +5 −1 ...tend/src/app/modules/aspect-configuration/components/aspect-metrics/aspect-metrics.component.scss
  12. +14 −11 ...d/src/app/modules/aspect-configuration/components/aspect-metrics/aspect-metrics.component.spec.ts
  13. +30 −6 frontend/src/app/modules/aspect-configuration/components/aspect-metrics/aspect-metrics.component.ts
  14. +22 −0 ...pp/modules/aspect-configuration/components/edit-aspect-metrics/edit-aspect-metrics.component.html
  15. +13 −0 ...pp/modules/aspect-configuration/components/edit-aspect-metrics/edit-aspect-metrics.component.scss
  16. +70 −0 ...modules/aspect-configuration/components/edit-aspect-metrics/edit-aspect-metrics.component.spec.ts
  17. +81 −0 .../app/modules/aspect-configuration/components/edit-aspect-metrics/edit-aspect-metrics.component.ts
  18. +98 −58 frontend/src/app/modules/aspect-configuration/services/aspect-configuration.service.spec.ts
  19. +151 −17 frontend/src/app/modules/aspect-configuration/services/aspect-configuration.service.ts
  20. +10 −1 frontend/src/app/modules/job-threshold/components/threshold-group/threshold-group.component.spec.ts
  21. +3 −4 frontend/src/app/modules/landing/landing.component.ts
  22. +4 −0 ...src/app/modules/metric-finder/components/comparable-filmstrips/comparable-filmstrips.component.ts
  23. +12 −2 frontend/src/app/modules/metric-finder/components/line-chart/line-chart.component.ts
  24. +4 −6 frontend/src/app/modules/metric-finder/metric-finder.component.html
  25. +0 −2 frontend/src/app/modules/metric-finder/metric-finder.component.spec.ts
  26. +17 −2 frontend/src/app/modules/metric-finder/metric-finder.component.ts
  27. +4 −1 frontend/src/app/modules/metric-finder/metric-finder.module.ts
  28. +1 −7 frontend/src/app/modules/metric-finder/services/metric-finder.service.ts
  29. +80 −19 frontend/src/app/services/application.service.spec.ts
  30. +49 −139 frontend/src/app/services/application.service.ts
  31. +17 −0 frontend/src/app/services/performance-aspect.service.spec.ts
  32. +25 −0 frontend/src/app/services/performance-aspect.service.ts
  33. +1 −0 frontend/src/styles/clickable-list.scss
  34. +14 −1 grails-app/controllers/de/iteratec/osm/result/AspectConfigurationController.groovy
  35. +6 −0 grails-app/i18n/messages.properties
  36. +6 −0 grails-app/i18n/messages_de.properties
  37. +2 −1 grails-app/services/de/iteratec/osm/measurement/environment/BrowserService.groovy
  38. +3 −1 grails-app/services/de/iteratec/osm/result/ApplicationDashboardService.groovy
  39. +8 −5 src/test/groovy/de/iteratec/osm/measurement/environment/BrowserServiceSpec.groovy
@@ -5,7 +5,7 @@ import {BrowserInfoDto} from "./browser.model";
export interface PerformanceAspect {
id: number
pageId: number
jobGroupId: number
applicationId: number
browserId: number
measurand: SelectableMeasurand
performanceAspectType: PerformanceAspectType
@@ -1,30 +1,38 @@
<h1>
<osm-application-select [selectedApplication]="selectedApplication"
<osm-application-select [selectedApplication]="selectedApplication$ | async"
[applications]="applications$ | async"
(selectedApplicationChange)="updateApplication($event)"></osm-application-select>
</h1>
<div class="main-container" *ngIf="selectedApplication">

<div class="main-container">
<h2 class="card">{{ 'frontend.de.iteratec.osm.applicationDashboard.kpi.title' | translate }}</h2>
<h2 class="card application-job-status">{{ 'frontend.de.iteratec.osm.applicationDashboard.jobStatus.title' | translate }}</h2>
<h2
class="card application-job-status">{{ 'frontend.de.iteratec.osm.applicationDashboard.jobStatus.title' | translate }}</h2>

<osm-csi-value-big [csiValue]="(recentCsiValue$ | async)?.csiDocComplete" [csiDate]="(recentCsiValue$ | async)?.date?.toString()"
<osm-csi-value-big [csiValue]="(recentCsiValue$ | async)?.csiDocComplete"
[csiDate]="(recentCsiValue$ | async)?.date?.toString()"
[showLoading]="isLoading$ | async"
[lastResultDate]="selectedApplication.dateOfLastResults" class="card"></osm-csi-value-big>
[lastResultDate]="(selectedApplication$ | async)?.dateOfLastResults"
class="card"></osm-csi-value-big>

<div *ngIf="!isLoading && !(applicationCsi$ | async)?.csiValues.length; then showInfo else showGraph"></div>
<div
*ngIf="!(isLoading$ | async) && !(applicationCsi$ | async)?.csiValues.length; then showInfo else showGraph"></div>

<ng-template #showInfo>
<osm-csi-info [csiData]="applicationCsi$ | async" [selectedApplication]="selectedApplication" class="card"></osm-csi-info>
<osm-csi-info [csiData]="applicationCsi$ | async" [selectedApplication]="selectedApplication$ | async"
class="card"></osm-csi-info>
</ng-template>

<ng-template #showGraph>
<osm-csi-graph [csiData]="applicationCsi$ | async" [recentCsiData]="recentCsiValue$ | async" class="card"></osm-csi-graph>
<osm-csi-graph [csiData]="applicationCsi$ | async" [recentCsiData]="recentCsiValue$ | async"
class="card"></osm-csi-graph>
</ng-template>

<osm-application-job-status [failingJobStatistic]="failingJobStatistic$ | async" [selectedApplication]="selectedApplication" class="card"></osm-application-job-status>
<osm-application-job-status [failingJobStatistic]="failingJobStatistic$ | async"
[selectedApplication]="selectedApplication$ | async"
class="card"></osm-application-job-status>

<osm-page *ngFor="let metric of pages$ | async" [metricsForPage]="metric"
[lastDateOfResult]="selectedApplication.dateOfLastResults" [application]="selectedApplication"
[lastDateOfResult]="(selectedApplication$ | async)?.dateOfLastResults"
[application]="selectedApplication$ | async"
class="card"></osm-page>
</div>
@@ -16,6 +16,7 @@ import {GraphiteIntegrationComponent} from "./components/application-job-status/
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {MeasurandSelectComponent} from "../result-selection/components/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;
@@ -44,7 +45,8 @@ describe('ApplicationDashboardComponent', () => {
],
providers: [
ApplicationService,
ResultSelectionService
ResultSelectionService,
GrailsBridgeService
]
})
.compileComponents();
@@ -8,7 +8,6 @@ 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 {ResultSelectionService} from "../result-selection/services/result-selection.service";

@Component({
selector: 'osm-application-dashboard',
@@ -17,20 +16,19 @@ import {ResultSelectionService} from "../result-selection/services/result-select
})
export class ApplicationDashboardComponent implements OnDestroy {
applications$: Observable<Application[]>;
selectedApplication: Application;
destroyed$ = new Subject<void>();
pages$: Observable<PageMetricsDto[]>;
applicationCsi$: Observable<ApplicationCsi>;
recentCsiValue$: Observable<Csi>;
hasConfiguration$: Observable<boolean>;
isLoading$: Observable<boolean>;
failingJobStatistic$: Observable<FailingJobStatistic>;
selectedApplication$: Observable<Application>;

constructor(
private route: ActivatedRoute,
private router: Router,
private applicationService: ApplicationService,
private resultSelectionService: ResultSelectionService
private applicationService: ApplicationService
) {
this.pages$ = this.applicationService.metrics$;
this.applications$ = applicationService.applications$.pipe(
@@ -47,20 +45,16 @@ export class ApplicationDashboardComponent implements OnDestroy {
combineLatest(this.route.paramMap, this.applications$)
.pipe(takeUntil(this.destroyed$))
.subscribe(([navParams, applications]) => this.handleNavigation(navParams.get('applicationId'), applications));
this.applicationService.loadApplications();
this.failingJobStatistic$ = this.applicationService.failingJobStatistics$;
this.selectedApplication$ = this.applicationService.selectedApplication$;
}

private handleNavigation(applicationId: string, applications: Application[]) {
if (!applicationId) {
this.updateApplication(applications[0]);
return;
}
this.selectedApplication = this.findApplicationById(applications, applicationId);
if (this.selectedApplication) {
this.applicationService.updateSelectedApplication(this.selectedApplication);
this.resultSelectionService.updateApplications([this.selectedApplication]);
}
this.applicationService.setSelectedApplication(applicationId);
}

ngOnDestroy() {
@@ -72,8 +66,4 @@ export class ApplicationDashboardComponent implements OnDestroy {
this.router.navigate(['/applicationDashboard', application.id]);
}

private findApplicationById(applications: Application[], applicationId: string): Application {
return applications.find(application => application.id == Number(applicationId));
}

}
@@ -7,10 +7,10 @@ <h1>{{ 'frontend.de.iteratec.osm.performance-aspects' | translate }}: {{(applica
{{ 'frontend.de.iteratec.osm.dashboard' | translate }}
</a>
<div class="grid-container">
<osm-aspect-metrics *ngFor="let aspectType of (aspectTypes$ | async)"
[aspects]="performanceAspects$ | async"
[aspectType]="aspectType"
class="aspect-inspect"></osm-aspect-metrics>
<div *ngFor="let aspectType of (aspectTypes$ | async)" class="card">
<osm-aspect-metrics [application]="application$ | async" [page]="page$ | async"
[actualType]="aspectType" class="aspect-inspect"></osm-aspect-metrics>
</div>
</div>

<ng-template #isLoading>
@@ -1,10 +1,11 @@
a {
margin-left: 10px;
margin: 0 10px 20px 0;
}

.grid-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(460px, 1fr));
margin: 10px 0 0 0;

osm-aspect-metrics {
margin: 10px 0 20px 10px;
@@ -1,18 +1,11 @@
import {async, ComponentFixture, inject, TestBed} from '@angular/core/testing';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';

import {AspectConfigurationComponent} from './aspect-configuration.component';
import {SharedMocksModule} from "../../testing/shared-mocks.module";
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {of} from "rxjs";
import {
ExtendedPerformanceAspect,
PerformanceAspect,
PerformanceAspectType
} from "../../models/perfomance-aspect.model";
import {AspectMetricsComponent} from "./components/aspect-metrics/aspect-metrics.component";
import {ApplicationService} from "../../services/application.service";
import {AspectConfigurationService} from "./services/aspect-configuration.service";
import {BrowserInfoDto} from "../../models/browser.model";

describe('AspectConfigurationComponent', () => {
let component: AspectConfigurationComponent;
@@ -47,139 +40,5 @@ describe('AspectConfigurationComponent', () => {
it('should create', () => {
expect(component).toBeTruthy();
});
it('should provide unique AspectTypes correctly according to given PerformanceAspects', inject(
[AspectConfigurationComponent],
(component: AspectConfigurationComponent) => {
const type1: PerformanceAspectType = {name: 'PAGE_CONSTRUCTION_STARTED', icon: 'hourglass'};
const type2: PerformanceAspectType = {name: 'PAGE_SHOWS_USEFUL_CONTENT', icon: 'hourglass'};
const aspectsOfTwoDifferentTypes = [
{
id: 1,
pageId: 1,
jobGroupId: 1,
browserId: 1,
measurand: {id: 'DOC_COMPLETE', name: 'Document complete'},
performanceAspectType: type1,
persistent: true,
browserName: 'browser1',
operatingSystem: 'Android',
deviceType: {name: 'Smartphone', icon: 'mobile'}
},
{
id: 1,
pageId: 2,
jobGroupId: 1,
browserId: 1,
measurand: {id: 'DOC_COMPLETE', name: 'Document complete'},
performanceAspectType: type1,
persistent: true,
browserName: 'browser1',
operatingSystem: 'Android',
deviceType: {name: 'Smartphone', icon: 'mobile'}
},
{
id: 1,
pageId: 3,
jobGroupId: 1,
browserId: 1,
measurand: {id: 'DOC_COMPLETE', name: 'Document complete'},
performanceAspectType: type1,
persistent: true,
browserName: 'browser1',
operatingSystem: 'Android',
deviceType: {name: 'Smartphone', icon: 'mobile'}
},
{
id: 1,
pageId: 4,
jobGroupId: 1,
browserId: 1,
measurand: {id: 'DOC_COMPLETE', name: 'Document complete'},
performanceAspectType: type2,
persistent: true,
browserName: 'browser1',
operatingSystem: 'Android',
deviceType: {name: 'Smartphone', icon: 'mobile'}
}];
component.performanceAspects$ = of(aspectsOfTwoDifferentTypes);
component.initAspectTypes();
component.aspectTypes$.subscribe((aspectTypes: PerformanceAspectType[]) => {
expect(aspectTypes.length).toBe(2);
expect(aspectTypes.filter((type: PerformanceAspectType) => type == type1).length).toBe(1);
expect(aspectTypes.filter((type: PerformanceAspectType) => type == type2).length).toBe(1);
})
}));

describe('aspect extension', () => {
it('should not provide any extended aspects if just BrowserInfos and no PerformanceAspects exist', inject(
[AspectConfigurationComponent],
(component: AspectConfigurationComponent) => {
const browserInfos: BrowserInfoDto[] = [{
browserId: 1,
browserName: 'Chrome',
operatingSystem: 'Windows',
deviceType: {name: 'Desktop', icon: 'desktop'}
}];
const extendedAspects: ExtendedPerformanceAspect[] = component.extendAspects([], browserInfos);
expect(extendedAspects.length).toBe(0)
}));
it('should not provide any extended aspects if just PerformanceAspects and no BrowserInfos exist', inject(
[AspectConfigurationComponent],
(component: AspectConfigurationComponent) => {
const aspects: PerformanceAspect[] = [{
id: 1,
pageId: 1,
jobGroupId: 1,
browserId: 1,
measurand: {id: 'DOC_COMPLETE', name: 'Document complete'},
performanceAspectType: {name: 'PAGE_CONSTRUCTION_STARTED', icon: 'hourglass'},
persistent: true,
}];
const extendedAspects: ExtendedPerformanceAspect[] = component.extendAspects(aspects, []);
expect(extendedAspects.length).toBe(0)
}));
it('should extend aspects correctly only if matching BrowserInfo exists', inject(
[AspectConfigurationComponent],
(component: AspectConfigurationComponent) => {
const idOfExtended: number = 1;
const idOfNotExtended: number = 2;
const aspects: PerformanceAspect[] = [
{
id: 1,
pageId: 1,
jobGroupId: 1,
browserId: idOfExtended,
measurand: {id: 'DOC_COMPLETE', name: 'Document complete'},
performanceAspectType: {name: 'PAGE_CONSTRUCTION_STARTED', icon: 'hourglass'},
persistent: true,
},
{
id: 1,
pageId: 1,
jobGroupId: 1,
browserId: idOfNotExtended,
measurand: {id: 'DOC_COMPLETE', name: 'Document complete'},
performanceAspectType: {name: 'PAGE_CONSTRUCTION_STARTED', icon: 'hourglass'},
persistent: true,
}
];
const browserInfos: BrowserInfoDto[] = [{
browserId: idOfExtended,
browserName: 'Chrome',
operatingSystem: 'Windows',
deviceType: {name: 'Desktop', icon: 'desktop'}
}];
const extendedAspects: ExtendedPerformanceAspect[] = component.extendAspects(aspects, browserInfos);
expect(extendedAspects.length).toBe(2);
const extendedAspect: ExtendedPerformanceAspect = extendedAspects.filter((aspect: PerformanceAspect) => aspect.browserId == idOfExtended)[0];
expect(extendedAspect.browserName).toBe('Chrome');
expect(extendedAspect.operatingSystem).toBe('Windows');
expect(extendedAspect.deviceType).toEqual({name: 'Desktop', icon: 'desktop'});
const notExtendedAspect: ExtendedPerformanceAspect = extendedAspects.filter((aspect: PerformanceAspect) => aspect.browserId == idOfNotExtended)[0];
expect(notExtendedAspect.browserName).toBe('Unknown');
expect(notExtendedAspect.operatingSystem).toBe('Unknown');
expect(notExtendedAspect.deviceType).toEqual({name: 'Unknown', icon: 'question'});
}));
});

});

0 comments on commit 1428f01

Please sign in to comment.
You can’t perform that action at this time.