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

Commit c38ae12

Browse files
committed
Stream History
Resolves #841
1 parent e808236 commit c38ae12

16 files changed

+446
-16
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { StreamHistoryStatusComponent } from './stream-status.component';
3+
4+
/**
5+
* Test {@link StreamHistoryComponent}.
6+
*
7+
* @author Damien Vitrac
8+
*/
9+
describe('StreamHistoryStatusComponent', () => {
10+
let component: StreamHistoryStatusComponent;
11+
let fixture: ComponentFixture<StreamHistoryStatusComponent>;
12+
13+
beforeEach(async(() => {
14+
TestBed.configureTestingModule({
15+
declarations: [
16+
StreamHistoryStatusComponent
17+
]
18+
}).compileComponents();
19+
}));
20+
21+
beforeEach(() => {
22+
fixture = TestBed.createComponent(StreamHistoryStatusComponent);
23+
component = fixture.componentInstance;
24+
});
25+
26+
it('should be created', () => {
27+
fixture.detectChanges();
28+
expect(component).toBeTruthy();
29+
});
30+
31+
});
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core';
2+
3+
/**
4+
* Component used to display a stream history status.
5+
*
6+
* @author Damien Vitrac
7+
*/
8+
@Component({
9+
selector: 'app-stream-history-status',
10+
template: `<span class="label label-stream-status label-{{ labelClass }}">{{ label }}</span>`,
11+
changeDetection: ChangeDetectionStrategy.OnPush
12+
})
13+
export class StreamHistoryStatusComponent implements OnChanges {
14+
15+
/**
16+
* Stream Definition
17+
*/
18+
@Input() status: string;
19+
20+
/**
21+
* Label
22+
*/
23+
label: string;
24+
25+
/**
26+
* Dedicate CSS class
27+
*/
28+
labelClass: string;
29+
30+
/**
31+
* On Changes listener
32+
* @param {SimpleChanges} changes
33+
*/
34+
ngOnChanges(changes: SimpleChanges) {
35+
if (changes.status && changes.status.currentValue) {
36+
this.label = changes.status.currentValue.toString().toUpperCase()
37+
} else {
38+
this.label = 'unknown'.toUpperCase();
39+
}
40+
switch (this.label.toLowerCase()) {
41+
default:
42+
case 'undeployed':
43+
this.labelClass = 'default';
44+
break;
45+
case 'deleted':
46+
this.labelClass = 'danger';
47+
break;
48+
case 'incomplete':
49+
this.labelClass = 'warning';
50+
break;
51+
case 'deployed':
52+
this.labelClass = 'primary';
53+
break;
54+
}
55+
}
56+
}

ui/src/app/streams/components/stream-status/stream-status.component.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export class StreamStatusComponent implements OnChanges {
3434
*/
3535
ngOnChanges(changes: SimpleChanges) {
3636
if (changes.streamDefinition) {
37+
console.log(changes.streamDefinition.currentValue.status);
3738
if (changes.streamDefinition.currentValue.status) {
3839
this.label = changes.streamDefinition.currentValue.status.toString().toUpperCase();
3940
} else {
@@ -44,6 +45,7 @@ export class StreamStatusComponent implements OnChanges {
4445
case 'undeployed':
4546
this.labelClass = 'default';
4647
break;
48+
case 'deleted':
4749
case 'failed':
4850
this.labelClass = 'danger';
4951
break;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { StreamHistory } from './stream-history';
2+
3+
/**
4+
* Test {@link StreamHistory} model.
5+
*
6+
* @author Damien Vitrac
7+
*/
8+
describe('StreamHistory', () => {
9+
10+
describe('basicValidationCheck', () => {
11+
it('Constructor should setup stream history properly.', () => {
12+
const date = new Date();
13+
const history = new StreamHistory('foo', 1, date, 'deployed', 'Upgrade complete', 'default');
14+
expect(history.stream).toBe('foo');
15+
expect(history.version).toBe(1);
16+
expect(history.firstDeployed).toBe(date);
17+
expect(history.statusCode).toBe('deployed');
18+
expect(history.description).toBe('Upgrade complete');
19+
expect(history.platformName).toBe('default');
20+
});
21+
});
22+
23+
});
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* Represents a deployment history of a stream definition
3+
*
4+
* @author Damien Vitrac
5+
*/
6+
export class StreamHistory {
7+
8+
public stream: string;
9+
10+
public version: number;
11+
12+
public firstDeployed: Date;
13+
14+
public statusCode: string;
15+
16+
public description: string;
17+
18+
public platformName: string;
19+
20+
constructor(stream: string, version: number, firstDeployed: Date, statusCode: string, description: string, platformName: string) {
21+
this.stream = stream;
22+
this.version = version;
23+
this.firstDeployed = firstDeployed;
24+
this.statusCode = statusCode;
25+
this.description = description;
26+
this.platformName = platformName;
27+
}
28+
29+
static fromJSON(input) {
30+
let firstDeployed;
31+
let statusCode;
32+
let description;
33+
34+
console.log(input);
35+
36+
if (input['info']) {
37+
description = input.info.description;
38+
firstDeployed = input.info.firstDeployed;
39+
if (input.info['status'] && input.info.status['statusCode']) {
40+
statusCode = input.info.status.statusCode;
41+
}
42+
}
43+
return new StreamHistory(input.name, input.version, firstDeployed, statusCode, description, input.platformName);
44+
}
45+
46+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<div *ngIf="stream$ | async as stream; else loading">
2+
3+
<table class="table table-hover" id="table-history" *ngIf="stream.history.length > 0">
4+
<thead>
5+
<tr>
6+
<th>Version</th>
7+
<th>Date</th>
8+
<th>Stream Status</th>
9+
<th>Description</th>
10+
<th>platformName</th>
11+
</tr>
12+
</thead>
13+
<tbody>
14+
<tr *ngFor="let history of stream.history">
15+
<td>
16+
<strong>{{ history.version }}</strong>
17+
</td>
18+
<td>{{ history.firstDeployed | date: 'short'}}</td>
19+
<td>
20+
<app-stream-history-status [status]="history.statusCode"></app-stream-history-status>
21+
</td>
22+
<td>{{ history.description}}</td>
23+
<td>{{ history.platformName}}</td>
24+
</tr>
25+
</tbody>
26+
</table>
27+
28+
<div *ngIf="stream.history.length == 0" class="alert alert-warning" style="display:inline-block;margin:0 auto">
29+
<div style="padding-right: 15px">
30+
No history.
31+
</div>
32+
</div>
33+
34+
</div>
35+
<ng-template #loading>
36+
<app-loader></app-loader>
37+
</ng-template>
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { MockStreamsService } from '../../../tests/mocks/streams';
3+
import { MockActivatedRoute } from '../../../tests/mocks/activated-route';
4+
import { RouterTestingModule } from '@angular/router/testing';
5+
import { StreamsService } from '../../streams.service';
6+
import { ActivatedRoute } from '@angular/router';
7+
import { FloModule } from 'spring-flo';
8+
import { MockNotificationService } from '../../../tests/mocks/notification';
9+
import { BsModalService } from 'ngx-bootstrap';
10+
import { MockModalService } from '../../../tests/mocks/modal';
11+
import { StreamStatusComponent } from '../../components/stream-status/stream-status.component';
12+
import { AppTypeComponent } from '../../../apps/components/app-type/app-type.component';
13+
import { RolesDirective } from '../../../auth/directives/roles.directive';
14+
import { StreamDslComponent } from '../../../shared/components/dsl/dsl.component';
15+
import { STREAM_DEFINITIONS } from '../../../tests/mocks/mock-data';
16+
import { MockAuthService } from '../../../tests/mocks/auth';
17+
import { AuthService } from '../../../auth/auth.service';
18+
import { MocksSharedAboutService } from '../../../tests/mocks/shared-about';
19+
import { SharedAboutService } from '../../../shared/services/shared-about.service';
20+
import { LoaderComponent } from '../../../shared/components/loader/loader.component';
21+
import { DeploymentPropertiesInfoComponent } from '../../streams/deployment-properties-info/deployment-properties-info.component';
22+
import { NotificationService } from '../../../shared/services/notification.service';
23+
import { LoggerService } from '../../../shared/services/logger.service';
24+
import { StreamHistoryComponent } from './stream-history.component';
25+
import { StreamHistoryStatusComponent } from '../../components/stream-history-status/stream-status.component';
26+
import { By } from '@angular/platform-browser';
27+
28+
/**
29+
* Test {@link StreamHistoryComponent}.
30+
*
31+
* @author Damien Vitrac
32+
*/
33+
describe('StreamHistoryComponent', () => {
34+
let component: StreamHistoryComponent;
35+
let fixture: ComponentFixture<StreamHistoryComponent>;
36+
let activeRoute: MockActivatedRoute;
37+
const streamsService = new MockStreamsService();
38+
const commonTestParams = { id: '1' };
39+
const notificationService = new MockNotificationService();
40+
const modalService = new MockModalService();
41+
const authService = new MockAuthService();
42+
const aboutService = new MocksSharedAboutService();
43+
const loggerService = new LoggerService();
44+
45+
beforeEach(async(() => {
46+
activeRoute = new MockActivatedRoute();
47+
48+
TestBed.configureTestingModule({
49+
declarations: [
50+
StreamHistoryComponent,
51+
StreamStatusComponent,
52+
AppTypeComponent,
53+
StreamDslComponent,
54+
RolesDirective,
55+
DeploymentPropertiesInfoComponent,
56+
LoaderComponent,
57+
StreamHistoryStatusComponent
58+
],
59+
imports: [
60+
RouterTestingModule.withRoutes([]),
61+
FloModule
62+
],
63+
providers: [
64+
{ provide: StreamsService, useValue: streamsService },
65+
{ provide: ActivatedRoute, useValue: activeRoute },
66+
{ provide: BsModalService, useValue: modalService },
67+
{ provide: SharedAboutService, useValue: aboutService },
68+
{ provide: AuthService, useValue: authService },
69+
{ provide: NotificationService, useValue: notificationService },
70+
{ provide: LoggerService, useValue: loggerService }
71+
]
72+
})
73+
.compileComponents();
74+
}));
75+
76+
beforeEach(() => {
77+
activeRoute.testParams = commonTestParams;
78+
fixture = TestBed.createComponent(StreamHistoryComponent);
79+
component = fixture.componentInstance;
80+
streamsService.streamDefinitions = STREAM_DEFINITIONS;
81+
});
82+
83+
it('should be created', () => {
84+
fixture.detectChanges();
85+
expect(component).toBeTruthy();
86+
});
87+
88+
it('should populate 2 history', () => {
89+
fixture.detectChanges();
90+
91+
const trs = fixture.debugElement.queryAll(By.css('#table-history tbody tr'));
92+
expect(trs.length).toBe(2);
93+
94+
const tds0 = trs[0].queryAll(By.css('td'));
95+
const tds1 = trs[1].queryAll(By.css('td'));
96+
97+
expect(tds0.length).toBe(5);
98+
expect(tds1.length).toBe(5);
99+
100+
expect(tds0[0].nativeElement.textContent).toBe('2');
101+
expect(tds0[2].nativeElement.textContent).toContain('DEPLOYED');
102+
expect(tds0[3].nativeElement.textContent).toContain('Upgrade complete');
103+
expect(tds0[4].nativeElement.textContent).toContain('default');
104+
105+
expect(tds1[0].nativeElement.textContent).toBe('1');
106+
expect(tds1[2].nativeElement.textContent).toContain('DELETED');
107+
expect(tds1[3].nativeElement.textContent).toContain('Delete complete');
108+
expect(tds1[4].nativeElement.textContent).toContain('default');
109+
});
110+
111+
});
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { Component, OnInit } from '@angular/core';
2+
import { Observable } from 'rxjs/Rx';
3+
import { StreamDefinition } from '../../model/stream-definition';
4+
import { map, mergeMap } from 'rxjs/internal/operators';
5+
import { StreamsService } from '../../streams.service';
6+
import { ActivatedRoute, Router } from '@angular/router';
7+
import { StreamHistory } from '../../model/stream-history';
8+
9+
/**
10+
* Component that shows the history of a Stream Definition
11+
* Available only if skipper is enabled
12+
*
13+
* @author Damien Vitrac
14+
*/
15+
@Component({
16+
selector: 'app-stream-history',
17+
templateUrl: 'stream-history.component.html',
18+
styleUrls: ['../styles.scss'],
19+
})
20+
export class StreamHistoryComponent implements OnInit {
21+
22+
/**
23+
* Observable of stream information
24+
* Contains the stream definition, a list of the streams"s apps
25+
*/
26+
stream$: Observable<any>;
27+
28+
constructor(private route: ActivatedRoute,
29+
private router: Router,
30+
private streamsService: StreamsService) {
31+
}
32+
33+
ngOnInit() {
34+
this.stream$ = this.route.parent.params
35+
.pipe(mergeMap(
36+
val => this.streamsService.getDefinition(val.id)
37+
))
38+
.pipe(mergeMap(
39+
(streamDefinition: StreamDefinition) => this.streamsService.getHistory(streamDefinition.name)
40+
.pipe(map((streamHistory: StreamHistory[]) => {
41+
return {
42+
stream: streamDefinition,
43+
history: streamHistory
44+
};
45+
}))
46+
));
47+
}
48+
49+
}

ui/src/app/streams/stream/stream.component.html

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
<div *ngIf="streamDefinitions$ | async as streamDefinitions; else loading">
1+
<div *ngIf="streamDefinition$ | async as streamDefinition; else loading">
22

33
<div class="heading">
44
<div class="description">
5-
<h1>Detailed view of stream <strong>'{{ streamDefinitions.name }}'</strong></h1>
5+
<h1>Detailed view of stream <strong>'{{ streamDefinition.streamDefinition.name }}'</strong></h1>
66
<p>This section shows the details of a stream.</p>
77
</div>
88
</div>
@@ -11,6 +11,9 @@ <h1>Detailed view of stream <strong>'{{ streamDefinitions.name }}'</strong></h1>
1111
<ul class="nav nav-tabs">
1212
<li role="presentation" routerLinkActive="active"><a routerLink="summary">Summary</a></li>
1313
<li role="presentation" routerLinkActive="active"><a routerLink="graph">Graph</a></li>
14+
<li role="presentation" routerLinkActive="active" *ngIf="streamDefinition.featureInfo.skipperEnabled">
15+
<a routerLink="history">History</a>
16+
</li>
1417
</ul>
1518
<div class="tab-content">
1619
<div class="tab-pane in active">

0 commit comments

Comments
 (0)