Skip to content

Commit b77c79d

Browse files
Add stability indicator
1 parent 30e58d8 commit b77c79d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+498
-231
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
Features:
66
- Move Administration to main Menu bar to make it more visible -> [View Issue](https://github.com/aquality-automation/aquality-tracking/issues/58)
7+
- Test Run view: Add stability indicator -> [View Issue](https://github.com/aquality-automation/aquality-tracking/issues/60)
78

89
Bugfixes:
910

src/app/app.component.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,9 @@ export class AppComponent {
192192
link: `/audit/${this.projectId}`,
193193
show: (await this.permissionsService.hasPermissions(undefined,
194194
[ELocalPermissions.admin, ELocalPermissions.engineer, ELocalPermissions.manager, ELocalPermissions.viewer]))
195-
&& this.projectId && this.globaldata.auditModule,
195+
&& this.projectId && this.globaldata.auditModule &&
196+
!(await this.permissionsService.hasPermissions([EGlobalPermissions.manager, EGlobalPermissions.auditor,
197+
EGlobalPermissions.audit_admin])),
196198
routerOptions: { exact: true }
197199
}, {
198200
name: 'Audits',

src/app/app.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { NgModule } from '@angular/core';
22
import { BrowserModule, } from '@angular/platform-browser';
33
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
4-
import { FormsModule } from '@angular/forms';
4+
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
55
import { HttpModule, BrowserXhr } from '@angular/http';
66
import { HashLocationStrategy, LocationStrategy } from '@angular/common';
77
import { CookieService, CookieOptions } from 'angular2-cookie/core';
@@ -33,6 +33,7 @@ import { GuardService } from './shared/guards/guard.service';
3333
AdministrationModule,
3434
BrowserModule,
3535
FormsModule,
36+
ReactiveFormsModule,
3637
appRouting,
3738
HttpModule,
3839
ProjectModule,

src/app/derectives/mfTableSorter.derective.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ import {
22
Directive, ElementRef, AfterViewChecked,
33
Input, Output, Renderer, EventEmitter
44
} from '@angular/core';
5+
import { TFSorting, TFOrder } from '../elements/table/tfColumn';
56

67
@Directive({
78
selector: '[sorter]'
89
})
910
export class TableSorterDerective implements AfterViewChecked {
1011
@Input()
11-
sorter: {order: string, property: string};
12+
sorter: TFSorting;
1213
@Output()
1314
sorted = new EventEmitter();
1415

@@ -46,15 +47,17 @@ export class TableSorterDerective implements AfterViewChecked {
4647
icon.classList.remove('glyphicon-triangle-top');
4748
icon.classList.remove('glyphicon');
4849

49-
if (this.sorter.order === 'asc') {
50-
this.sorter = {order: 'desc', property: this.sorter.property};
51-
icon.classList.add('glyphicon');
52-
icon.classList.add('glyphicon-triangle-top');
53-
} else if (this.sorter.order === 'desc') {
54-
this.sorter = {order: 'asc', property: this.sorter.property};
55-
icon.classList.add('glyphicon');
56-
icon.classList.add('glyphicon-triangle-bottom');
50+
switch (this.sorter.order) {
51+
case TFOrder.asc:
52+
this.sorter.order = TFOrder.desc;
53+
break;
54+
case TFOrder.desc:
55+
this.sorter.order = TFOrder.asc;
56+
break;
5757
}
58+
59+
icon.classList.add('glyphicon');
60+
icon.classList.add('glyphicon-triangle-bottom');
5861
this.sorted.emit(this.sorter);
5962
}
6063
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.label:empty {
2+
display: inline;
3+
}
4+
5+
.label {
6+
margin: 1px;
7+
padding: .2em .8em .3em;
8+
border-radius: 1em;
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<div class="color-dots-container">
2+
<span *ngFor="let color of numericColors" class="label" [ngClass]="{
3+
'label-danger': color === 1,
4+
'label-primary': color === 3,
5+
'label-warning': color === 2,
6+
'label-info': color === 4,
7+
'label-success': color === 5
8+
}"></span>
9+
</div>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Component, OnInit, Input } from '@angular/core';
2+
3+
@Component({
4+
selector: 'app-color-dots',
5+
templateUrl: './color-dots.component.html',
6+
styleUrls: ['./color-dots.component.css']
7+
})
8+
export class ColorDotsComponent implements OnInit {
9+
@Input() numericColors: number[];
10+
11+
constructor() { }
12+
13+
ngOnInit() {
14+
}
15+
16+
}
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
<div class="container-element" [ngClass]="{'el-small': size === 'small'}">
22
<div class="label-element pull-left">
3-
<label for="identifier" [title]="label">{{label}}</label>
3+
<label [for]="identifier" [title]="label">{{label}}</label>
44
</div>
5-
<div class="switch-element">
6-
<input class="form-control" [(ngModel)]="value" [id]="identifier"/>
5+
<div class="input-element">
6+
<input class="form-control" [(ngModel)]="value" [type]="type" [min]="min" [max]="max" [id]="identifier"
7+
[formControl]="rateControl" [name]="identifier" />
78
</div>
89
</div>
Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { Component, OnInit} from '@angular/core';
2-
import { NG_VALUE_ACCESSOR } from '@angular/forms';
1+
import { Component, OnInit, Input } from '@angular/core';
2+
import { NG_VALUE_ACCESSOR, FormControl, Validators, ValidatorFn } from '@angular/forms';
33
import { LabeledBaseComponent } from '../labeled-base.component';
44
let identifier = 0;
55

@@ -8,16 +8,29 @@ let identifier = 0;
88
templateUrl: './labeled-input.component.html',
99
styleUrls: ['./labeled-input.component.css'],
1010
providers: [
11-
{provide: NG_VALUE_ACCESSOR, useExisting: LabeledInputComponent, multi: true}
11+
{ provide: NG_VALUE_ACCESSOR, useExisting: LabeledInputComponent, multi: true }
1212
],
1313
})
1414
export class LabeledInputComponent extends LabeledBaseComponent<string> implements OnInit {
1515
public identifier = `labeled-input-${identifier++}`;
16+
public rateControl = new FormControl();
17+
@Input() public type: string;
18+
@Input() public max: string;
19+
@Input() public min: string;
1620

1721
constructor() {
1822
super();
1923
}
2024

2125
ngOnInit() {
26+
const validators: ValidatorFn[] = []
27+
if (this.min) {
28+
validators.push(Validators.min(+this.min));
29+
}
30+
if (this.max) {
31+
validators.push(Validators.max(+this.max));
32+
}
33+
34+
this.rateControl.setValidators(validators);
2235
}
2336
}

src/app/elements/table/filter.helper.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ export class Filter {
99
to?: Date;
1010
options?: string;
1111
range?: string;
12+
dots?: { name: string, only?: number[], contains?: number[] }
13+
ft_select?: boolean | number;
1214
}
1315

1416
export class FilterHelper {
@@ -35,9 +37,9 @@ export class FilterHelper {
3537

3638
updateAppliedFilters = (appliedFilters: Filter[], filter: Filter) => {
3739
appliedFilters = appliedFilters.filter((x: Filter) => x.property !== filter.property &&
38-
(x.from === undefined || filter.from === undefined ) ||
40+
(x.from === undefined || filter.from === undefined) ||
3941
(x.to === undefined || filter.to === undefined));
40-
if (filter.value || filter.state !== undefined || filter.options || filter.range || filter.from || filter.to) {
42+
if (filter.value || filter.state !== undefined || filter.options || filter.range || filter.from || filter.to || filter.dots) {
4143
appliedFilters.push(filter);
4244
}
4345
return appliedFilters;
@@ -60,6 +62,11 @@ export class FilterHelper {
6062
queryParam[`f_${filter.property}_opt`] = filter.options;
6163
} else if (filter.range) {
6264
queryParam[`f_${filter.property}_rng`] = filter.range;
65+
} else if (filter.dots) {
66+
queryParam[`f_${filter.property}_dots`]
67+
= `name_${filter.dots.name}_only_${
68+
filter.dots.only ? filter.dots.only.join(',') : ''}_contains_${
69+
filter.dots.contains ? filter.dots.contains.join(',') : ''}`;
6370
} else {
6471
this.route.queryParams.subscribe(params => {
6572
const filterKeys = Object.keys(params);
@@ -96,6 +103,8 @@ export class FilterHelper {
96103
return this.filterRange(data, filter);
97104
} else if (filter.hasOwnProperty('state')) {
98105
return this.filterState(data, filter);
106+
} else if (filter.hasOwnProperty('dots')) {
107+
return this.filterDots(data, filter);
99108
} else {
100109
return data;
101110
}
@@ -164,6 +173,23 @@ export class FilterHelper {
164173
return data;
165174
}
166175

176+
filterDots(filteredData: any[], filter: Filter) {
177+
let data = filteredData;
178+
if (filter.dots !== undefined) {
179+
data = filteredData.filter(x => {
180+
const value = x[filter.property] as number[];
181+
if (filter.dots.only && filter.dots.only.length > 0) {
182+
return value.every(dot => filter.dots.only.includes(dot));
183+
} else if (filter.dots.contains && filter.dots.contains.length > 0) {
184+
return value.some(dot => filter.dots.contains.includes(dot));
185+
} else {
186+
return true;
187+
}
188+
});
189+
}
190+
return data;
191+
}
192+
167193
applyNewFilter = (data: any[], appliedFilters: Filter[], newFilter: Filter, queryParams: boolean): {
168194
filteredData: any[],
169195
newFilters: Filter[]
@@ -203,6 +229,8 @@ export class FilterHelper {
203229
const range = /f_(.*)_rng/;
204230
const state = /f_(.*)_st/;
205231
const value = /f_(.*)/;
232+
const dots = /f_(.*)_dots/;
233+
const dotsValue = /name_(.*)_only_(.*)_contains_(.*)/;
206234
const filter: Filter = new Filter();
207235

208236
if (dateFrom.test(parameter)) {
@@ -220,6 +248,15 @@ export class FilterHelper {
220248
} else if (state.test(parameter)) {
221249
filter.property = parameter.match(state)[1];
222250
filter.state = parameters[parameter] === 'true' ? true : parameters[parameter] === 'false' ? false : undefined;
251+
} else if (dots.test(parameter)) {
252+
filter.property = parameter.match(dots)[1];
253+
if (parameters[parameter]) {
254+
filter.dots = {
255+
name: parameters[parameter].match(dotsValue)[1],
256+
only: JSON.parse(`[${parameters[parameter].match(dotsValue)[2]}]`) as number[],
257+
contains: JSON.parse(`[${parameters[parameter].match(dotsValue)[3]}]`) as number[]
258+
};
259+
}
223260
} else if (value.test(parameter)) {
224261
filter.property = parameter.match(value)[1];
225262
filter.value = parameters[parameter];

0 commit comments

Comments
 (0)