Add dashboard prototype

This commit is contained in:
Jakob Fahr 2020-06-29 19:31:11 +02:00
parent bb50b6c6cd
commit e5a5c1bcb2
No known key found for this signature in database
GPG Key ID: 8873416D8E4CEF6B
7 changed files with 13668 additions and 13442 deletions

26911
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,7 @@
"@angular/router": "~9.1.9",
"@ng-bootstrap/ng-bootstrap": "^6.0.0",
"bootstrap": "^4.4.0",
"chart.js": "^2.9.3",
"rxjs": "~6.5.4",
"tslib": "^1.10.0",
"zone.js": "~0.10.2"

View File

@ -3,11 +3,13 @@ import { Routes, RouterModule } from '@angular/router';
import { TaskListComponent } from './task-list/task-list.component';
import { UserstoryListComponent } from './userstory-list/userstory-list.component';
import { DashboardComponent } from './dashboard/dashboard.component';
const routes: Routes = [
{ path: 'tasks', component: TaskListComponent },
{ path: 'userstories', component: UserstoryListComponent },
{ path: 'dashboard', component: DashboardComponent },
{ path: '', redirectTo: '/tasks', pathMatch: 'full' },
];

View File

@ -11,7 +11,8 @@ import { TaskListComponent } from './task-list/task-list.component';
import { TaskFormComponent } from './task-form/task-form.component';
import { UserstoryListComponent } from './userstory-list/userstory-list.component';
import { UserstoryFormComponent } from './userstory-form/userstory-form.component';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { DashboardComponent } from './dashboard/dashboard.component';
@NgModule({
declarations: [
@ -19,7 +20,8 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
TaskListComponent,
TaskFormComponent,
UserstoryListComponent,
UserstoryFormComponent
UserstoryFormComponent,
DashboardComponent
],
imports: [
BrowserModule,

View File

@ -0,0 +1,3 @@
.text-2em {
font-size: 2rem;
}

View File

@ -0,0 +1,60 @@
<div class="container-fluid">
<div class="row px-3 py-2">
<h1>Dashboard</h1>
</div>
<div class="row px-3 py-2">
<h2>Current sprint</h2>
</div>
<div class="row">
<div class="p-3 xl-col-6 lg-col-6 md-col-12 sm-col-12 xs-col-12">
<div class="card">
<div class="card-header">
Userstories
</div>
<div class="card-body">
<canvas id="done-stories-chart"></canvas>
</div>
</div>
</div>
<div class="p-3 xl-col-6 lg-col-6 md-col-12 sm-col-12 xs-col-12">
<div class="card-deck">
<div
class="card"
[class.border-danger]="getSprintUrgency() == 0"
[class.border-warning]="getSprintUrgency() == 1"
[class.border-success]="getSprintUrgency() == 2"
*ngIf="getRemainingDaysInSprint() !== undefined"
>
<div class="card-header">
Days remaining
</div>
<div class="card-body text-center">
<span class="text-2em">
{{getRemainingDaysInSprint()}}
</span>
</div>
</div>
<div class="card" *ngFor="let status of usedStatus">
<div class="card-header">
Userstories: {{status.title}}
</div>
<div class="card-body text-center">
<span class="text-2em">
{{getNumberOfUserstoriesByStatus(status)}}
</span>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,127 @@
import {Component, OnInit} from '@angular/core';
import Chart from 'chart.js';
import {BackendService, ScrumStatus, ScrumUser, ScrumUserstory, ScrumSprint} from '../services/backend.service';
@Component({
selector: 'app-dashboard',
templateUrl: 'dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
/**
* Returns the status that are used by at least one userstory.
*/
private get usedStatus(): ScrumStatus[] {
return this.status.filter(s => this.userstories.find(us => us.status === s.id) !== undefined);
}
private status: ScrumStatus[];
private userstories: ScrumUserstory[];
private sprints: ScrumSprint[];
constructor(private backendService: BackendService) {
// backendService.getUserstories().subscribe(response => {
// if (response.status > 399) {
// alert('Fehler');
// } else {
// this.userstories.push(...response.body);
// }
// });
// backendService.getAllStatus().subscribe(response => {
// if (response.status > 399) {
// alert('Fehler');
// } else {
// this.status.push(...response.body);
// }
// });
// backendService.getSprints().subscribe(response => {
// if (response.status > 399) {
// alert('Fehler');
// } else {
// this.sprints.push(...response.body);
// }
// });
this.status = [
{id: 0, title: "In progress", description:""},
{id: 1, title: "Done", description:""},
];
this.userstories = [
{status: 0, title:""},
{status: 0, title:""},
{status: 0, title:""},
{status: 1, title:""},
{status: 1, title:""},
];
this.sprints = [
{description:"", title:"", project: 0, startDate: new Date(2020, 5, 22), endDate: new Date(2020, 5, 28)},
{description:"", title:"", project: 0, startDate: new Date(2020, 5, 29), endDate: new Date(2020, 6, 5)},
]
}
ngOnInit(): void {
// @ts-ignore
const context = document.getElementById('done-stories-chart').getContext('2d');
const chart = new Chart(context, {
type: 'pie',
data: {
labels: this.usedStatus.map(s => s.title),
datasets: [{
label: 'Done stories',
data: this.usedStatus.map(s => this.getNumberOfUserstoriesByStatus(s)),
backgroundColor: this.getBackgroundColors(),
}]
}
});
}
private getBackgroundColors(): string[] {
const baseColors = [
'rgb(255, 153, 102)',
'rgb(255, 102, 102)',
'rgb(153, 204, 255)',
'rgb(102, 153, 102)',
'rgb(204, 204, 153)',
'rgb(153, 102, 204)',
'rgb(204, 102, 102)',
'rgb(255, 204, 153)',
'rgb(153, 102, 255)',
'rgb(204, 204, 204)',
'rgb(102, 255, 204)',
'rgb(102, 153, 255)',
'rgb(153, 102, 153)',
'rgb(204, 204, 255)',
];
const colors = [];
while (colors.length < this.usedStatus.length) {
colors.push(...baseColors);
}
return colors;
}
public getNumberOfUserstoriesByStatus(status: ScrumStatus): number {
return this.userstories.filter(us => us.status === status.id).length;
}
public getRemainingDaysInSprint(): number {
const now = new Date();
const currentSprint = this.sprints.find(s => s.endDate > now && s.startDate < now);
if (currentSprint === undefined) {
return undefined;
}
const daysDelta = Math.floor((currentSprint.endDate.getTime() - now.getTime()) / 86400000);
return daysDelta;
}
public getSprintUrgency(): number {
const now = new Date();
const currentSprint = this.sprints.find(s => s.endDate > now && s.startDate < now);
if (currentSprint === undefined) {
return undefined;
}
const deltaFromNow = currentSprint.endDate.getTime() - now.getTime();
const deltaFromStart = currentSprint.endDate.getTime() - currentSprint.startDate.getTime();
return Math.floor(3 * deltaFromNow / deltaFromStart);
}
}