Skip to content
This repository was archived by the owner on May 14, 2025. It is now read-only.

Commit af54815

Browse files
oodamienghillert
authored andcommitted
Runtime Module: coverage tests, documentation, optimizations
- Clean architecture - Separate runtime list and runtime modal - Create component state runtime - Fix type model (String to string)
1 parent 5b86399 commit af54815

22 files changed

+733
-302
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import {Component, ChangeDetectionStrategy, Input, OnChanges, SimpleChanges} from '@angular/core';
2+
3+
/**
4+
* Runtime application status.
5+
*
6+
* @author Vitrac Damien
7+
*/
8+
@Component({
9+
selector: 'app-runtime-state',
10+
styleUrls: ['./styles.scss'],
11+
template: `<span *ngIf="state" class="label label-{{className}}">{{ state | uppercase }}</span>`,
12+
changeDetection: ChangeDetectionStrategy.OnPush
13+
})
14+
export class RuntimeAppStateComponent implements OnChanges {
15+
16+
/**
17+
* Runtime Application
18+
*/
19+
@Input() runtimeApp;
20+
21+
/**
22+
* Current status
23+
*/
24+
state = '';
25+
26+
/**
27+
* CSS class
28+
*/
29+
className = 'default';
30+
31+
/**
32+
* Constructor
33+
*/
34+
constructor() {
35+
}
36+
37+
ngOnChanges(changes: SimpleChanges) {
38+
if (changes.runtimeApp.currentValue.state) {
39+
this.state = changes.runtimeApp.currentValue.state;
40+
switch (this.state) {
41+
case 'failed':
42+
this.className = 'danger';
43+
break;
44+
case 'deploying':
45+
this.className = 'info';
46+
break;
47+
case 'deployed':
48+
this.className = 'success';
49+
break;
50+
}
51+
}
52+
}
53+
54+
55+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
.label {
3+
border-radius: 10px;
4+
font-size: 12px;
5+
}

ui/src/app/runtime/model/runtime-app.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ import {Page} from '../../shared/model/page';
77
* @author Ilayaperumal Gopinathan
88
*/
99
export class RuntimeApp {
10-
public deploymentId: String;
11-
public state: String;
10+
public deploymentId: string;
11+
public state: string;
1212
public instances: any;
1313
public appInstances: RuntimeAppInstance[];
1414

1515
constructor(
16-
deploymentId: String,
17-
state: String,
16+
deploymentId: string,
17+
state: string,
1818
instances: any,
1919
appInstances: RuntimeAppInstance[]) {
2020
this.deploymentId = deploymentId;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<div *ngIf="runtimeApp$ | async as runtimeApp; else loading" id="page">
2+
<div class="modal-header">
3+
<h4 class="modal-title pull-left">Instances for app <strong>{{runtimeApp.deploymentId}}</strong></h4>
4+
<button type="button" class="close pull-right" aria-label="Close" (click)="cancel()">
5+
<span aria-hidden="true">&times;</span>
6+
</button>
7+
</div>
8+
<div class="modal-body">
9+
<ng-template ngFor let-item [ngForOf]="runtimeApp.appInstances">
10+
<div class="panel">
11+
<div class="panel-heading">
12+
Instance
13+
<strong>{{item.instanceId}}</strong>
14+
<app-runtime-state [runtimeApp]="item"></app-runtime-state>
15+
</div>
16+
<div class="panel-content">
17+
<ng-template ngFor let-item [ngForOf]="item.attributes | keyvalues">
18+
<div class="row row-key-value">
19+
<div class="col-md-4">
20+
<strong>{{item.key}}</strong>
21+
</div>
22+
<div class="col-md-20">
23+
<span class="form-control input-sm">{{item.value}}</span>
24+
</div>
25+
</div>
26+
</ng-template>
27+
</div>
28+
</div>
29+
</ng-template>
30+
</div>
31+
<div class="modal-footer">
32+
<button type="button" class="btn btn-default" (click)="cancel()">Cancel</button>
33+
</div>
34+
</div>
35+
36+
<ng-template #loading><div>Loading...</div></ng-template>
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
2+
import {NgxPaginationModule} from 'ngx-pagination';
3+
import {ToastyService} from 'ng2-toasty';
4+
import {ModalModule, BsModalRef} from 'ngx-bootstrap';
5+
import {MockToastyService} from '../../tests/mocks/toasty';
6+
import {MockRuntimeAppsService} from '../../tests/mocks/runtime';
7+
import {RuntimeAppsService} from '../runtime-apps.service';
8+
import {RuntimeAppStateComponent} from '../components/runtime-app-state/runtime-app-state.component';
9+
import {RuntimeAppComponent} from './runtime-app.component';
10+
import {By} from '@angular/platform-browser';
11+
import {RUNTIME_APPS} from '../../tests/mocks/mock-data';
12+
import {RuntimeApp} from '../model/runtime-app';
13+
import {KeyValuePipe} from '../../shared/pipes/key-value-filter.pipe';
14+
import {RuntimeAppInstance} from '../model/runtime-app-instance';
15+
import {NgBusyModule} from 'ng-busy';
16+
17+
describe('RuntimeAppComponent', () => {
18+
let component: RuntimeAppComponent;
19+
let fixture: ComponentFixture<RuntimeAppComponent>;
20+
const toastyService = new MockToastyService();
21+
const runtimeAppsService = new MockRuntimeAppsService();
22+
const bsModalRef = new BsModalRef();
23+
const mock: any = RUNTIME_APPS;
24+
25+
beforeEach(async(() => {
26+
TestBed.configureTestingModule({
27+
declarations: [
28+
RuntimeAppComponent,
29+
KeyValuePipe,
30+
RuntimeAppStateComponent
31+
],
32+
imports: [
33+
NgBusyModule,
34+
NgxPaginationModule,
35+
ModalModule.forRoot()
36+
],
37+
providers: [
38+
{provide: RuntimeAppsService, useValue: runtimeAppsService},
39+
{provide: BsModalRef, useValue: bsModalRef},
40+
{provide: ToastyService, useValue: toastyService}
41+
]
42+
})
43+
.compileComponents();
44+
}));
45+
46+
beforeEach(() => {
47+
fixture = TestBed.createComponent(RuntimeAppComponent);
48+
component = fixture.componentInstance;
49+
});
50+
51+
describe('2 instances with multiples attributes', () => {
52+
53+
beforeEach(() => {
54+
component.open(new RuntimeApp(
55+
'ab.log',
56+
'failed',
57+
null,
58+
[
59+
new RuntimeAppInstance('Instance1', 'deployed', {foo: 'bar'}),
60+
new RuntimeAppInstance('Instance2', 'failed', {foo: 'bar'}),
61+
]
62+
));
63+
fixture.detectChanges();
64+
});
65+
66+
it('should display the name, type and attributes of each instance', () => {
67+
const modalHeader = fixture.debugElement.query(By.css('.modal-header'));
68+
const panelHeadings = fixture.debugElement.queryAll(By.css('.modal-body .panel-heading'));
69+
expect(panelHeadings[0].nativeElement.textContent).toContain('Instance1');
70+
expect(panelHeadings[0].nativeElement.textContent).toContain('DEPLOYED');
71+
expect(panelHeadings[1].nativeElement.textContent).toContain('Instance2');
72+
expect(panelHeadings[1].nativeElement.textContent).toContain('FAILED');
73+
expect(modalHeader.nativeElement.textContent).toContain('ab.log');
74+
});
75+
76+
});
77+
78+
describe('Modal cancel', () => {
79+
80+
beforeEach(() => {
81+
component.open(mock._embedded.appStatusResourceList[0] as RuntimeApp);
82+
fixture.detectChanges();
83+
});
84+
85+
it('should call the close action (header close)', () => {
86+
const spy = spyOn(bsModalRef, 'hide');
87+
fixture.debugElement.query(By.css('.modal-header .close')).nativeElement.click();
88+
fixture.detectChanges();
89+
expect(spy).toHaveBeenCalled();
90+
});
91+
92+
it('should call the close action (footer close)', () => {
93+
const spy = spyOn(bsModalRef, 'hide');
94+
fixture.debugElement.query(By.css('.modal-footer .btn-default')).nativeElement.click();
95+
fixture.detectChanges();
96+
expect(spy).toHaveBeenCalled();
97+
});
98+
99+
});
100+
101+
});
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import {Component} from '@angular/core';
2+
import {RuntimeApp} from '../model/runtime-app';
3+
import {Observable} from 'rxjs/Observable';
4+
import {BsModalRef} from 'ngx-bootstrap';
5+
6+
/**
7+
* Component that display a Runtime application.
8+
*
9+
* @author Ilayaperumal Gopinathan
10+
* @author Vitrac Damien
11+
*/
12+
@Component({
13+
selector: 'app-runtime-app',
14+
styleUrls: ['./styles.scss'],
15+
templateUrl: './runtime-app.component.html',
16+
})
17+
export class RuntimeAppComponent {
18+
19+
/**
20+
* Observable of Runtime Application
21+
*/
22+
runtimeApp$: Observable<RuntimeApp>;
23+
24+
/**
25+
* Constructor
26+
*
27+
* @param {BsModalRef} modalRef
28+
*/
29+
constructor(private modalRef: BsModalRef) {
30+
}
31+
32+
/**
33+
* Set the runtime application
34+
*
35+
* @param {RuntimeApp} runtimeApp
36+
*/
37+
open(runtimeApp: RuntimeApp) {
38+
this.runtimeApp$ = Observable.of(runtimeApp);
39+
}
40+
41+
/**
42+
* Hide the modal
43+
*/
44+
cancel() {
45+
this.modalRef.hide();
46+
}
47+
48+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
.panel {
2+
padding: 0;
3+
box-shadow: 0 0 0 white;
4+
border: 0 none;
5+
margin: 0;
6+
margin-bottom: 2rem;
7+
background: transparent;
8+
.panel-heading {
9+
padding: 1rem 0;
10+
border: 0 none;
11+
background: transparent;
12+
box-shadow: 0 0 0 white;
13+
}
14+
.panel-content {
15+
background: #f5f6f7;
16+
padding: 1.9rem 2.5rem;
17+
}
18+
}
19+
20+
.row-key-value {
21+
padding: 0.4rem 0;
22+
strong {
23+
line-height: 32px;
24+
}
25+
.form-control {
26+
overflow-x: auto;
27+
overflow-y: hidden;
28+
white-space: nowrap;
29+
display: block;
30+
height: 32px;
31+
word-break: break-all;
32+
word-wrap: break-word;
33+
}
34+
}
35+

ui/src/app/runtime/runtime-apps.component.html

Lines changed: 0 additions & 74 deletions
This file was deleted.

0 commit comments

Comments
 (0)