Merge remote-tracking branch 'origin/feature/dashboard' into preview
This commit is contained in:
commit
2398a642ae
26911
package-lock.json
generated
26911
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -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"
|
||||
|
@ -4,11 +4,13 @@ import { Routes, RouterModule } from '@angular/router';
|
||||
import {UserstoryTableComponent} from './userstory-table/userstory-table.component';
|
||||
import {TaskTableComponent} from './task-table/task-table.component';
|
||||
import { SprintTableComponent } from './sprint-table/sprint-table.component';
|
||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'tasks', component: TaskTableComponent },
|
||||
{ path: 'userstories', component: UserstoryTableComponent },
|
||||
{ path: 'sprints', component: SprintTableComponent },
|
||||
{ path: 'dashboard', component: DashboardComponent },
|
||||
{ path: '', redirectTo: '/tasks', pathMatch: 'full' },
|
||||
];
|
||||
|
||||
|
@ -14,6 +14,7 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { UserstoryTableComponent } from './userstory-table/userstory-table.component';
|
||||
import { TaskTableComponent } from './task-table/task-table.component';
|
||||
import { SprintTableComponent } from './sprint-table/sprint-table.component';
|
||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@ -24,7 +25,8 @@ import { SprintTableComponent } from './sprint-table/sprint-table.component';
|
||||
UserstoryFormComponent,
|
||||
UserstoryTableComponent,
|
||||
SprintFormComponent,
|
||||
SprintTableComponent
|
||||
SprintTableComponent,
|
||||
DashboardComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
3
src/app/dashboard/dashboard.component.css
Normal file
3
src/app/dashboard/dashboard.component.css
Normal file
@ -0,0 +1,3 @@
|
||||
.text-2em {
|
||||
font-size: 2rem;
|
||||
}
|
60
src/app/dashboard/dashboard.component.html
Normal file
60
src/app/dashboard/dashboard.component.html
Normal 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>
|
127
src/app/dashboard/dashboard.component.ts
Normal file
127
src/app/dashboard/dashboard.component.ts
Normal 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);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user