Skip to content
This repository has been archived by the owner on Dec 21, 2023. It is now read-only.

Commit

Permalink
feat(bridge): Refactor dashboard to use interfaces (#8205)
Browse files Browse the repository at this point in the history
* feat(bridge): Refactor dashboard to use interfaces
- Add IProject, IProjectResult
- Refactor components and services

Signed-off-by: Heinz Burgstaller <heinz.burgstaller@dynatrace.com>

* - Refactor to use ISequence

Signed-off-by: Heinz Burgstaller <heinz.burgstaller@dynatrace.com>

* - Refactor unit tests

Signed-off-by: Heinz Burgstaller <heinz.burgstaller@dynatrace.com>

* - Add steady to abstract state info

Signed-off-by: Heinz Burgstaller <heinz.burgstaller@dynatrace.com>
  • Loading branch information
heinzburgstaller committed Jun 28, 2022
1 parent 5d14929 commit 2cbbc2d
Show file tree
Hide file tree
Showing 40 changed files with 474 additions and 182 deletions.
@@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { Project } from '../../_models/project';
import { Sequence } from '../../_models/sequence';
import { IMetadata } from '../../_interfaces/metadata';
import { IProject } from '../../../../shared/interfaces/project';

export type ProjectSequences = Record<string, Sequence[]>;

Expand All @@ -13,10 +13,10 @@ export type ProjectSequences = Record<string, Sequence[]>;
})
export class KtbProjectListComponent {
@Input() metadata: IMetadata | null = null;
@Input() projects: Project[] = [];
@Input() projects: IProject[] = [];
@Input() sequences: ProjectSequences = {};

getSequencesPerProject(project: Project): Sequence[] {
getSequencesPerProject(project: IProject): Sequence[] {
const latestSequences = this.sequences[project.projectName];
return latestSequences ?? [];
}
Expand Down
Expand Up @@ -2,28 +2,28 @@
<dt-tile-title uitestid="keptn-project-tile-title">
<a
[routerLink]="['/project', project.projectName]"
[class.error]="project.isShipyardNotSupported(supportedShipyardVersion)"
[class.error]="isShipyardNotSupported(project, supportedShipyardVersion)"
>{{ project.projectName }}</a
>
</dt-tile-title>
<dt-tile-subtitle>
<p class="mt-0 mb-2" *ngIf="project.stages" uitestid="keptn-project-tile-numStagesServices">
<span [textContent]="project.stages.length"></span> Stages,
<span [textContent]="project.getServices().length"></span> Services
<span [textContent]="getDistinctServiceNames(project).length"></span> Services
</p>
<p class="mt-0 mb-2" *ngIf="project.getShipyardVersion() as sv" uitestid="keptn-project-tile-shipyardVersion">
<p class="mt-0 mb-2" *ngIf="getShipyardVersion(project) as sv" uitestid="keptn-project-tile-shipyardVersion">
Shipyard version: <span [textContent]="sv"></span>
<dt-icon
name="abort"
class="error bottom"
*ngIf="project.isShipyardNotSupported(supportedShipyardVersion)"
*ngIf="isShipyardNotSupported(project, supportedShipyardVersion)"
></dt-icon>
</p>
<div
class="mb-2"
fxLayout="row"
fxLayoutAlign="flex-start center"
*ngIf="project.isShipyardNotSupported(supportedShipyardVersion)"
*ngIf="isShipyardNotSupported(project, supportedShipyardVersion)"
>
<dt-icon name="information" class="info mr-1"></dt-icon>
<p class="small m-0" uitestid="keptn-project-tile-shipyardVersionNotSupported">
Expand Down
@@ -1,6 +1,7 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { Project } from '../../_models/project';
import { Sequence } from '../../_models/sequence';
import { IProject } from '../../../../shared/interfaces/project';
import { getDistinctServiceNames, getShipyardVersion, isShipyardNotSupported } from '../../_models/project';

@Component({
selector: 'ktb-project-tile',
Expand All @@ -9,7 +10,11 @@ import { Sequence } from '../../_models/sequence';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class KtbProjectTileComponent {
@Input() project?: Project;
@Input() project?: IProject;
@Input() sequences: Sequence[] = [];
@Input() supportedShipyardVersion: string | undefined;

getShipyardVersion = getShipyardVersion;
isShipyardNotSupported = isShipyardNotSupported;
getDistinctServiceNames = getDistinctServiceNames;
}
Expand Up @@ -11,6 +11,7 @@ import {
import { DateUtil } from '../../_utils/date.utils';
import { Project } from '../../_models/project';
import { Sequence } from '../../_models/sequence';
import { ISequence } from '../../../../shared/interfaces/sequence';

@Component({
selector: 'ktb-root-events-list',
Expand Down Expand Up @@ -54,9 +55,11 @@ export class KtbRootEventsListComponent {

constructor(private _changeDetectorRef: ChangeDetectorRef, public dateUtil: DateUtil) {}

selectEvent(sequence: Sequence, stage?: string): void {
this.selectedEvent = sequence;
this.selectedEventChange.emit({ sequence, stage });
selectEvent(sequence: ISequence, stage?: string): void {
// Refactor without using cast to Sequence
// use ISequence instead
this.selectedEvent = <Sequence>sequence;
this.selectedEventChange.emit({ sequence: <Sequence>sequence, stage });
}

identifyEvent(index: number, item: Sequence): string | undefined {
Expand Down
@@ -1,7 +1,7 @@
import { ChangeDetectorRef, Component, HostBinding, Input } from '@angular/core';
import { DataService } from '../../_services/data.service';
import { Sequence } from '../../_models/sequence';
import { SequenceStateControl } from '../../../../shared/models/sequence';
import { SequenceStateControl } from '../../../../shared/interfaces/sequence';
import {
KtbConfirmationDialogComponent,
SequenceConfirmDialogData,
Expand Down
Expand Up @@ -9,7 +9,7 @@ import { SubSequence } from '../../../../shared/interfaces/deployment';
import { EVENT_ICONS } from '../../_models/event-icons';
import { DtIconType } from '@dynatrace/barista-icons';
import { ResultTypes } from '../../../../shared/models/result-types';
import { SequenceState } from '../../../../shared/models/sequence';
import { SequenceState } from '../../../../shared/interfaces/sequence';

@Component({
selector: 'ktb-sequence-list',
Expand Down
@@ -1,27 +1,27 @@
<ng-container *ngIf="sequence">
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="5px">
<div *ngIf="createSequenceStateInfo(sequence) as info" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="5px">
<dt-icon
*ngIf="(!sequence.isLoading() && !sequence.isWaiting()) || sequence.hasPendingApproval(); else showLoading"
*ngIf="info.steady; else showLoading"
class="event-icon"
[name]="sequence.getIcon()"
[class.success]="sequence.isSuccessful()"
[class.warning]="sequence.isWarning()"
[class.error]="sequence.isFaulty()"
[class.highlight]="sequence.hasPendingApproval()"
[class.aborted]="sequence.isAborted()"
[name]="info.icon"
[class.success]="info.successful"
[class.warning]="info.warning"
[class.error]="info.faulty"
[class.highlight]="info.pendingApproval"
[class.aborted]="info.aborted"
></dt-icon>
<ng-template #showLoading>
<button class="m-0 p-0" dt-button disabled variant="nested" *ngIf="sequence.isLoading() && !sequence.isWaiting()">
<button class="m-0 p-0" dt-button disabled variant="nested" *ngIf="info.loading && !info.waiting">
<ktb-loading-spinner aria-label="Task is running..."></ktb-loading-spinner>
</button>
<dt-icon *ngIf="sequence.isWaiting()" class="event-icon" name="idle"></dt-icon>
<dt-icon *ngIf="info.waiting" class="event-icon" name="idle"></dt-icon>
</ng-template>
<p class="m-0 smaller">
<a
class="m-0 bold"
uitestid="keptn-sequence-info-sequenceName"
[routerLink]="getSequenceLink(sequence)"
[class.error]="sequence.isFaulty()"
[class.error]="info.faulty"
[textContent]="sequence.name"
></a>
of
Expand All @@ -31,7 +31,7 @@
[routerLink]="getServiceLink(sequence)"
[textContent]="sequence.service"
></a>
<span [textContent]="sequence.getStatus()" uitestid="keptn-sequence-info-status"></span>
<span [textContent]="info.statusText" uitestid="keptn-sequence-info-status"></span>
</p>
</div>
<div
Expand All @@ -42,16 +42,17 @@
fxLayoutGap="5px"
uitestid="keptn-sequence-info-stageDetails"
>
<ng-container *ngFor="let stage of sequence.getStages()">
<ng-container *ngFor="let stageName of getStageNames(sequence)">
<ktb-stage-badge
[stage]="stage"
[evaluationResult]="sequence.getEvaluation(stage)"
[success]="sequence.isSuccessful(stage)"
[error]="sequence.isFaulty(stage)"
[warning]="sequence.isWarning(stage)"
[highlight]="sequence.hasPendingApproval(stage)"
[aborted]="sequence.isAborted(stage)"
(click)="$event.stopPropagation(); stageClick(sequence, stage)"
*ngIf="createSequenceStateInfo(sequence, stageName) as badgeInfo"
[stage]="stageName"
[evaluationResult]="badgeInfo.evaluation"
[success]="badgeInfo.successful"
[error]="badgeInfo.faulty"
[warning]="badgeInfo.warning"
[highlight]="badgeInfo.pendingApproval"
[aborted]="badgeInfo.aborted"
(click)="$event.stopPropagation(); stageClick(sequence, stageName)"
></ktb-stage-badge>
</ng-container>
</div>
Expand Down
@@ -1,5 +1,6 @@
import { Component, EventEmitter, HostBinding, Input, Output, ViewEncapsulation } from '@angular/core';
import { Sequence } from '../../_models/sequence';
import { ISequence } from '../../../../shared/interfaces/sequence';
import { createSequenceStateInfo, getLastStageName, getStageNames } from '../../_models/sequence';

@Component({
selector: 'ktb-sequence-state-info',
Expand All @@ -9,16 +10,20 @@ import { Sequence } from '../../_models/sequence';
})
export class KtbSequenceStateInfoComponent {
@HostBinding('class') cls = 'ktb-sequence-state-info';
private _sequence?: Sequence;
private _sequence?: ISequence;
private _showStages = true;

@Output() readonly stageClicked = new EventEmitter<{ sequence: Sequence; stage?: string }>();
createSequenceStateInfo = createSequenceStateInfo;
getStageNames = getStageNames;

@Output() readonly stageClicked = new EventEmitter<{ sequence: ISequence; stage?: string }>();

@Input()
get sequence(): Sequence | undefined {
get sequence(): ISequence | undefined {
return this._sequence;
}
set sequence(sequence: Sequence | undefined) {

set sequence(sequence: ISequence | undefined) {
if (this._sequence !== sequence) {
this._sequence = sequence;
}
Expand All @@ -28,13 +33,14 @@ export class KtbSequenceStateInfoComponent {
get showStages(): boolean {
return this._showStages;
}

set showStages(showStages: boolean) {
if (this._showStages !== showStages) {
this._showStages = showStages;
}
}

getServiceLink(sequence: Sequence): (string | undefined)[] {
getServiceLink(sequence: ISequence): (string | undefined)[] {
return [
'/project',
sequence.project,
Expand All @@ -43,15 +49,15 @@ export class KtbSequenceStateInfoComponent {
'context',
sequence.shkeptncontext,
'stage',
sequence.getLastStage(),
getLastStageName(sequence),
];
}

getSequenceLink(sequence: Sequence): (string | undefined)[] {
return ['/project', sequence.project, 'sequence', sequence.shkeptncontext, 'stage', sequence.getLastStage()];
getSequenceLink(sequence: ISequence): (string | undefined)[] {
return ['/project', sequence.project, 'sequence', sequence.shkeptncontext, 'stage', getLastStageName(sequence)];
}

stageClick(sequence: Sequence, stage: string): void {
stageClick(sequence: ISequence, stage: string): void {
this.stageClicked.emit({ sequence, stage });
}
}
Expand Up @@ -3,18 +3,16 @@
<dt-table [dataSource]="dataSource">
<ng-container dtColumnDef="recentSequence" [dtColumnProportion]="4">
<dt-cell *dtCellDef="let row">
<ng-container *ngIf="row | toType: SequenceClass as sequence">
<ktb-sequence-state-info
[sequence]="sequence"
[showStages]="false"
(stageClicked)="selectSequence($event)"
></ktb-sequence-state-info>
</ng-container>
<ktb-sequence-state-info
[sequence]="toSequence(row)"
[showStages]="false"
(stageClicked)="selectSequence($event)"
></ktb-sequence-state-info>
</dt-cell>
</ng-container>
<ng-container dtColumnDef="recentEvaluation" dtColumnAlign="number" [dtColumnProportion]="2">
<dt-cell *dtCellDef="let row">
<ng-container *ngIf="row | toType: SequenceClass as sequence">
<ng-container *ngIf="toSequence(row) as sequence">
<p class="m-0 small" [textContent]="sequence.time | toDate | amCalendar: dateUtil.getCalendarFormats()"></p>
</ng-container>
</dt-cell>
Expand Down
@@ -1,8 +1,9 @@
import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core';
import { DtTableDataSource } from '@dynatrace/barista-components/table';
import { DateUtil } from '../../_utils/date.utils';
import { Sequence } from '../../_models/sequence';
import { Router } from '@angular/router';
import { ISequence } from '../../../../shared/interfaces/sequence';
import { getLastStageName } from '../../_models/sequence';

@Component({
selector: 'ktb-sequence-state-list',
Expand All @@ -13,16 +14,15 @@ import { Router } from '@angular/router';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class KtbSequenceStateListComponent {
private _sequenceStates: Sequence[] = [];
public dataSource: DtTableDataSource<Sequence> = new DtTableDataSource();
public SequenceClass = Sequence;
private _sequenceStates: ISequence[] = [];
public dataSource: DtTableDataSource<ISequence> = new DtTableDataSource();

@Input()
get sequenceStates(): Sequence[] {
get sequenceStates(): ISequence[] {
return this._sequenceStates;
}

set sequenceStates(value: Sequence[]) {
set sequenceStates(value: ISequence[]) {
if (this._sequenceStates !== value) {
this._sequenceStates = value;
this.updateDataSource();
Expand All @@ -35,8 +35,8 @@ export class KtbSequenceStateListComponent {
this.dataSource = new DtTableDataSource(this.sequenceStates);
}

selectSequence(event: { sequence: Sequence; stage?: string }): void {
const stage = event.stage || event.sequence.getStages().pop();
selectSequence(event: { sequence: ISequence; stage?: string }): void {
const stage = event.stage || getLastStageName(event.sequence);
this.router.navigate([
'/project',
event.sequence.project,
Expand All @@ -45,4 +45,8 @@ export class KtbSequenceStateListComponent {
...(stage ? ['stage', stage] : []),
]);
}

toSequence(value: unknown): ISequence {
return value as ISequence;
}
}
7 changes: 0 additions & 7 deletions bridge/client/app/_interfaces/project-result.ts

This file was deleted.

2 changes: 1 addition & 1 deletion bridge/client/app/_models/deployment.spec.ts
Expand Up @@ -19,7 +19,7 @@ import {
SubSequencesWarningMock,
UpdatedDeploymentMock,
} from '../_services/_mockData/deployments.mock';
import { SequenceState } from '../../../shared/models/sequence';
import { SequenceState } from '../../../shared/interfaces/sequence';

describe('Deployment', () => {
it('should correctly create new class', () => {
Expand Down
2 changes: 1 addition & 1 deletion bridge/client/app/_models/deployment.ts
@@ -1,7 +1,7 @@
import { Deployment as dp, IStageDeployment, SubSequence } from '../../../shared/interfaces/deployment';
import { EvaluationResult } from '../../../shared/interfaces/evaluation-result';
import { Trace } from './trace';
import { SequenceState } from '../../../shared/models/sequence';
import { SequenceState } from '../../../shared/interfaces/sequence';
import { ResultTypes } from '../../../shared/models/result-types';
import { Sequence } from './sequence';
import { ServiceRemediationInformation } from './service-remediation-information';
Expand Down

0 comments on commit 2cbbc2d

Please sign in to comment.