Merge feature/dashboard
This commit is contained in:
parent
f5dae215a4
commit
4ca662c819
1767
package-lock.json
generated
1767
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -23,6 +23,7 @@
|
|||||||
"@ng-bootstrap/ng-bootstrap": "^6.0.0",
|
"@ng-bootstrap/ng-bootstrap": "^6.0.0",
|
||||||
"bootstrap": "^4.4.0",
|
"bootstrap": "^4.4.0",
|
||||||
"chart.js": "^2.9.3",
|
"chart.js": "^2.9.3",
|
||||||
|
"component": "^1.1.0",
|
||||||
"rxjs": "~6.5.4",
|
"rxjs": "~6.5.4",
|
||||||
"tslib": "^1.10.0",
|
"tslib": "^1.10.0",
|
||||||
"zone.js": "~0.10.2"
|
"zone.js": "~0.10.2"
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { Routes, RouterModule } from '@angular/router';
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||||
import { UserstoryTableComponent } from './userstory-table/userstory-table.component';
|
import { UserstoryTableComponent } from './userstory-table/userstory-table.component';
|
||||||
import { TaskTableComponent } from './task-table/task-table.component';
|
import { TaskTableComponent } from './task-table/task-table.component';
|
||||||
import { SprintTableComponent } from './sprint-table/sprint-table.component';
|
import { SprintTableComponent } from './sprint-table/sprint-table.component';
|
||||||
// import { DashboardComponent } from './dashboard/dashboard.component';
|
// import { DashboardComponent } from './dashboard/dashboard.component';
|
||||||
|
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{ path: 'tasks', component: TaskTableComponent },
|
{ path: 'tasks', component: TaskTableComponent },
|
||||||
{ path: 'userstories', component: UserstoryTableComponent },
|
{ path: 'userstories', component: UserstoryTableComponent },
|
||||||
|
{ path: 'dashboard', component: DashboardComponent },
|
||||||
{ path: 'sprints', component: SprintTableComponent },
|
{ path: 'sprints', component: SprintTableComponent },
|
||||||
// { path: 'dashboard', component: DashboardComponent },
|
|
||||||
{ path: '', redirectTo: '/tasks', pathMatch: 'full' },
|
{ path: '', redirectTo: '/tasks', pathMatch: 'full' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -14,7 +14,8 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
|||||||
import { UserstoryTableComponent } from './userstory-table/userstory-table.component';
|
import { UserstoryTableComponent } from './userstory-table/userstory-table.component';
|
||||||
import { TaskTableComponent } from './task-table/task-table.component';
|
import { TaskTableComponent } from './task-table/task-table.component';
|
||||||
import { SprintTableComponent } from './sprint-table/sprint-table.component';
|
import { SprintTableComponent } from './sprint-table/sprint-table.component';
|
||||||
// import { DashboardComponent } from './dashboard/dashboard.component';
|
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||||
|
import { UserstoryInnerTableComponent } from './userstory-inner-table/userstory-inner-table.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -26,7 +27,8 @@ import { SprintTableComponent } from './sprint-table/sprint-table.component';
|
|||||||
UserstoryTableComponent,
|
UserstoryTableComponent,
|
||||||
SprintFormComponent,
|
SprintFormComponent,
|
||||||
SprintTableComponent,
|
SprintTableComponent,
|
||||||
// DashboardComponent,
|
DashboardComponent,
|
||||||
|
UserstoryInnerTableComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
/* .text-2em {
|
.text-large {
|
||||||
font-size: 2rem;
|
font-size: 1.2rem;
|
||||||
} */
|
}
|
||||||
|
|
||||||
|
.text-very-large {
|
||||||
|
font-size: 2.4rem;
|
||||||
|
}
|
||||||
|
@ -1,60 +1,98 @@
|
|||||||
{% comment %} <div class="container-fluid">
|
<div class="mx-5 my-3">
|
||||||
|
|
||||||
<div class="row px-3 py-2">
|
<div class="row px-3 py-2">
|
||||||
<h1>Dashboard</h1>
|
<h1>Dashboard</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row px-3 py-2">
|
<div class="row px-3 py-2">
|
||||||
<h2>Current sprint</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
<ng-container *ngIf="selectedSprint === undefined">
|
||||||
|
<h3 class="mr-3 text-primary">Alle Userstories</h3>
|
||||||
|
<a [routerLink]="['sprints']">Lege einen Sprint an, um Userstories zu organisieren.</a>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
<div class="p-3 xl-col-6 lg-col-6 md-col-12 sm-col-12 xs-col-12">
|
<ng-container *ngIf="selectedSprint !== undefined">
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">
|
<h3 class="mr-3 text-primary" *ngIf="selectedSprint === currentSprint">Aktueller Sprint:</h3>
|
||||||
|
<h3 class="mr-3 text-primary" *ngIf="selectedSprint !== currentSprint">Sprint:</h3>
|
||||||
|
<h3 class="mr-3 custom-text-secondary">{{selectedSprint.title}}</h3>
|
||||||
|
<h3 class="mr-3">{{toDateString(selectedSprint.startDate)}} - {{toDateString(selectedSprint.endDate)}}</h3>
|
||||||
|
|
||||||
|
<label class="mr-3">
|
||||||
|
<select class="select custom-select custom-text-secondary" [(ngModel)]="selectedSprint">
|
||||||
|
<option class="bg-secondary text-dark" [ngValue]="currentSprint">
|
||||||
|
{{currentSprint.title}} (aktuell)
|
||||||
|
</option>
|
||||||
|
<option value="" disabled="disabled">─────────────────────────</option>
|
||||||
|
<option class="text-dark" *ngFor="let sprint of sprints" [ngValue]="sprint">
|
||||||
|
<ng-container *ngIf="sprint === currentSprint">
|
||||||
|
{{sprint.title}} (aktuell)
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngIf="sprint !== currentSprint">
|
||||||
|
{{sprint.title}} ({{toDateString(sprint.startDate)}} - {{toDateString(sprint.endDate)}})
|
||||||
|
</ng-container>
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<span class="mr-5"></span>
|
||||||
|
<h3
|
||||||
|
*ngIf="selectedSprint === currentSprint"
|
||||||
|
class="mr-3 custom-text-secondary"
|
||||||
|
[class.text-success]="getSprintUrgency() === 2"
|
||||||
|
[class.text-warning]="getSprintUrgency() === 1"
|
||||||
|
[class.text-danger]="getSprintUrgency() === 0"
|
||||||
|
>
|
||||||
|
Verbleibende Tage: {{getRemainingDaysInSprint()}}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="p-3 col-12 col-xl-6 col-lg-6 col-md-12 col-sm-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="text-large">
|
||||||
Userstories
|
Userstories
|
||||||
</div>
|
</span>
|
||||||
<div class="card-body">
|
|
||||||
<canvas id="done-stories-chart"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="card-body">
|
||||||
|
<div *ngIf="selectedSprint !== undefined && usedStatus.length === 0">
|
||||||
<div class="p-3 xl-col-6 lg-col-6 md-col-12 sm-col-12 xs-col-12">
|
Zum Sprint "{{selectedSprint.title}}" sind aktuell keine Userstories vorhanden.
|
||||||
<div class="card-deck">
|
</div>
|
||||||
|
<canvas id="done-stories-chart"></canvas>
|
||||||
<div
|
</div>
|
||||||
class="card"
|
</div>
|
||||||
[class.border-danger]="getSprintUrgency() == 0"
|
<div class="card-deck">
|
||||||
[class.border-warning]="getSprintUrgency() == 1"
|
<div
|
||||||
[class.border-success]="getSprintUrgency() == 2"
|
class="card text-center"
|
||||||
*ngIf="getRemainingDaysInSprint() !== undefined"
|
*ngFor="let status of usedStatus"
|
||||||
>
|
>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
Days remaining
|
<span class="text-large">
|
||||||
|
{{status.title}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<span class="text-very-large">
|
||||||
|
<b>{{getNumberOfUserstoriesByStatus(status)}}</b>
|
||||||
|
</span>
|
||||||
</div>
|
</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>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div> {% endcomment %}
|
<div class="p-3 col-12 col-xl-6 col-lg-6 col-md-12 col-sm-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<app-userstory-inner-table [items]="selectedSprintUserstories"></app-userstory-inner-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
@ -1,159 +1,140 @@
|
|||||||
// import { Component, OnInit } from '@angular/core';
|
import {Component, OnChanges} from '@angular/core';
|
||||||
// // import Chart from 'chart.js';
|
import {forkJoin} from 'rxjs';
|
||||||
// import {
|
import Chart from 'chart.js';
|
||||||
// BackendService,
|
import {BackendService, ScrumSprint, ScrumStatus, ScrumUserstory} from '../services/backend.service';
|
||||||
// ScrumStatus,
|
|
||||||
// ScrumUser,
|
|
||||||
// ScrumUserstory,
|
|
||||||
// ScrumSprint,
|
|
||||||
// } from '../services/backend.service';
|
|
||||||
|
|
||||||
// @Component({
|
@Component({
|
||||||
// selector: 'app-dashboard',
|
selector: 'app-dashboard',
|
||||||
// templateUrl: 'dashboard.component.html',
|
templateUrl: 'dashboard.component.html',
|
||||||
// styleUrls: ['./dashboard.component.css'],
|
styleUrls: ['./dashboard.component.css']
|
||||||
// })
|
})
|
||||||
// export class DashboardComponent implements OnInit {
|
export class DashboardComponent {
|
||||||
// /**
|
/**
|
||||||
// * Returns the status that are used by at least one userstory.
|
* Returns the status that are used by at least one userstory.
|
||||||
// */
|
*/
|
||||||
// public get usedStatus(): ScrumStatus[] {
|
public get usedStatus(): ScrumStatus[] {
|
||||||
// return this.status.filter(
|
return this.status.filter(s => this.selectedSprintUserstories.find(us => us.statusid === s.id) !== undefined);
|
||||||
// (s) => this.userstories.find((us) => us.statusid === s.id) !== undefined
|
}
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private status: ScrumStatus[];
|
public get selectedSprintUserstories(): ScrumUserstory[] {
|
||||||
// private userstories: ScrumUserstory[];
|
if (this.selectedSprint === undefined) {
|
||||||
// private sprints: ScrumSprint[];
|
return this.userstories;
|
||||||
|
}
|
||||||
|
return this.userstories.filter(us => us.sprintid === this.selectedSprint.id);
|
||||||
|
}
|
||||||
|
|
||||||
// constructor(private backendService: BackendService) {
|
public get currentSprint(): ScrumSprint {
|
||||||
// // backendService.getUserstories().subscribe(response => {
|
const now = Date.now();
|
||||||
// // if (response.status > 399) {
|
return this.sprints.find(s => Date.parse(s.startDate) < now && Date.parse(s.endDate) > now);
|
||||||
// // 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 = [
|
private _selectedSprint: ScrumSprint;
|
||||||
// { id: 0, title: 'In progress', description: '' },
|
public get selectedSprint(): ScrumSprint {
|
||||||
// { id: 1, title: 'Done', description: '' },
|
if (this._selectedSprint === undefined) {
|
||||||
// ];
|
if (this.currentSprint === undefined) {
|
||||||
// this.userstories = [
|
return this.sprints[0];
|
||||||
// { statusid: 0, title: '' },
|
}
|
||||||
// { statusid: 0, title: '' },
|
return this.currentSprint;
|
||||||
// { statusid: 0, title: '' },
|
}
|
||||||
// { statusid: 1, title: '' },
|
return this._selectedSprint;
|
||||||
// { statusid: 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 {
|
public set selectedSprint(value) {
|
||||||
// // @ts-ignore
|
this._selectedSprint = value;
|
||||||
// const context = document
|
this.createChart();
|
||||||
// .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[] {
|
public status: ScrumStatus[] = [];
|
||||||
// const baseColors = [
|
public userstories: ScrumUserstory[] = [];
|
||||||
// 'rgb(255, 153, 102)',
|
public sprints: ScrumSprint[] = [];
|
||||||
// 'rgb(255, 102, 102)',
|
|
||||||
// 'rgb(153, 204, 255)',
|
public chart: Chart;
|
||||||
// 'rgb(102, 153, 102)',
|
|
||||||
// 'rgb(204, 204, 153)',
|
constructor(private backendService: BackendService) {
|
||||||
// 'rgb(153, 102, 204)',
|
// download userstories, status and sprints and update
|
||||||
// 'rgb(204, 102, 102)',
|
// the chart whenever a new response is there
|
||||||
// 'rgb(255, 204, 153)',
|
forkJoin([backendService.getUserstories(), backendService.getAllStatus(), backendService.getSprints()])
|
||||||
// 'rgb(153, 102, 255)',
|
.subscribe(results => {
|
||||||
// 'rgb(204, 204, 204)',
|
const [userstoryResponse, statusResponse, sprintResponse] = results;
|
||||||
// 'rgb(102, 255, 204)',
|
if (userstoryResponse.status > 399 || statusResponse.status > 399 || sprintResponse.status > 399) {
|
||||||
// 'rgb(102, 153, 255)',
|
alert('Fehler');
|
||||||
// 'rgb(153, 102, 153)',
|
} else {
|
||||||
// 'rgb(204, 204, 255)',
|
this.userstories.push(...userstoryResponse.body);
|
||||||
// ];
|
this.status.push(...statusResponse.body);
|
||||||
// const colors = [];
|
this.sprints.push(...sprintResponse.body);
|
||||||
// while (colors.length < this.usedStatus.length) {
|
this.createChart();
|
||||||
// colors.push(...baseColors);
|
}
|
||||||
// }
|
});
|
||||||
// return colors;
|
}
|
||||||
// }
|
|
||||||
|
/**
|
||||||
|
* Returns the date in the following format: 1.7.2020
|
||||||
|
*/
|
||||||
|
public toDateString(isoFormatString) {
|
||||||
|
const date = new Date(isoFormatString);
|
||||||
|
return `${date.getDate()}.${date.getMonth() + 1}.${date.getFullYear()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private createChart() {
|
||||||
|
// @ts-ignore
|
||||||
|
const context = document.getElementById('done-stories-chart').getContext('2d');
|
||||||
|
|
||||||
|
if (this.usedStatus.length === 0) {
|
||||||
|
this.chart.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
this.chart = new Chart(context, {
|
||||||
|
type: 'pie',
|
||||||
|
data: {
|
||||||
|
labels: this.usedStatus.map(s => s.title),
|
||||||
|
datasets: [{
|
||||||
|
data: this.usedStatus.map(s => this.getNumberOfUserstoriesByStatus(s)),
|
||||||
|
backgroundColor: this.getBackgroundColors(),
|
||||||
|
options: {
|
||||||
|
legend: {
|
||||||
|
display: true,
|
||||||
|
position: 'right',
|
||||||
|
labels: {
|
||||||
|
fontColor: 'rgba(255, 255, 255, 0.8)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.chart.update();
|
||||||
|
this.chart.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// public getNumberOfUserstoriesByStatus(status: ScrumStatus): number {
|
// public getNumberOfUserstoriesByStatus(status: ScrumStatus): number {
|
||||||
// return this.userstories.filter((us) => us.statusid === status.id).length;
|
// return this.userstories.filter((us) => us.statusid === status.id).length;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// public getRemainingDaysInSprint(): number {
|
public getNumberOfUserstoriesByStatus(status: ScrumStatus): number {
|
||||||
// const now = new Date();
|
return this.selectedSprintUserstories.filter(us => us.statusid === status.id).length;
|
||||||
// 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 {
|
public getRemainingDaysInSprint(): number {
|
||||||
// const now = new Date();
|
if (this.selectedSprint === undefined) {
|
||||||
// const currentSprint = this.sprints.find(
|
return undefined;
|
||||||
// (s) => s.endDate > now && s.startDate < now
|
}
|
||||||
// );
|
return Math.floor((Date.parse(this.selectedSprint.endDate) - Date.now()) / 86400000);
|
||||||
// if (currentSprint === undefined) {
|
}
|
||||||
// return undefined;
|
|
||||||
// }
|
/**
|
||||||
// const deltaFromNow = currentSprint.endDate.getTime() - now.getTime();
|
* Returns the "urgency" of the current sprint (ie what percentage of the sprint is remaining)
|
||||||
// const deltaFromStart =
|
* as an integer from 0 (most urgent) to 2 (least urgent).
|
||||||
// currentSprint.endDate.getTime() - currentSprint.startDate.getTime();
|
*/
|
||||||
// return Math.floor((3 * deltaFromNow) / deltaFromStart);
|
public getSprintUrgency(): number {
|
||||||
// }
|
const now = Date.now();
|
||||||
// }
|
const sprint = this.selectedSprint;
|
||||||
|
if (sprint === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const deltaFromNow = Date.parse(sprint.endDate) - now;
|
||||||
|
const deltaFromStart = Date.parse(sprint.endDate) - Date.parse(sprint.startDate);
|
||||||
|
return Math.floor(3 * deltaFromNow / deltaFromStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -246,6 +246,7 @@ export interface ScrumUserstory {
|
|||||||
projectid?: number;
|
projectid?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
export interface ScrumSprint {
|
export interface ScrumSprint {
|
||||||
id?: number;
|
id?: number;
|
||||||
title: string;
|
title: string;
|
||||||
@ -253,6 +254,15 @@ export interface ScrumSprint {
|
|||||||
startDate: Date;
|
startDate: Date;
|
||||||
endDate: Date;
|
endDate: Date;
|
||||||
project?: number;
|
project?: number;
|
||||||
|
=======
|
||||||
|
export interface ScrumSprint{
|
||||||
|
id?: number;
|
||||||
|
title: string;
|
||||||
|
description?: string;
|
||||||
|
startDate: string;
|
||||||
|
endDate: string;
|
||||||
|
project: number;
|
||||||
|
>>>>>>> feature/dashboard
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ScrumCategory {
|
export interface ScrumCategory {
|
||||||
|
@ -14,7 +14,7 @@ import { getNumberForPriority } from '../services/sorting.service';
|
|||||||
import { NONE_TYPE } from '@angular/compiler';
|
import { NONE_TYPE } from '@angular/compiler';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-userstory-table',
|
selector: 'app-task-table',
|
||||||
templateUrl: './task-table.component.html',
|
templateUrl: './task-table.component.html',
|
||||||
styleUrls: ['./task-table.component.css'],
|
styleUrls: ['./task-table.component.css'],
|
||||||
})
|
})
|
||||||
|
@ -0,0 +1,90 @@
|
|||||||
|
<button class="btn btn-secondary my-3" (click)="openUserstoryForm()">Neue Userstory</button>
|
||||||
|
|
||||||
|
<table class="table">
|
||||||
|
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th (click)="sortById()" class="sortable">
|
||||||
|
<span>ID</span>
|
||||||
|
<span *ngIf="sortBy === 'id'" class="pl-3">
|
||||||
|
<span *ngIf="sortDescending"><i class="fa fa-sort-up"></i></span>
|
||||||
|
<span *ngIf="sortDescending === false"><i class="fa fa-sort-down"></i></span>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th (click)="sortByTitle()" class="sortable">
|
||||||
|
<span>Titel</span>
|
||||||
|
<span *ngIf="sortBy === 'title'" class="pl-3">
|
||||||
|
<span *ngIf="sortDescending"><i class="fa fa-sort-up"></i></span>
|
||||||
|
<span *ngIf="sortDescending === false"><i class="fa fa-sort-down"></i></span>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th (click)="sortByTasks()" class="sortable">
|
||||||
|
<span>Tasks</span>
|
||||||
|
<span *ngIf="sortBy === 'tasks'" class="pl-3">
|
||||||
|
<span *ngIf="sortDescending"><i class="fa fa-sort-up"></i></span>
|
||||||
|
<span *ngIf="sortDescending === false"><i class="fa fa-sort-down"></i></span>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th (click)="sortByStatus()" class="sortable">
|
||||||
|
<span>Status</span>
|
||||||
|
<span *ngIf="sortBy === 'statusid'" class="pl-3">
|
||||||
|
<span *ngIf="sortDescending"><i class="fa fa-sort-up"></i></span>
|
||||||
|
<span *ngIf="sortDescending === false"><i class="fa fa-sort-down"></i></span>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th (click)="sortByPrio()" class="sortable">
|
||||||
|
<span>Priorität</span>
|
||||||
|
<label class="pl-3" (click)="$event.stopPropagation()">
|
||||||
|
<select [(ngModel)]="filterPriority">
|
||||||
|
<option [ngValue]="null" selected></option>
|
||||||
|
<option *ngFor="let p of getAllPriorities()" [ngValue]="p">{{p}}</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<span *ngIf="sortBy === 'priority'" class="pl-3">
|
||||||
|
<span *ngIf="sortDescending"><i class="fa fa-sort-up"></i></span>
|
||||||
|
<span *ngIf="sortDescending === false"><i class="fa fa-sort-down"></i></span>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th (click)="sortByCategory()" class="sortable">
|
||||||
|
<span>Category</span>
|
||||||
|
<span *ngIf="sortBy === 'categoryid'" class="pl-3">
|
||||||
|
<span *ngIf="sortDescending"><i class="fa fa-sort-up"></i></span>
|
||||||
|
<span *ngIf="sortDescending === false"><i class="fa fa-sort-down"></i></span>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let userstory of filteredItems" [class.table-info]="userstory.id === highlightId">
|
||||||
|
<td>{{userstory.id}}</td>
|
||||||
|
<td>{{userstory.title}}</td>
|
||||||
|
<td>
|
||||||
|
<a [routerLink]="['/tasks', {userstoryId: userstory.id}]">
|
||||||
|
{{getNumberOfTasks(userstory)}} Tasks
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a [routerLink]="['/status', {id: userstory.statusid}]">
|
||||||
|
{{getStatusTitleById(userstory.statusid)}}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>{{userstory.priority}}</td>
|
||||||
|
<td>
|
||||||
|
<a [routerLink]="['/categories', {id: userstory.categoryid}]">
|
||||||
|
{{getCategoryTitleById(userstory.categoryid)}}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" rel="tooltip" (click)="openUserstoryForm(userstory)" class="btn btn-success btn-sm btn-icon">
|
||||||
|
<i class="fa fa-pencil-alt"></i>
|
||||||
|
</button>
|
||||||
|
<button type="button" rel="tooltip" (click)="deleteUserstory(userstory)" class="btn btn-danger btn-sm btn-icon">
|
||||||
|
<i class="fa fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
|
||||||
|
</table>
|
143
src/app/userstory-inner-table/userstory-inner-table.component.ts
Normal file
143
src/app/userstory-inner-table/userstory-inner-table.component.ts
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
import {
|
||||||
|
BackendService,
|
||||||
|
ScrumTask,
|
||||||
|
ScrumUserstory,
|
||||||
|
ScrumStatus,
|
||||||
|
ScrumCategory,
|
||||||
|
} from '../services/backend.service';
|
||||||
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import { TableComponentBase } from '../services/table-component.base';
|
||||||
|
import { getNumberForPriority } from '../services/sorting.service';
|
||||||
|
import { UserstoryFormComponent } from '../userstory-form/userstory-form.component';
|
||||||
|
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-userstory-inner-table',
|
||||||
|
templateUrl: './userstory-inner-table.component.html',
|
||||||
|
styleUrls: ['./userstory-inner-table.component.css']
|
||||||
|
})
|
||||||
|
export class UserstoryInnerTableComponent extends TableComponentBase<ScrumUserstory> {
|
||||||
|
public tasks: ScrumTask[] = [];
|
||||||
|
public filterPriority: string | null = null;
|
||||||
|
public highlightId: number;
|
||||||
|
public status: ScrumStatus[] = [];
|
||||||
|
public categories: ScrumCategory[] = [];
|
||||||
|
|
||||||
|
@Input() public items: ScrumUserstory[] = [];
|
||||||
|
|
||||||
|
public get filteredItems() {
|
||||||
|
return this.items.filter(
|
||||||
|
(task) =>
|
||||||
|
this.filterPriority === null || task.priority === this.filterPriority
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private backendService: BackendService,
|
||||||
|
private modalService: NgbModal,
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private router: Router
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.applyFilterParameters(this.route.snapshot.paramMap);
|
||||||
|
this.route.paramMap.subscribe((map) => this.applyFilterParameters(map));
|
||||||
|
|
||||||
|
backendService.getTasks().subscribe((response) => {
|
||||||
|
if (response.status > 399) {
|
||||||
|
alert('Fehler');
|
||||||
|
} else {
|
||||||
|
this.tasks.push(...response.body);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
backendService.getAllStatus().subscribe((response) => {
|
||||||
|
if (response.status > 399) {
|
||||||
|
alert('Fehler');
|
||||||
|
} else {
|
||||||
|
this.status.push(...response.body);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
backendService.getCategories().subscribe((response) => {
|
||||||
|
if (response.status > 399) {
|
||||||
|
alert('Fehler');
|
||||||
|
} else {
|
||||||
|
this.categories.push(...response.body);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private applyFilterParameters(params: ParamMap) {
|
||||||
|
if (params.has('id')) {
|
||||||
|
this.highlightId = parseInt(params.get('id'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public deleteUserstory(userstory: ScrumUserstory) {
|
||||||
|
this.backendService.deleteUserstory(userstory).subscribe((response) => {
|
||||||
|
if (response.status > 399) {
|
||||||
|
alert('Fehler');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const index = this.items.indexOf(userstory);
|
||||||
|
if (index !== -1) {
|
||||||
|
this.items.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public openUserstoryForm(editUserstory?: ScrumUserstory) {
|
||||||
|
const modalRef = this.modalService.open(UserstoryFormComponent, {
|
||||||
|
backdrop: 'static',
|
||||||
|
keyboard: true,
|
||||||
|
});
|
||||||
|
if (editUserstory === null) {
|
||||||
|
modalRef.result.then((result) => {
|
||||||
|
this.items.push(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
modalRef.componentInstance.userstory = editUserstory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getNumberOfTasks(userstory: ScrumUserstory) {
|
||||||
|
return this.tasks.filter((t) => t.userstoryid === userstory.id).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public sortById() {
|
||||||
|
this.doNumericSort('id', (us) => us.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public sortByTitle() {
|
||||||
|
this.doStringSort('title', (us) => us.title);
|
||||||
|
}
|
||||||
|
|
||||||
|
public sortByPrio() {
|
||||||
|
this.doNumericSort('priority', (us) => getNumberForPriority(us.priority));
|
||||||
|
}
|
||||||
|
|
||||||
|
public sortByTasks() {
|
||||||
|
this.doNumericSort('tasks', (us) => this.getNumberOfTasks(us));
|
||||||
|
}
|
||||||
|
|
||||||
|
sortByStatus() {
|
||||||
|
this.doNumericSort('statusid', (us) => us.statusid);
|
||||||
|
}
|
||||||
|
sortByCategory() {
|
||||||
|
this.doNumericSort('categoryid', (us) => us.categoryid);
|
||||||
|
}
|
||||||
|
|
||||||
|
getStatusTitleById(id) {
|
||||||
|
var status = this.status.find((x) => x.id === id);
|
||||||
|
if (!status) {
|
||||||
|
return 'N/A';
|
||||||
|
}
|
||||||
|
return status.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCategoryTitleById(id) {
|
||||||
|
var category = this.categories.find((x) => x.id === id);
|
||||||
|
if (!category) {
|
||||||
|
return 'N/A';
|
||||||
|
}
|
||||||
|
return category.title;
|
||||||
|
}
|
||||||
|
}
|
@ -1,106 +1,4 @@
|
|||||||
<div class="container-fluid">
|
<div class="mx-5 my-3">
|
||||||
|
<h3 class="my-1">Userstories</h3>
|
||||||
<h3>Userstories</h3>
|
<app-userstory-inner-table [items]="items"></app-userstory-inner-table>
|
||||||
|
|
||||||
<button class="btn btn-secondary" (click)="openUserstoryForm()">Neue Userstory</button>
|
|
||||||
|
|
||||||
<table class="table">
|
|
||||||
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th (click)="sortById()" class="sortable">
|
|
||||||
<span>ID</span>
|
|
||||||
<span>
|
|
||||||
<span *ngIf="sortBy != 'id'"><i class="fa fa-sort fa-lg"></i></span>
|
|
||||||
<span *ngIf="sortDescending && sortBy === 'id'"><i class="fa fa-sort-up fa-lg"></i></span>
|
|
||||||
<span *ngIf="sortDescending === false && sortBy === 'id'"><i class="fa fa-sort-down fa-lg"></i></span>
|
|
||||||
</span>
|
|
||||||
</th>
|
|
||||||
<th (click)="sortByTitle()" class="sortable">
|
|
||||||
<span>Titel</span>
|
|
||||||
<span>
|
|
||||||
<span *ngIf="sortBy != 'title'"><i class="fa fa-sort fa-lg"></i></span>
|
|
||||||
<span *ngIf="sortDescending && sortBy === 'title'"><i class="fa fa-sort-up fa-lg"></i></span>
|
|
||||||
<span *ngIf="sortDescending === false && sortBy === 'title'"><i class="fa fa-sort-down fa-lg"></i></span>
|
|
||||||
</span>
|
|
||||||
</th>
|
|
||||||
<th (click)="sortByTasks()" class="sortable">
|
|
||||||
<span>Tasks</span>
|
|
||||||
<span>
|
|
||||||
<span *ngIf="sortBy != 'tasks'"><i class="fa fa-sort fa-lg"></i></span>
|
|
||||||
<span *ngIf="sortDescending && sortBy === 'tasks'"><i class="fa fa-sort-up fa-lg"></i></span>
|
|
||||||
<span *ngIf="sortDescending === false && sortBy === 'tasks'"><i class="fa fa-sort-down fa-lg"></i></span>
|
|
||||||
</span>
|
|
||||||
</th>
|
|
||||||
<th (click)="sortByStatus()" class="sortable">
|
|
||||||
<span>Status</span>
|
|
||||||
<span>
|
|
||||||
<span *ngIf="sortBy != 'statusid'"><i class="fa fa-sort fa-lg"></i></span>
|
|
||||||
<span *ngIf="sortDescending && sortBy === 'statusid'"><i class="fa fa-sort-up fa-lg"></i></span>
|
|
||||||
<span *ngIf="sortDescending === false && sortBy === 'statusid'"><i class="fa fa-sort-down fa-lg"></i></span>
|
|
||||||
</span>
|
|
||||||
</th>
|
|
||||||
<th class="sortable">
|
|
||||||
<div class="d-inline-block">
|
|
||||||
<div class="d-inline-block">
|
|
||||||
<span (click)="sortByPrio()">Priorität: </span>
|
|
||||||
<div ngbDropdown class="d-inline-block">
|
|
||||||
<span id="dropdownBasic1" ngbDropdownToggle>{{filterPriority || "All"}}</span>
|
|
||||||
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
|
|
||||||
<option ngbDropdownItem (click)="filterPriority=null">All</option>
|
|
||||||
<option ngbDropdownItem *ngFor="let p of getAllPriorities()" (click)="filterPriority=p">{{p}}</option>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<span (click)="sortByPrio()">
|
|
||||||
<span *ngIf="sortBy != 'priority'"><i class="fa fa-sort fa-lg"></i></span>
|
|
||||||
<span *ngIf="sortDescending && sortBy === 'priority'"><i class="fa fa-sort-up fa-lg"></i></span>
|
|
||||||
<span *ngIf="sortDescending === false && sortBy === 'priority'"><i class="fa fa-sort-down fa-lg"></i></span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
<th (click)="sortByCategory()" class="sortable">
|
|
||||||
<span>Category</span>
|
|
||||||
<span>
|
|
||||||
<span *ngIf="sortBy != 'categoryid'"><i class="fa fa-sort fa-lg"></i></span>
|
|
||||||
<span *ngIf="sortDescending && sortBy === 'categoryid'"><i class="fa fa-sort-up fa-lg"></i></span>
|
|
||||||
<span *ngIf="sortDescending === false && sortBy === 'categoryid'"><i class="fa fa-sort-down fa-lg"></i></span>
|
|
||||||
</span>
|
|
||||||
</th>
|
|
||||||
<th></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
|
||||||
<tr *ngFor="let userstory of filteredItems" [class.table-info]="userstory.id === highlightId">
|
|
||||||
<td>{{userstory.id}}</td>
|
|
||||||
<td>{{userstory.title}}</td>
|
|
||||||
<td>
|
|
||||||
<a [routerLink]="['/tasks', {userstoryId: userstory.id}]">
|
|
||||||
{{getNumberOfTasks(userstory)}} Tasks
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a [routerLink]="['/status', {id: userstory.statusid}]">
|
|
||||||
{{getStatusTitleById(userstory.statusid)}}
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>{{userstory.priority}}</td>
|
|
||||||
<td>
|
|
||||||
<a [routerLink]="['/categories', {id: userstory.categoryid}]">
|
|
||||||
{{getCategoryTitleById(userstory.categoryid)}}
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<button type="button" rel="tooltip" (click)="openUserstoryForm(userstory)" class="btn btn-success btn-sm btn-icon">
|
|
||||||
<i class="fa fa-pencil-alt"></i>
|
|
||||||
</button>
|
|
||||||
<button type="button" rel="tooltip" (click)="deleteUserstory(userstory)" class="btn btn-danger btn-sm btn-icon">
|
|
||||||
<i class="fa fa-trash"></i>
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,49 +1,18 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
BackendService,
|
BackendService,
|
||||||
ScrumTask,
|
|
||||||
ScrumUserstory,
|
ScrumUserstory,
|
||||||
ScrumStatus,
|
|
||||||
ScrumCategory,
|
|
||||||
} from '../services/backend.service';
|
} from '../services/backend.service';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
|
||||||
import { TableComponentBase } from '../services/table-component.base';
|
|
||||||
import { getNumberForPriority } from '../services/sorting.service';
|
|
||||||
import { UserstoryFormComponent } from '../userstory-form/userstory-form.component';
|
|
||||||
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-userstory-table',
|
selector: 'app-userstory-table',
|
||||||
templateUrl: './userstory-table.component.html',
|
templateUrl: './userstory-table.component.html',
|
||||||
styleUrls: ['./userstory-table.component.css'],
|
styleUrls: ['./userstory-table.component.css'],
|
||||||
})
|
})
|
||||||
export class UserstoryTableComponent extends TableComponentBase<
|
export class UserstoryTableComponent {
|
||||||
ScrumUserstory
|
public items: ScrumUserstory[] = [];
|
||||||
> {
|
|
||||||
public tasks: ScrumTask[] = [];
|
|
||||||
public filterPriority: string | null = null;
|
|
||||||
public highlightId: number;
|
|
||||||
public status: ScrumStatus[] = [];
|
|
||||||
public categories: ScrumCategory[] = [];
|
|
||||||
|
|
||||||
public get filteredItems() {
|
|
||||||
return this.items.filter(
|
|
||||||
(task) =>
|
|
||||||
this.filterPriority === null || task.priority === this.filterPriority
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private backendService: BackendService,
|
|
||||||
private modalService: NgbModal,
|
|
||||||
private route: ActivatedRoute,
|
|
||||||
private router: Router
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.applyFilterParameters(this.route.snapshot.paramMap);
|
|
||||||
this.route.paramMap.subscribe((map) => this.applyFilterParameters(map));
|
|
||||||
|
|
||||||
|
constructor(private backendService: BackendService) {
|
||||||
backendService.getUserstories().subscribe((response) => {
|
backendService.getUserstories().subscribe((response) => {
|
||||||
if (response.status > 399) {
|
if (response.status > 399) {
|
||||||
alert('Fehler');
|
alert('Fehler');
|
||||||
@ -51,101 +20,5 @@ export class UserstoryTableComponent extends TableComponentBase<
|
|||||||
this.items.push(...response.body);
|
this.items.push(...response.body);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
backendService.getTasks().subscribe((response) => {
|
|
||||||
if (response.status > 399) {
|
|
||||||
alert('Fehler');
|
|
||||||
} else {
|
|
||||||
this.tasks.push(...response.body);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
backendService.getAllStatus().subscribe((response) => {
|
|
||||||
if (response.status > 399) {
|
|
||||||
alert('Fehler');
|
|
||||||
} else {
|
|
||||||
this.status.push(...response.body);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
backendService.getCategories().subscribe((response) => {
|
|
||||||
if (response.status > 399) {
|
|
||||||
alert('Fehler');
|
|
||||||
} else {
|
|
||||||
this.categories.push(...response.body);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private applyFilterParameters(params: ParamMap) {
|
|
||||||
if (params.has('id')) {
|
|
||||||
this.highlightId = parseInt(params.get('id'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public deleteUserstory(userstory: ScrumUserstory) {
|
|
||||||
this.backendService.deleteUserstory(userstory).subscribe((response) => {
|
|
||||||
if (response.status > 399) {
|
|
||||||
alert('Fehler');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const index = this.items.indexOf(userstory);
|
|
||||||
if (index !== -1) {
|
|
||||||
this.items.splice(index, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public openUserstoryForm(editUserstory?: ScrumUserstory) {
|
|
||||||
const modalRef = this.modalService.open(UserstoryFormComponent, {
|
|
||||||
backdrop: 'static',
|
|
||||||
keyboard: true,
|
|
||||||
size: 'lg'
|
|
||||||
});
|
|
||||||
if (editUserstory === null) {
|
|
||||||
modalRef.result.then((result) => {
|
|
||||||
this.items.push(result);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
modalRef.componentInstance.userstory = editUserstory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getNumberOfTasks(userstory: ScrumUserstory) {
|
|
||||||
return this.tasks.filter((t) => t.userstoryid === userstory.id).length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public sortById() {
|
|
||||||
this.doNumericSort('id', (us) => us.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sortByTitle() {
|
|
||||||
this.doStringSort('title', (us) => us.title);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sortByPrio() {
|
|
||||||
this.doNumericSort('priority', (us) => getNumberForPriority(us.priority));
|
|
||||||
}
|
|
||||||
|
|
||||||
public sortByTasks() {
|
|
||||||
this.doNumericSort('tasks', (us) => this.getNumberOfTasks(us));
|
|
||||||
}
|
|
||||||
|
|
||||||
sortByStatus() {
|
|
||||||
this.doNumericSort('statusid', (us) => us.statusid);
|
|
||||||
}
|
|
||||||
sortByCategory() {
|
|
||||||
this.doNumericSort('categoryid', (us) => us.categoryid);
|
|
||||||
}
|
|
||||||
|
|
||||||
getStatusTitleById(id) {
|
|
||||||
var status = this.status.find((x) => x.id === id);
|
|
||||||
if (!status) {
|
|
||||||
return 'N/A';
|
|
||||||
}
|
|
||||||
return status.title;
|
|
||||||
}
|
|
||||||
|
|
||||||
getCategoryTitleById(id) {
|
|
||||||
var category = this.categories.find((x) => x.id === id);
|
|
||||||
if (!category) {
|
|
||||||
return 'N/A';
|
|
||||||
}
|
|
||||||
return category.title;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
src/styles.css
Normal file
9
src/styles.css
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/* You can add global styles to this file, and also import other style files */
|
||||||
|
.custom-text-secondary {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.white-content .custom-text-secondary {
|
||||||
|
color: black !important;
|
||||||
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user