move all components into 'components' folder (except app-component)

This commit is contained in:
Jakob Fahr 2020-07-08 13:27:12 +02:00
parent f64f7439ea
commit faebfb5695
No known key found for this signature in database
GPG Key ID: 8873416D8E4CEF6B
30 changed files with 1147 additions and 1147 deletions

View File

@ -1,10 +1,10 @@
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 { DashboardComponent } from './components/dashboard/dashboard.component';
import { UserstoryTableComponent } from './userstory-table/userstory-table.component'; import { UserstoryTableComponent } from './components/userstory-table/userstory-table.component';
import { TaskTableComponent } from './task-table/task-table.component'; import { TaskTableComponent } from './components/task-table/task-table.component';
import { SprintTableComponent } from './sprint-table/sprint-table.component'; import { SprintTableComponent } from './components/sprint-table/sprint-table.component';
import {BacklogComponent} from './backlog-table/backlog.component'; import {BacklogComponent} from './components/backlog-table/backlog.component';
const routes: Routes = [ const routes: Routes = [
{ path: 'tasks', component: TaskTableComponent }, { path: 'tasks', component: TaskTableComponent },

View File

@ -7,16 +7,16 @@ import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { BackendService } from './services/backend.service'; import { BackendService } from './services/backend.service';
import { TaskFormComponent } from './task-form/task-form.component'; import { TaskFormComponent } from './components/task-form/task-form.component';
import { UserstoryFormComponent } from './userstory-form/userstory-form.component'; import { UserstoryFormComponent } from './components/userstory-form/userstory-form.component';
import { SprintFormComponent } from './sprint-form/sprint-form.component'; import { SprintFormComponent } from './components/sprint-form/sprint-form.component';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { UserstoryTableComponent } from './userstory-table/userstory-table.component'; import { UserstoryTableComponent } from './components/userstory-table/userstory-table.component';
import { TaskTableComponent } from './task-table/task-table.component'; import { TaskTableComponent } from './components/task-table/task-table.component';
import { SprintTableComponent } from './sprint-table/sprint-table.component'; import { SprintTableComponent } from './components/sprint-table/sprint-table.component';
import { DashboardComponent } from './dashboard/dashboard.component'; import { DashboardComponent } from './components/dashboard/dashboard.component';
import { UserstoryInnerTableComponent } from './userstory-inner-table/userstory-inner-table.component'; import { UserstoryInnerTableComponent } from './components/userstory-inner-table/userstory-inner-table.component';
import { BacklogComponent } from './backlog-table/backlog.component'; import { BacklogComponent } from './components/backlog-table/backlog.component';
@NgModule({ @NgModule({
declarations: [ declarations: [

View File

@ -1,3 +1,3 @@
th.sortable:hover { th.sortable:hover {
text-decoration: underline; text-decoration: underline;
} }

View File

@ -1,62 +1,62 @@
<div class="container-fluid"> <div class="container-fluid">
<div class="content"> <div class="content">
<h3>Backlog</h3> <h3>Backlog</h3>
<div class="row"> <div class="row">
<div class="col-lg-6 container-fluid"> <div class="col-lg-6 container-fluid">
</div> </div>
<div align="right" class="col-lg-6 container-fluid"> <div align="right" class="col-lg-6 container-fluid">
<button class="btn btn-secondary" (click)="openSprintForm()">Neuer Sprint</button> <button class="btn btn-secondary" (click)="openSprintForm()">Neuer Sprint</button>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-lg-6 container-fluid"> <div class="col-lg-6 container-fluid">
<h4>Backlog</h4> <h4>Backlog</h4>
<div *ngFor="let story of backlog" class="col-lg-6 container-fluid"> <div *ngFor="let story of backlog" class="col-lg-6 container-fluid">
<div class="card" style="width: 150%;"> <div class="card" style="width: 150%;">
<div class="card-body"> <div class="card-body">
<h4 class="card-title">{{story.title}}</h4> <h4 class="card-title">{{story.title}}</h4>
<h6 class="card-subtitle mb-2 text-muted">Prio: {{story.priority}}</h6> <h6 class="card-subtitle mb-2 text-muted">Prio: {{story.priority}}</h6>
<p class="card-text">{{story.content}}</p> <p class="card-text">{{story.content}}</p>
<div title="Badges"> <div title="Badges">
<span class="badge badge-primary">Category: {{story.categoryid || "N/A"}}</span> <span class="badge badge-primary">Category: {{story.categoryid || "N/A"}}</span>
<span class="badge badge-info">Status: {{story.statusid || "N/A"}}</span> <span class="badge badge-info">Status: {{story.statusid || "N/A"}}</span>
</div> </div>
<div style="text-align: right;"> <div style="text-align: right;">
<button type="button" rel="tooltip" (click)="addToSprintBacklog(story)" <button type="button" rel="tooltip" (click)="addToSprintBacklog(story)"
class="btn btn-sm btn-success btn-icon"> class="btn btn-sm btn-success btn-icon">
<i class="fas fa-plus-square"></i> <i class="fas fa-plus-square"></i>
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div></div> <div></div>
<div class="col-lg-6 container-fluid"> <div class="col-lg-6 container-fluid">
<h4>Sprint-Backlog - Aktueller Sprint: {{this.currentSprint.title}}</h4> <h4>Sprint-Backlog - Aktueller Sprint: {{this.currentSprint.title}}</h4>
<div *ngFor="let story of choosen" class="col-lg-6 container-fluid"> <div *ngFor="let story of choosen" class="col-lg-6 container-fluid">
<div class="card" style="width: 150%;"> <div class="card" style="width: 150%;">
<div class="card-body"> <div class="card-body">
<h4 class="card-title">{{story.title}}</h4> <h4 class="card-title">{{story.title}}</h4>
<h6 class="card-subtitle mb-2 text-muted">Prio: {{story.priority}}</h6> <h6 class="card-subtitle mb-2 text-muted">Prio: {{story.priority}}</h6>
<p class="card-text">{{story.content}}</p> <p class="card-text">{{story.content}}</p>
<div title="Badges"> <div title="Badges">
<span class="badge badge-primary">Category: {{story.categoryid || "N/A"}}</span> <span class="badge badge-primary">Category: {{story.categoryid || "N/A"}}</span>
<span class="badge badge-info">Status: {{story.statusid || "N/A"}}</span> <span class="badge badge-info">Status: {{story.statusid || "N/A"}}</span>
</div> </div>
<div style="text-align: right;"> <div style="text-align: right;">
<button type="button" rel="tooltip" (click)="deleteFromSprintBacklog(story)" <button type="button" rel="tooltip" (click)="deleteFromSprintBacklog(story)"
class="btn btn-danger btn-sm btn-icon"> class="btn btn-danger btn-sm btn-icon">
<i class="fa fa-trash"></i> <i class="fa fa-trash"></i>
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,160 +1,160 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { import {
BackendService, BackendService,
ScrumTask, ScrumTask,
ScrumUserstory, ScrumUserstory,
ScrumStatus, ScrumStatus,
ScrumCategory, ScrumCategory,
ScrumSprint, ScrumSprint,
} from '../services/backend.service'; } from '../../services/backend.service';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { TableComponentBase } from '../services/table-component.base'; import { TableComponentBase } from '../../services/table-component.base';
import { getNumberForPriority } from '../services/sorting.service'; import { getNumberForPriority } from '../../services/sorting.service';
import { UserstoryFormComponent } from '../userstory-form/userstory-form.component'; import { UserstoryFormComponent } from '../userstory-form/userstory-form.component';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { SprintFormComponent } from '../sprint-form/sprint-form.component'; import { SprintFormComponent } from '../sprint-form/sprint-form.component';
@Component({ @Component({
selector: 'app-backlog', selector: 'app-backlog',
templateUrl: './backlog.component.html', templateUrl: './backlog.component.html',
styleUrls: ['./backlog.component.css'], styleUrls: ['./backlog.component.css'],
}) })
export class BacklogComponent extends TableComponentBase< export class BacklogComponent extends TableComponentBase<
ScrumUserstory ScrumUserstory
> { > {
public tasks: ScrumTask[] = []; public tasks: ScrumTask[] = [];
public filterPriority: string | null = null; public filterPriority: string | null = null;
public status: ScrumStatus[] = []; public status: ScrumStatus[] = [];
public categories: ScrumCategory[] = []; public categories: ScrumCategory[] = [];
public sprints: ScrumSprint[] = []; public sprints: ScrumSprint[] = [];
public backlog: ScrumUserstory[] = []; public backlog: ScrumUserstory[] = [];
public choosen: ScrumUserstory[] = []; public choosen: ScrumUserstory[] = [];
constructor( constructor(
private backendService: BackendService, private backendService: BackendService,
private modalService: NgbModal, private modalService: NgbModal,
private route: ActivatedRoute, private route: ActivatedRoute,
) { ) {
super(); super();
backendService.getSprints().subscribe((response) => { backendService.getSprints().subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} else { } else {
this.sprints.push(...response.body); this.sprints.push(...response.body);
} }
}); });
backendService.getUserstories().subscribe((response) => { backendService.getUserstories().subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} else { } else {
this.backlog = response.body.filter(u => u.sprintid == null); this.backlog = response.body.filter(u => u.sprintid == null);
this.choosen = response.body.filter(u => u.sprintid == this.currentSprint.id); this.choosen = response.body.filter(u => u.sprintid == this.currentSprint.id);
} }
}); });
backendService.getTasks().subscribe((response) => { backendService.getTasks().subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} else { } else {
this.tasks.push(...response.body); this.tasks.push(...response.body);
} }
}); });
backendService.getAllStatus().subscribe((response) => { backendService.getAllStatus().subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} else { } else {
this.status.push(...response.body); this.status.push(...response.body);
} }
}); });
backendService.getCategories().subscribe((response) => { backendService.getCategories().subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} else { } else {
this.categories.push(...response.body); this.categories.push(...response.body);
} }
}); });
} }
public deleteUserstory(userstory: ScrumUserstory) { public deleteUserstory(userstory: ScrumUserstory) {
this.backendService.deleteUserstory(userstory).subscribe((response) => { this.backendService.deleteUserstory(userstory).subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} }
}); });
const index = this.items.indexOf(userstory); const index = this.items.indexOf(userstory);
if (index !== -1) { if (index !== -1) {
this.items.splice(index, 1); this.items.splice(index, 1);
} }
} }
public openUserstoryForm(editUserstory?: ScrumUserstory) { public openUserstoryForm(editUserstory?: ScrumUserstory) {
const modalRef = this.modalService.open(UserstoryFormComponent, { const modalRef = this.modalService.open(UserstoryFormComponent, {
backdrop: 'static', backdrop: 'static',
keyboard: true, keyboard: true,
size: 'lg' size: 'lg'
}); });
if (editUserstory === null) { if (editUserstory === null) {
modalRef.result.then((result) => { modalRef.result.then((result) => {
this.items.push(result); this.items.push(result);
}); });
} }
modalRef.componentInstance.userstory = editUserstory; modalRef.componentInstance.userstory = editUserstory;
} }
public getNumberOfTasks(userstory: ScrumUserstory) { public getNumberOfTasks(userstory: ScrumUserstory) {
return this.tasks.filter((t) => t.userstoryid === userstory.id).length; return this.tasks.filter((t) => t.userstoryid === userstory.id).length;
} }
getCategoryTitleById(id) { getCategoryTitleById(id) {
var category = this.categories.find((x) => x.id === id); var category = this.categories.find((x) => x.id === id);
if (!category) { if (!category) {
return 'N/A'; return 'N/A';
} }
return category.title; return category.title;
} }
// Sprint-Backlog // Sprint-Backlog
public addToSprintBacklog(userstory: ScrumUserstory) { public addToSprintBacklog(userstory: ScrumUserstory) {
this.choosen.push(userstory); this.choosen.push(userstory);
const index = this.backlog.indexOf(userstory); const index = this.backlog.indexOf(userstory);
this.backlog.splice(index, 1); this.backlog.splice(index, 1);
userstory.sprintid = this.currentSprint.id; userstory.sprintid = this.currentSprint.id;
this.backendService.putUserstory(userstory).subscribe((response) => { this.backendService.putUserstory(userstory).subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} }
}); });
} }
public deleteFromSprintBacklog(userstory: ScrumUserstory){ public deleteFromSprintBacklog(userstory: ScrumUserstory){
const index = this.choosen.indexOf(userstory); const index = this.choosen.indexOf(userstory);
this.choosen.splice(index, 1); this.choosen.splice(index, 1);
this.backlog.push(userstory) this.backlog.push(userstory)
userstory.sprintid = null; userstory.sprintid = null;
this.backendService.putUserstory(userstory).subscribe((response) => { this.backendService.putUserstory(userstory).subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} }
}); });
} }
public get currentSprint(): ScrumSprint { public get currentSprint(): ScrumSprint {
const now = Date.now(); const now = Date.now();
return this.sprints.find(s => Date.parse(s.startDate) < now && Date.parse(s.endDate) > now); return this.sprints.find(s => Date.parse(s.startDate) < now && Date.parse(s.endDate) > now);
} }
public openSprintForm(editSprint?: ScrumSprint) { public openSprintForm(editSprint?: ScrumSprint) {
const modalRef = this.modalService.open(SprintFormComponent, { const modalRef = this.modalService.open(SprintFormComponent, {
backdrop: 'static', backdrop: 'static',
keyboard: true, keyboard: true,
}); });
if (editSprint === null) { if (editSprint === null) {
modalRef.result.then(result => { modalRef.result.then(result => {
this.items.push(result); this.items.push(result);
}); });
} }
modalRef.componentInstance.sprint = editSprint; modalRef.componentInstance.sprint = editSprint;
} }
} }

View File

@ -1,7 +1,7 @@
.text-large { .text-large {
font-size: 1.2rem; font-size: 1.2rem;
} }
.text-very-large { .text-very-large {
font-size: 2.4rem; font-size: 2.4rem;
} }

View File

@ -1,101 +1,101 @@
<div class="container-fluid"> <div class="container-fluid">
<div class="content"> <div class="content">
<h3>Dashboard</h3> <h3>Dashboard</h3>
<div> <div>
<div class="row px-3 py-2"> <div class="row px-3 py-2">
<ng-container *ngIf="selectedSprint === undefined"> <ng-container *ngIf="selectedSprint === undefined">
<h3 class="mr-3 text-primary">Alle Userstories</h3> <h3 class="mr-3 text-primary">Alle Userstories</h3>
<a [routerLink]="['sprints']">Lege einen Sprint an, um Userstories zu organisieren.</a> <a [routerLink]="['sprints']">Lege einen Sprint an, um Userstories zu organisieren.</a>
</ng-container> </ng-container>
<ng-container *ngIf="selectedSprint !== undefined"> <ng-container *ngIf="selectedSprint !== undefined">
<h3 class="mr-3 text-primary" *ngIf="selectedSprint === currentSprint">Aktueller Sprint:</h3> <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 text-primary" *ngIf="selectedSprint !== currentSprint">Sprint:</h3>
<h3 class="mr-3 custom-text-secondary">{{selectedSprint.title}}</h3> <h3 class="mr-3 custom-text-secondary">{{selectedSprint.title}}</h3>
<h3 class="mr-3">{{toDateString(selectedSprint.startDate)}} - {{toDateString(selectedSprint.endDate)}}</h3> <h3 class="mr-3">{{toDateString(selectedSprint.startDate)}} - {{toDateString(selectedSprint.endDate)}}</h3>
<label class="mr-3"> <label class="mr-3">
<select class="select custom-select custom-text-secondary" [(ngModel)]="selectedSprint"> <select class="select custom-select custom-text-secondary" [(ngModel)]="selectedSprint">
<option class="bg-secondary text-dark" [ngValue]="currentSprint"> <option class="bg-secondary text-dark" [ngValue]="currentSprint">
{{currentSprint.title}} (aktuell) {{currentSprint.title}} (aktuell)
</option> </option>
<option value="" disabled="disabled">─────────────────────────</option> <option value="" disabled="disabled">─────────────────────────</option>
<option class="text-dark" *ngFor="let sprint of sprints" [ngValue]="sprint"> <option class="text-dark" *ngFor="let sprint of sprints" [ngValue]="sprint">
<ng-container *ngIf="sprint === currentSprint"> <ng-container *ngIf="sprint === currentSprint">
{{sprint.title}} (aktuell) {{sprint.title}} (aktuell)
</ng-container> </ng-container>
<ng-container *ngIf="sprint !== currentSprint"> <ng-container *ngIf="sprint !== currentSprint">
{{sprint.title}} ({{toDateString(sprint.startDate)}} - {{toDateString(sprint.endDate)}}) {{sprint.title}} ({{toDateString(sprint.startDate)}} - {{toDateString(sprint.endDate)}})
</ng-container> </ng-container>
</option> </option>
</select> </select>
</label> </label>
<span class="mr-5"></span> <span class="mr-5"></span>
<h3 <h3
*ngIf="selectedSprint === currentSprint" *ngIf="selectedSprint === currentSprint"
class="mr-3 custom-text-secondary" class="mr-3 custom-text-secondary"
[class.text-success]="getSprintUrgency() === 2" [class.text-success]="getSprintUrgency() === 2"
[class.text-warning]="getSprintUrgency() === 1" [class.text-warning]="getSprintUrgency() === 1"
[class.text-danger]="getSprintUrgency() === 0" [class.text-danger]="getSprintUrgency() === 0"
> >
Verbleibende Tage: {{getRemainingDaysInSprint()}} Verbleibende Tage: {{getRemainingDaysInSprint()}}
</h3> </h3>
</ng-container> </ng-container>
</div> </div>
<div class="row"> <div class="row">
<div class="p-3 col-12 col-xl-6 col-lg-6 col-md-12 col-sm-12"> <div class="p-3 col-12 col-xl-6 col-lg-6 col-md-12 col-sm-12">
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<span class="text-large"> <span class="text-large">
Userstories Userstories
</span> </span>
</div> </div>
<div class="card-body"> <div class="card-body">
<div *ngIf="selectedSprint !== undefined && usedStatus.length === 0"> <div *ngIf="selectedSprint !== undefined && usedStatus.length === 0">
Zum Sprint "{{selectedSprint.title}}" sind aktuell keine Userstories vorhanden. Zum Sprint "{{selectedSprint.title}}" sind aktuell keine Userstories vorhanden.
</div> </div>
<canvas id="done-stories-chart"></canvas> <canvas id="done-stories-chart"></canvas>
</div> </div>
</div> </div>
<div class="card-deck"> <div class="card-deck">
<div <div
class="card text-center" class="card text-center"
*ngFor="let status of usedStatus" *ngFor="let status of usedStatus"
> >
<div class="card-header"> <div class="card-header">
<span class="text-large"> <span class="text-large">
{{status.title}} {{status.title}}
</span> </span>
</div> </div>
<div class="card-body"> <div class="card-body">
<span class="text-very-large"> <span class="text-very-large">
<b>{{getNumberOfUserstoriesByStatus(status)}}</b> <b>{{getNumberOfUserstoriesByStatus(status)}}</b>
</span> </span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="p-3 col-12 col-xl-6 col-lg-6 col-md-12 col-sm-12"> <div class="p-3 col-12 col-xl-6 col-lg-6 col-md-12 col-sm-12">
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<app-userstory-inner-table [items]="selectedSprintUserstories"></app-userstory-inner-table> <app-userstory-inner-table [items]="selectedSprintUserstories"></app-userstory-inner-table>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,7 +1,7 @@
import {Component, OnChanges} from '@angular/core'; import {Component, OnChanges} from '@angular/core';
import {forkJoin} from 'rxjs'; import {forkJoin} from 'rxjs';
import Chart from 'chart.js'; import Chart from 'chart.js';
import {BackendService, ScrumSprint, ScrumStatus, ScrumUserstory} from '../services/backend.service'; import {BackendService, ScrumSprint, ScrumStatus, ScrumUserstory} from '../../services/backend.service';
@Component({ @Component({
selector: 'app-dashboard', selector: 'app-dashboard',

View File

@ -1,35 +1,35 @@
<!--Popup form to create an modify sprints--> <!--Popup form to create an modify sprints-->
<div class="card" style="width: 100%;"> <div class="card" style="width: 100%;">
<div class="container"> <div class="container">
<div class="card-body"> <div class="card-body">
<div style="text-align: right;"> <div style="text-align: right;">
<i class="fa fa-times fa-2x" (click)="onClose()"></i> <i class="fa fa-times fa-2x" (click)="onClose()"></i>
</div> </div>
<h4 class="card-title">Neuen Sprint anlegen</h4> <h4 class="card-title">Neuen Sprint anlegen</h4>
<form (ngSubmit)="onSubmit()"> <form (ngSubmit)="onSubmit()">
<div class="form-group"> <div class="form-group">
<label for="Title">Titel</label> <label for="Title">Titel</label>
<input type="text" class="form-control" id="Title" required name="title" [(ngModel)]="sprint.title" <input type="text" class="form-control" id="Title" required name="title" [(ngModel)]="sprint.title"
id="titleField"> id="titleField">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="date">Startdatum</label> <label for="date">Startdatum</label>
<input #startDate type="Date" class="form-control" id="Date" required name="date" <input #startDate type="Date" class="form-control" id="Date" required name="date"
[value]="sprint.startDate | date: 'yyyy-MM-dd'" (change)="sprint.startDate=startDate.value" [value]="sprint.startDate | date: 'yyyy-MM-dd'" (change)="sprint.startDate=startDate.value"
id="startDateField"> id="startDateField">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="Date">Enddatum</label> <label for="Date">Enddatum</label>
<input #endDate type="date" class="form-control" id="Date" required name="date" <input #endDate type="date" class="form-control" id="Date" required name="date"
[value]="sprint.endDate | date: 'yyyy-MM-dd'" (change)="sprint.endDate=endDate.value" id="endDateField"> [value]="sprint.endDate | date: 'yyyy-MM-dd'" (change)="sprint.endDate=endDate.value" id="endDateField">
</div> </div>
<div> <div>
<button (click)="onClose()" type="dismiss" class="btn btn-secondary" data-dismiss="modal">Abbrechen <button (click)="onClose()" type="dismiss" class="btn btn-secondary" data-dismiss="modal">Abbrechen
</button> </button>
<button type="submit" class="btn btn-primary">Sprint starten</button> <button type="submit" class="btn btn-primary">Sprint starten</button>
</div> </div>
</form> </form>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,60 +1,60 @@
// Importing necessary components and interfaces. // Importing necessary components and interfaces.
import { Component, OnInit, Input } from '@angular/core'; import { Component, OnInit, Input } from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { import {
BackendService, BackendService,
ScrumSprint ScrumSprint
} from '../services/backend.service'; } from '../../services/backend.service';
@Component({ @Component({
selector: 'app-task-form', selector: 'app-task-form',
templateUrl: './sprint-form.component.html', templateUrl: './sprint-form.component.html',
styleUrls: ['./sprint-form.component.css'] styleUrls: ['./sprint-form.component.css']
}) })
// Class implements the logic for a popup window form to create and modify sprints. // Class implements the logic for a popup window form to create and modify sprints.
export class SprintFormComponent implements OnInit { export class SprintFormComponent implements OnInit {
@Input() public sprint: ScrumSprint; @Input() public sprint: ScrumSprint;
public editing: Boolean; public editing: Boolean;
public sprintid: string; public sprintid: string;
constructor(private backendService: BackendService, private activeModalService: NgbActiveModal) { } constructor(private backendService: BackendService, private activeModalService: NgbActiveModal) { }
// If no sprint exists a new one will be created. // If no sprint exists a new one will be created.
// In other cases the sprint exists and gets modifiable. // In other cases the sprint exists and gets modifiable.
ngOnInit(): void { ngOnInit(): void {
if (this.sprint === null || this.sprint === undefined) { if (this.sprint === null || this.sprint === undefined) {
this.sprint = { title: '', startDate: '', endDate: '' }; this.sprint = { title: '', startDate: '', endDate: '' };
this.editing = false; this.editing = false;
} else { } else {
this.editing = true; this.editing = true;
} }
document.getElementById('titleField').focus(); document.getElementById('titleField').focus();
} }
// A new created sprint will be saved in backend (POST). // A new created sprint will be saved in backend (POST).
// If a sprint already exists, modifying results an update (PUT) to the backend. // If a sprint already exists, modifying results an update (PUT) to the backend.
onSubmit() { onSubmit() {
if (this.editing) { if (this.editing) {
this.backendService.putSprint(this.sprint).subscribe((response) => { this.backendService.putSprint(this.sprint).subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} }
}); });
} else { } else {
this.backendService.postSprint(this.sprint).subscribe((response) => { this.backendService.postSprint(this.sprint).subscribe((response) => {
console.log('Sprint gespeichert!'); console.log('Sprint gespeichert!');
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} }
}); });
} }
// Closes the popup window after submitting/canceling. // Closes the popup window after submitting/canceling.
this.activeModalService.close(this.sprint); this.activeModalService.close(this.sprint);
} }
// Closes the popup form window (by clicking "close button"). // Closes the popup form window (by clicking "close button").
onClose() { onClose() {
this.activeModalService.dismiss(this.sprint); this.activeModalService.dismiss(this.sprint);
} }
} }

View File

@ -1,66 +1,66 @@
<div class="container-fluid"> <div class="container-fluid">
<div class="content"> <div class="content">
<h3> <h3>
Sprints Sprints
</h3> </h3>
<button class="btn btn-secondary" (click)="openSprintForm()">Neuer Sprint</button> <button class="btn btn-secondary" (click)="openSprintForm()">Neuer Sprint</button>
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
<th (click)="sortById()" class="sortable"> <th (click)="sortById()" class="sortable">
<span>ID</span> <span>ID</span>
<span> <span>
<span *ngIf="sortBy != 'id'"><i class="fa fa-sort fa-lg"></i></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 && 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 *ngIf="sortDescending === false && sortBy === 'id'"><i class="fa fa-sort-down fa-lg"></i></span>
</span> </span>
</th> </th>
<th (click)="sortByTitle()" class="sortable"> <th (click)="sortByTitle()" class="sortable">
<span>Titel</span> <span>Titel</span>
<span> <span>
<span *ngIf="sortBy != 'title'"><i class="fa fa-sort fa-lg"></i></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 && 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 *ngIf="sortDescending === false && sortBy === 'title'"><i class="fa fa-sort-down fa-lg"></i></span>
</span> </span>
</th> </th>
<th (click)="sortByStartDate()" class="sortable"> <th (click)="sortByStartDate()" class="sortable">
<span>Start</span> <span>Start</span>
<span> <span>
<span *ngIf="sortBy != 'startDate'"><i class="fa fa-sort fa-lg"></i></span> <span *ngIf="sortBy != 'startDate'"><i class="fa fa-sort fa-lg"></i></span>
<span *ngIf="sortDescending && sortBy === 'startDate'"><i class="fa fa-sort-up fa-lg"></i></span> <span *ngIf="sortDescending && sortBy === 'startDate'"><i class="fa fa-sort-up fa-lg"></i></span>
<span *ngIf="sortDescending === false && sortBy === 'startDate'"><i class="fa fa-sort-down fa-lg"></i></span> <span *ngIf="sortDescending === false && sortBy === 'startDate'"><i class="fa fa-sort-down fa-lg"></i></span>
</span> </span>
</th> </th>
<th (click)="sortByEndDate()" class="sortable"> <th (click)="sortByEndDate()" class="sortable">
<span>End</span> <span>End</span>
<span> <span>
<span *ngIf="sortBy != 'endDate'"><i class="fa fa-sort fa-lg"></i></span> <span *ngIf="sortBy != 'endDate'"><i class="fa fa-sort fa-lg"></i></span>
<span *ngIf="sortDescending && sortBy === 'endDate'"><i class="fa fa-sort-up fa-lg"></i></span> <span *ngIf="sortDescending && sortBy === 'endDate'"><i class="fa fa-sort-up fa-lg"></i></span>
<span *ngIf="sortDescending === false && sortBy === 'endDate'"><i class="fa fa-sort-down fa-lg"></i></span> <span *ngIf="sortDescending === false && sortBy === 'endDate'"><i class="fa fa-sort-down fa-lg"></i></span>
</span> </span>
</th> </th>
<th></th> <th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr *ngFor="let sprint of filteredItems" [class.table-info]="sprint.id === highlightId"> <tr *ngFor="let sprint of filteredItems" [class.table-info]="sprint.id === highlightId">
<td>{{sprint.id}}</td> <td>{{sprint.id}}</td>
<td>{{sprint.title}}</td> <td>{{sprint.title}}</td>
<td>{{sprint.startDate | date:'dd.MM.yyyy'}}</td> <td>{{sprint.startDate | date:'dd.MM.yyyy'}}</td>
<td>{{sprint.endDate | date:'dd.MM.yyyy'}}</td> <td>{{sprint.endDate | date:'dd.MM.yyyy'}}</td>
<td> <td>
<button type="button" rel="tooltip" (click)="openSprintForm(sprint)" class="btn btn-success btn-sm btn-icon"> <button type="button" rel="tooltip" (click)="openSprintForm(sprint)" class="btn btn-success btn-sm btn-icon">
<i class="fa fa-pencil-alt"></i> <i class="fa fa-pencil-alt"></i>
</button> </button>
<button type="button" rel="tooltip" (click)="deleteSprint(sprint)" class="btn btn-danger btn-sm btn-icon"> <button type="button" rel="tooltip" (click)="deleteSprint(sprint)" class="btn btn-danger btn-sm btn-icon">
<i class="fa fa-trash"></i> <i class="fa fa-trash"></i>
</button> </button>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>

View File

@ -1,87 +1,87 @@
import {Component} from '@angular/core'; import {Component} from '@angular/core';
import {BackendService, ScrumSprint} from '../services/backend.service'; import {BackendService, ScrumSprint} from '../../services/backend.service';
import {TableComponentBase} from '../services/table-component.base'; import {TableComponentBase} from '../../services/table-component.base';
import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
import {ActivatedRoute, ParamMap, Router} from '@angular/router'; import {ActivatedRoute, ParamMap, Router} from '@angular/router';
import { SprintFormComponent } from '../sprint-form/sprint-form.component'; import { SprintFormComponent } from '../sprint-form/sprint-form.component';
@Component({ @Component({
selector: 'app-sprint', selector: 'app-sprint',
templateUrl: './sprint-table.component.html', templateUrl: './sprint-table.component.html',
styleUrls: ['./sprint-table.component.css'] styleUrls: ['./sprint-table.component.css']
}) })
export class SprintTableComponent extends TableComponentBase<ScrumSprint> { export class SprintTableComponent extends TableComponentBase<ScrumSprint> {
public filterSprintId: number | null = null; public filterSprintId: number | null = null;
public highlightId: number; public highlightId: number;
public get filteredItems() { public get filteredItems() {
return this.items.filter(sprint => return this.items.filter(sprint =>
(this.filterSprintId === null || sprint.id === this.filterSprintId) (this.filterSprintId === null || sprint.id === this.filterSprintId)
); );
} }
constructor( constructor(
private backendService: BackendService, private modalService: NgbModal, private backendService: BackendService, private modalService: NgbModal,
private route: ActivatedRoute, private router: Router private route: ActivatedRoute, private router: Router
) { ) {
super(); super();
this.applyFilterParameters(route.snapshot.paramMap); this.applyFilterParameters(route.snapshot.paramMap);
route.paramMap.subscribe(map => this.applyFilterParameters(map)); route.paramMap.subscribe(map => this.applyFilterParameters(map));
backendService.getSprints().subscribe(response => { backendService.getSprints().subscribe(response => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} else { } else {
this.items.push(...response.body); this.items.push(...response.body);
} }
}); });
} }
private applyFilterParameters(params: ParamMap) { private applyFilterParameters(params: ParamMap) {
if (params.has('id')) { if (params.has('id')) {
this.highlightId = parseInt(params.get('id')); this.highlightId = parseInt(params.get('id'));
} }
} }
public deleteSprint(sprint: ScrumSprint) { public deleteSprint(sprint: ScrumSprint) {
this.backendService.deleteSprint(sprint).subscribe(response => { this.backendService.deleteSprint(sprint).subscribe(response => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} }
}); });
const index = this.items.indexOf(sprint); const index = this.items.indexOf(sprint);
if (index !== -1) { if (index !== -1) {
this.items.splice(index, 1); this.items.splice(index, 1);
} }
} }
public openSprintForm(editSprint?: ScrumSprint) { public openSprintForm(editSprint?: ScrumSprint) {
const modalRef = this.modalService.open(SprintFormComponent, { const modalRef = this.modalService.open(SprintFormComponent, {
backdrop: 'static', backdrop: 'static',
keyboard: true, keyboard: true,
}); });
if (editSprint === null) { if (editSprint === null) {
modalRef.result.then(result => { modalRef.result.then(result => {
this.items.push(result); this.items.push(result);
}); });
} }
modalRef.componentInstance.sprint = editSprint; modalRef.componentInstance.sprint = editSprint;
} }
sortById() { sortById() {
this.doNumericSort('id', sprint => sprint.id); this.doNumericSort('id', sprint => sprint.id);
} }
sortByTitle() { sortByTitle() {
this.doStringSort('title', sprint => sprint.title); this.doStringSort('title', sprint => sprint.title);
} }
sortByStartDate() { sortByStartDate() {
this.doStringSort('startDate', sprint => sprint.startDate); this.doStringSort('startDate', sprint => sprint.startDate);
} }
sortByEndDate() { sortByEndDate() {
this.doStringSort('endDate', sprint => sprint.endDate); this.doStringSort('endDate', sprint => sprint.endDate);
} }
} }

View File

@ -1,200 +1,200 @@
// Importing necessary components and interfaces. // Importing necessary components and interfaces.
import { Component, OnInit, Input } from '@angular/core'; import { Component, OnInit, Input } from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { import {
BackendService, BackendService,
ScrumTask, ScrumTask,
Priority, Priority,
ScrumStatus, ScrumStatus,
ScrumCategory, ScrumCategory,
ScrumUser, ScrumUser,
ScrumProject, ScrumProject,
ScrumUserstory ScrumUserstory
} from '../services/backend.service'; } from '../../services/backend.service';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { HttpResponse } from '@angular/common/http'; import { HttpResponse } from '@angular/common/http';
@Component({ @Component({
selector: 'app-task-form', selector: 'app-task-form',
templateUrl: './task-form.component.html', templateUrl: './task-form.component.html',
styleUrls: ['./task-form.component.css'] styleUrls: ['./task-form.component.css']
}) })
// Class implements the logic for a popup window form to create and modify tasks. // Class implements the logic for a popup window form to create and modify tasks.
export class TaskFormComponent implements OnInit { export class TaskFormComponent implements OnInit {
@Input() public task: ScrumTask; @Input() public task: ScrumTask;
public editing: boolean; public editing: boolean;
public creating: boolean; public creating: boolean;
public userstoryId: string; public userstoryId: string;
public userstories: any[] = []; public userstories: any[] = [];
public allStatus: any[] = []; public allStatus: any[] = [];
public status: ScrumStatus = { title: "", description: "" }; public status: ScrumStatus = { title: "", description: "" };
public allUser: any[] = []; public allUser: any[] = [];
public user: ScrumUser = { name: "" }; public user: ScrumUser = { name: "" };
constructor(private backendService: BackendService, private activeModalService: NgbActiveModal) { constructor(private backendService: BackendService, private activeModalService: NgbActiveModal) {
this.getUserStories(); this.getUserStories();
this.getTaskStatus(); this.getTaskStatus();
this.getAllUsers(); this.getAllUsers();
} }
// If no task exists a new one will be created. // If no task exists a new one will be created.
// In other cases the task exists and gets modifiable. // In other cases the task exists and gets modifiable.
ngOnInit(): void { ngOnInit(): void {
if (this.task === null || this.task === undefined) { if (this.task === null || this.task === undefined) {
this.task = { title: '' }; this.task = { title: '' };
this.editing = false; this.editing = false;
this.creating = false; this.creating = false;
} else if (this.task.userstoryid) { } else if (this.task.userstoryid) {
this.editing = true; this.editing = true;
} else { } else {
this.creating = true; this.creating = true;
} }
document.getElementById('titleField').focus(); document.getElementById('titleField').focus();
this.getRelatedStory(); this.getRelatedStory();
} }
// A new created task will be saved in backend (POST). // A new created task will be saved in backend (POST).
// If a task already exists, modifying results an update (PUT) to the backend. // If a task already exists, modifying results an update (PUT) to the backend.
onSubmit() { onSubmit() {
if (this.editing) { if (this.editing) {
this.backendService.putTask(this.task).subscribe((response) => { this.backendService.putTask(this.task).subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} }
}); });
} else { } else {
this.backendService.postTask(this.task).subscribe((response) => { this.backendService.postTask(this.task).subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} }
}); });
} }
// Closes the popup window after submitting/canceling. // Closes the popup window after submitting/canceling.
this.activeModalService.close(this.task); this.activeModalService.close(this.task);
} }
// Closes the popup form window (by clicking "close button"). // Closes the popup form window (by clicking "close button").
onClose() { onClose() {
this.activeModalService.dismiss(this.task); this.activeModalService.dismiss(this.task);
} }
// Getting the userstory which is related to a task. // Getting the userstory which is related to a task.
// The related story will be shown in popup window of a task. // The related story will be shown in popup window of a task.
getRelatedStory() { getRelatedStory() {
if (!this.task.userstoryid) { if (!this.task.userstoryid) {
return null; return null;
} }
this.backendService.getUserstory(this.task.userstoryid).subscribe((response) => { this.backendService.getUserstory(this.task.userstoryid).subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} else { } else {
this.userstoryId = response.body.title; this.userstoryId = response.body.title;
} }
}); });
} }
// Getting all userstories from backend to show in a dropdown in popup window. // Getting all userstories from backend to show in a dropdown in popup window.
getUserStories() { getUserStories() {
this.backendService.getUserstories().subscribe((response) => { this.backendService.getUserstories().subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} else { } else {
this.userstories.push(...response.body); this.userstories.push(...response.body);
} }
}); });
} }
// Getting all available status from backend to list it in status-dropdown in popup window. // Getting all available status from backend to list it in status-dropdown in popup window.
getTaskStatus() { getTaskStatus() {
this.backendService.getAllStatus().subscribe((response) => { this.backendService.getAllStatus().subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} else { } else {
this.allStatus.push(...response.body); this.allStatus.push(...response.body);
} }
}); });
} }
// If desired a new arbitrary status (such as "Waiting") can be created, which will be stored in an array. // If desired a new arbitrary status (such as "Waiting") can be created, which will be stored in an array.
// The new status is available to all tasks. // The new status is available to all tasks.
createTaskStatus(status: ScrumStatus) { createTaskStatus(status: ScrumStatus) {
this.backendService.postStatus(status).subscribe((response) => { this.backendService.postStatus(status).subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} }
else { else {
this.allStatus.push(response.body); this.allStatus.push(response.body);
} }
}); });
} }
// A custom status can even be deleted if not used anymore. // A custom status can even be deleted if not used anymore.
// This will remove the status from status-array. // This will remove the status from status-array.
deleteStatus(id: number) { deleteStatus(id: number) {
var status = this.allStatus.find((x) => x.id === id); var status = this.allStatus.find((x) => x.id === id);
this.backendService.deleteStatus(status).subscribe((response) => { this.backendService.deleteStatus(status).subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} }
else { else {
const index = this.allStatus.indexOf(status); const index = this.allStatus.indexOf(status);
if (index !== -1) { if (index !== -1) {
this.allStatus.splice(index, 1); this.allStatus.splice(index, 1);
} }
} }
this.task.statusid = null; this.task.statusid = null;
}); });
} }
// Getting the values of the Priority enum to be shown in a dropdown in popup window. // Getting the values of the Priority enum to be shown in a dropdown in popup window.
getAllPriorities(): Priority[] { getAllPriorities(): Priority[] {
return Object.values(Priority); return Object.values(Priority);
} }
// necessary????????????????????????????????????????????????????? // necessary?????????????????????????????????????????????????????
getUserstoryTitleById(id: number): string { getUserstoryTitleById(id: number): string {
if (!id) { if (!id) {
return null; return null;
} }
var story = this.userstories.find((x) => x.id === id); var story = this.userstories.find((x) => x.id === id);
if (!story) { if (!story) {
return null; return null;
} }
return story.title; return story.title;
} }
// Shows the before choosen status in the status-field in the popup window. // Shows the before choosen status in the status-field in the popup window.
getStatusTitleById(id: number): string { getStatusTitleById(id: number): string {
if (!id) { if (!id) {
return null; return null;
} }
var status = this.allStatus.find((x) => x.id === id); var status = this.allStatus.find((x) => x.id === id);
if (!status) { if (!status) {
return null; return null;
} }
return status.title; return status.title;
} }
// Getting all taskboard users from backend to show in a dropdown in popup window. // Getting all taskboard users from backend to show in a dropdown in popup window.
getAllUsers() { getAllUsers() {
this.backendService.getUsers().subscribe((response) => { this.backendService.getUsers().subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} else { } else {
this.allUser.push(...response.body); this.allUser.push(...response.body);
} }
}); });
} }
// Shows the before assigned user in the author-field in the popup window. // Shows the before assigned user in the author-field in the popup window.
getAuthorById(id: number): string { getAuthorById(id: number): string {
if (!id) { if (!id) {
return null; return null;
} }
var user = this.allUser.find((x) => x.id === id); var user = this.allUser.find((x) => x.id === id);
if (!user) { if (!user) {
return null; return null;
} }
return user.name; return user.name;
} }
} }

View File

@ -5,12 +5,12 @@ import {
ScrumStatus, ScrumStatus,
ScrumUser, ScrumUser,
ScrumCategory, ScrumCategory,
} from '../services/backend.service'; } from '../../services/backend.service';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { TaskFormComponent } from '../task-form/task-form.component'; import { TaskFormComponent } from '../task-form/task-form.component';
import { TableComponentBase } from '../services/table-component.base'; import { TableComponentBase } from '../../services/table-component.base';
import { ActivatedRoute, ParamMap, Router } from '@angular/router'; import { ActivatedRoute, ParamMap, Router } from '@angular/router';
import { getNumberForPriority } from '../services/sorting.service'; import { getNumberForPriority } from '../../services/sorting.service';
import { NONE_TYPE } from '@angular/compiler'; import { NONE_TYPE } from '@angular/compiler';
@Component({ @Component({

View File

@ -1,140 +1,140 @@
<!--Popup form to create and modify a task--> <!--Popup form to create and modify a task-->
<div class="card" style="width: 100%;"> <div class="card" style="width: 100%;">
<div class="container"> <div class="container">
<div class="card-body"> <div class="card-body">
<div style="text-align: right;"> <div style="text-align: right;">
<i class="fa fa-times fa-2x" (click)="onClose()"></i> <i class="fa fa-times fa-2x" (click)="onClose()"></i>
</div> </div>
<div class="row"> <div class="row">
<div class="col-8" style="text-align: left;"> <div class="col-8" style="text-align: left;">
<h4 class="card-title">Neue Userstory anlegen</h4> <h4 class="card-title">Neue Userstory anlegen</h4>
</div> </div>
<div class="col-4"></div> <div class="col-4"></div>
</div> </div>
<form (ngSubmit)="onSubmit()"> <form (ngSubmit)="onSubmit()">
<div class="row"> <div class="row">
<div class="col-8"> <div class="col-8">
<div class="form-group"> <div class="form-group">
<label for="Title">Titel</label> <label for="Title">Titel</label>
<input type="text" class="form-control" id="Title" required name="title" <input type="text" class="form-control" id="Title" required name="title"
[(ngModel)]="userstory.title" id="titleField" /> [(ngModel)]="userstory.title" id="titleField" />
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="Inhalt">Story</label> <label for="Inhalt">Story</label>
<textarea type="text" class="form-control" id="Story" required name="story" rows="5" <textarea type="text" class="form-control" id="Story" required name="story" rows="5"
[(ngModel)]="userstory.content"></textarea> [(ngModel)]="userstory.content"></textarea>
</div> </div>
</div> </div>
<div class="col-4"> <div class="col-4">
<div ngbDropdown class="dropdown"> <div ngbDropdown class="dropdown">
<button ngbDropdownToggle class="btn btn-secondary dropdown-toggle" type="button" <button ngbDropdownToggle class="btn btn-secondary dropdown-toggle" type="button"
id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Prio: {{userstory.priority}} Prio: {{userstory.priority}}
</button> </button>
<div ngbDropdownMenu class="dropdown-menu" aria-labelledby="dropdownMenu2"> <div ngbDropdownMenu class="dropdown-menu" aria-labelledby="dropdownMenu2">
<option ngbDropdownItem *ngFor="let p of getAllPriorities()" <option ngbDropdownItem *ngFor="let p of getAllPriorities()"
(click)="userstory.priority=p"> (click)="userstory.priority=p">
{{p}}</option> {{p}}</option>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div ngbDropdown class="dropdown" [autoClose]="false"> <div ngbDropdown class="dropdown" [autoClose]="false">
<button ngbDropdownToggle class="btn btn-secondary dropdown-toggle" type="button" <button ngbDropdownToggle class="btn btn-secondary dropdown-toggle" type="button"
id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true" id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false"> aria-expanded="false">
Status: {{getStatusTitleById(userstory.statusid)}} Status: {{getStatusTitleById(userstory.statusid)}}
</button> </button>
<div ngbDropdownMenu class="dropdown-menu" aria-labelledby="dropdownMenu2"> <div ngbDropdownMenu class="dropdown-menu" aria-labelledby="dropdownMenu2">
<div class="card-text" for="Inhalt">Status wählen</div> <div class="card-text" for="Inhalt">Status wählen</div>
<option disable-auto-close ngbDropdownItem *ngFor="let status of allStatus" <option disable-auto-close ngbDropdownItem *ngFor="let status of allStatus"
(click)="userstory.statusid = status.id">{{ status.title }}</option> (click)="userstory.statusid = status.id">{{ status.title }}</option>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<div class="card-text" for="Inhalt">Neuer Status</div> <div class="card-text" for="Inhalt">Neuer Status</div>
<input #statusname type="text" id="statusname" class="dropdown-item" <input #statusname type="text" id="statusname" class="dropdown-item"
(change)="status.title=statusname.value" placeholder="New Title..." (change)="status.title=statusname.value" placeholder="New Title..."
style="background-color: rgba(211, 211, 211, 0.342);"> style="background-color: rgba(211, 211, 211, 0.342);">
<button disable-auto-close ngbDropdownItem class="dropdown-item" type="button" <button disable-auto-close ngbDropdownItem class="dropdown-item" type="button"
(click)="createUserstoryStatus(status)">Status anlegen</button> (click)="createUserstoryStatus(status)">Status anlegen</button>
<button disable-auto-close ngbDropdownItem class="dropdown-item" type="button" <button disable-auto-close ngbDropdownItem class="dropdown-item" type="button"
(click)="deleteStatus(userstory.statusid)">Status löschen</button> (click)="deleteStatus(userstory.statusid)">Status löschen</button>
</div> </div>
</div> </div>
<div class="dropdown-menu"> <div class="dropdown-menu">
<select class="form-control custom-select mr-sm-2" id="prio" required name="prio" <select class="form-control custom-select mr-sm-2" id="prio" required name="prio"
[(ngModel)]="userstory.statusid"> [(ngModel)]="userstory.statusid">
<option *ngFor="let status of allStatus" [value]="status.id">{{ <option *ngFor="let status of allStatus" [value]="status.id">{{
status.title status.title
}}</option> }}</option>
</select> </select>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div ngbDropdown class="dropdown" [autoClose]="false"> <div ngbDropdown class="dropdown" [autoClose]="false">
<button ngbDropdownToggle class="btn btn-secondary dropdown-toggle" type="button" <button ngbDropdownToggle class="btn btn-secondary dropdown-toggle" type="button"
id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true" id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false"> aria-expanded="false">
Kategorie: {{getCategoryById(userstory.categoryid)}} Kategorie: {{getCategoryById(userstory.categoryid)}}
</button> </button>
<div ngbDropdownMenu class="dropdown-menu" aria-labelledby="dropdownMenu2"> <div ngbDropdownMenu class="dropdown-menu" aria-labelledby="dropdownMenu2">
<div class="card-text" for="Inhalt">Kategorie wählen</div> <div class="card-text" for="Inhalt">Kategorie wählen</div>
<option disable-auto-close ngbDropdownItem *ngFor="let category of allCategories" <option disable-auto-close ngbDropdownItem *ngFor="let category of allCategories"
(click)="userstory.categoryid = category.id">{{ category.title }}</option> (click)="userstory.categoryid = category.id">{{ category.title }}</option>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<div class="card-text" for="Inhalt">Neue Kategorie</div> <div class="card-text" for="Inhalt">Neue Kategorie</div>
<input #categoryname type="text" id="categoryname" class="dropdown-item" <input #categoryname type="text" id="categoryname" class="dropdown-item"
(change)="category.title=categoryname.value" placeholder="New Title..." (change)="category.title=categoryname.value" placeholder="New Title..."
style="background-color: rgba(211, 211, 211, 0.342);"> style="background-color: rgba(211, 211, 211, 0.342);">
<button disable-auto-close ngbDropdownItem class="dropdown-item" type="button" <button disable-auto-close ngbDropdownItem class="dropdown-item" type="button"
(click)="createUserstoryCategory(category)">Kategorie anlegen</button> (click)="createUserstoryCategory(category)">Kategorie anlegen</button>
<button disable-auto-close ngbDropdownItem class="dropdown-item" type="button" <button disable-auto-close ngbDropdownItem class="dropdown-item" type="button"
(click)="deleteCategory(userstory.categoryid)">Kategorie löschen</button> (click)="deleteCategory(userstory.categoryid)">Kategorie löschen</button>
</div> </div>
</div> </div>
<div class="dropdown-menu"> <div class="dropdown-menu">
<select class="form-control custom-select mr-sm-2" id="prio" required name="prio" <select class="form-control custom-select mr-sm-2" id="prio" required name="prio"
[(ngModel)]="userstory.categoryid"> [(ngModel)]="userstory.categoryid">
<option *ngFor="let category of allCategories" [value]="category.id">{{ <option *ngFor="let category of allCategories" [value]="category.id">{{
category.title category.title
}}</option> }}</option>
</select> </select>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div ngbDropdown class="dropdown" [autoClose]="true"> <div ngbDropdown class="dropdown" [autoClose]="true">
<button ngbDropdownToggle class="btn btn-secondary dropdown-toggle" type="button" <button ngbDropdownToggle class="btn btn-secondary dropdown-toggle" type="button"
id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true" id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false"> aria-expanded="false">
Autor: {{getAuthorById(userstory.createdbyid)}} Autor: {{getAuthorById(userstory.createdbyid)}}
</button> </button>
<div ngbDropdownMenu class="dropdown-menu" aria-labelledby="dropdownMenu2"> <div ngbDropdownMenu class="dropdown-menu" aria-labelledby="dropdownMenu2">
<div class="card-text" for="Inhalt">User wählen</div> <div class="card-text" for="Inhalt">User wählen</div>
<option disable-auto-close ngbDropdownItem *ngFor="let user of allUser" <option disable-auto-close ngbDropdownItem *ngFor="let user of allUser"
(click)="userstory.createdbyid = user.id">{{ user.name }}</option> (click)="userstory.createdbyid = user.id">{{ user.name }}</option>
</div> </div>
</div> </div>
<div class="dropdown-menu"> <div class="dropdown-menu">
<select class="form-control custom-select mr-sm-2" id="prio" required name="prio" <select class="form-control custom-select mr-sm-2" id="prio" required name="prio"
[(ngModel)]="userstory.createdbyid"> [(ngModel)]="userstory.createdbyid">
<option *ngFor="let user of allUser" [value]="user.id">{{ <option *ngFor="let user of allUser" [value]="user.id">{{
user.name user.name
}}</option> }}</option>
</select> </select>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-6"> <div class="col-6">
<button (click)="onClose()" type="dismiss" class="btn btn-secondary" data-dismiss="modal"> <button (click)="onClose()" type="dismiss" class="btn btn-secondary" data-dismiss="modal">
Abbrechen Abbrechen
</button> </button>
<button type="submit" class="btn btn-primary">Erstellen</button> <button type="submit" class="btn btn-primary">Erstellen</button>
</div> </div>
</div> </div>
</form> </form>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,207 +1,207 @@
// Importing necessary components and interfaces. // Importing necessary components and interfaces.
import { Component, OnInit, Input } from '@angular/core'; import { Component, OnInit, Input } from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { BackendService, ScrumUserstory, Priority } from '../services/backend.service'; import { BackendService, ScrumUserstory, Priority } from '../../services/backend.service';
import { import {
ScrumTask, ScrumTask,
ScrumStatus, ScrumStatus,
ScrumCategory, ScrumCategory,
ScrumUser, ScrumUser,
ScrumProject, ScrumProject,
} from '../services/backend.service'; } from '../../services/backend.service';
@Component({ @Component({
selector: 'app-userstory-form', selector: 'app-userstory-form',
templateUrl: './userstory-form.component.html', templateUrl: './userstory-form.component.html',
styleUrls: ['./userstory-form.component.css'] styleUrls: ['./userstory-form.component.css']
}) })
// Class implements the logic for a popup window form to create and modify userstories. // Class implements the logic for a popup window form to create and modify userstories.
export class UserstoryFormComponent implements OnInit { export class UserstoryFormComponent implements OnInit {
@Input() public userstory: ScrumUserstory; @Input() public userstory: ScrumUserstory;
public allStatus: any[] = []; public allStatus: any[] = [];
public status: ScrumStatus = { title: "", description: "" }; public status: ScrumStatus = { title: "", description: "" };
public allUser: any[] = []; public allUser: any[] = [];
public user: ScrumUser = { name: "" }; public user: ScrumUser = { name: "" };
public allCategories: any[] = []; public allCategories: any[] = [];
public category: ScrumCategory = { title: "" }; public category: ScrumCategory = { title: "" };
private editing: boolean; private editing: boolean;
constructor(private backendService: BackendService, private activeModalService: NgbActiveModal) { constructor(private backendService: BackendService, private activeModalService: NgbActiveModal) {
this.getUserstoryStatus(); this.getUserstoryStatus();
this.getAllUsers(); this.getAllUsers();
this.getUserstoryCategory(); this.getUserstoryCategory();
} }
// If no userstory exists a new one will be created. // If no userstory exists a new one will be created.
// In other cases the userstory exists and gets modifiable. // In other cases the userstory exists and gets modifiable.
ngOnInit(): void { ngOnInit(): void {
if (this.userstory === null || this.userstory === undefined) { if (this.userstory === null || this.userstory === undefined) {
this.userstory = { title: '' }; this.userstory = { title: '' };
this.editing = false; this.editing = false;
} else { } else {
this.editing = true; this.editing = true;
} }
document.getElementById('titleField').focus(); document.getElementById('titleField').focus();
} }
// A new created userstory will be saved in backend (POST). // A new created userstory will be saved in backend (POST).
// If a userstory already exists, modifying results an update (PUT) to the backend. // If a userstory already exists, modifying results an update (PUT) to the backend.
onSubmit() { onSubmit() {
if (this.editing) { if (this.editing) {
this.backendService.putUserstory(this.userstory).subscribe((response) => { this.backendService.putUserstory(this.userstory).subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} }
}); });
} else { } else {
this.backendService.postUserstory(this.userstory).subscribe((response) => { this.backendService.postUserstory(this.userstory).subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} }
}); });
} }
// Closes the popup window after submitting/canceling. // Closes the popup window after submitting/canceling.
this.activeModalService.close(this.userstory); this.activeModalService.close(this.userstory);
} }
// Closes the popup form window (by clicking "close button"). // Closes the popup form window (by clicking "close button").
onClose() { onClose() {
this.activeModalService.dismiss(this.userstory); this.activeModalService.dismiss(this.userstory);
} }
// Getting all available status from backend to list it in status-dropdown in popup window. // Getting all available status from backend to list it in status-dropdown in popup window.
getUserstoryStatus() { getUserstoryStatus() {
this.backendService.getAllStatus().subscribe((response) => { this.backendService.getAllStatus().subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} else { } else {
this.allStatus.push(...response.body); this.allStatus.push(...response.body);
} }
}); });
} }
// If desired a new arbitrary status (such as "Waiting") can be created, which will be stored in an array. // If desired a new arbitrary status (such as "Waiting") can be created, which will be stored in an array.
// The new status is available to all userstories. // The new status is available to all userstories.
createUserstoryStatus(status: ScrumStatus) { createUserstoryStatus(status: ScrumStatus) {
this.backendService.postStatus(status).subscribe((response) => { this.backendService.postStatus(status).subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} }
else { else {
this.allStatus.push(response.body); this.allStatus.push(response.body);
} }
}); });
} }
// A custom status can even be deleted if not used anymore. // A custom status can even be deleted if not used anymore.
// This will remove the status from status-array. // This will remove the status from status-array.
deleteStatus(id: number) { deleteStatus(id: number) {
var status = this.allStatus.find((x) => x.id === id); var status = this.allStatus.find((x) => x.id === id);
this.backendService.deleteStatus(status).subscribe((response) => { this.backendService.deleteStatus(status).subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} }
else { else {
const index = this.allStatus.indexOf(status); const index = this.allStatus.indexOf(status);
if (index !== -1) { if (index !== -1) {
this.allStatus.splice(index, 1); this.allStatus.splice(index, 1);
} }
} }
this.userstory.statusid = null; this.userstory.statusid = null;
}); });
} }
// Getting the values of the Priority enum to be shown in a dropdown in popup window. // Getting the values of the Priority enum to be shown in a dropdown in popup window.
getAllPriorities(): Priority[] { getAllPriorities(): Priority[] {
return Object.values(Priority); return Object.values(Priority);
} }
// Shows the before choosen status in the status-field in the popup window. // Shows the before choosen status in the status-field in the popup window.
getStatusTitleById(id: number): string { getStatusTitleById(id: number): string {
if (!id) { if (!id) {
return null; return null;
} }
var status = this.allStatus.find((x) => x.id === id); var status = this.allStatus.find((x) => x.id === id);
if (!status) { if (!status) {
return null; return null;
} }
return status.title; return status.title;
} }
// Getting all taskboard users from backend to show in a dropdown in popup window. // Getting all taskboard users from backend to show in a dropdown in popup window.
getAllUsers() { getAllUsers() {
this.backendService.getUsers().subscribe((response) => { this.backendService.getUsers().subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} else { } else {
this.allUser.push(...response.body); this.allUser.push(...response.body);
} }
}); });
} }
// Shows the before assigned user in the author-field in the popup window. // Shows the before assigned user in the author-field in the popup window.
getAuthorById(id: number): string { getAuthorById(id: number): string {
if (!id) { if (!id) {
return null; return null;
} }
var user = this.allUser.find((x) => x.id === id); var user = this.allUser.find((x) => x.id === id);
if (!user) { if (!user) {
return null; return null;
} }
return user.name; return user.name;
} }
// Getting all available categories from backend to list it in status-dropdown in popup window. // Getting all available categories from backend to list it in status-dropdown in popup window.
getUserstoryCategory() { getUserstoryCategory() {
this.backendService.getCategories().subscribe((response) => { this.backendService.getCategories().subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} else { } else {
this.allCategories.push(...response.body); this.allCategories.push(...response.body);
} }
}); });
} }
// If desired a new arbitrary category can be created, which will be stored in an array. // If desired a new arbitrary category can be created, which will be stored in an array.
// The new category is available to all userstories. // The new category is available to all userstories.
createUserstoryCategory(category: ScrumCategory) { createUserstoryCategory(category: ScrumCategory) {
this.backendService.postCategory(category).subscribe((response) => { this.backendService.postCategory(category).subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} }
else { else {
this.allCategories.push(response.body); this.allCategories.push(response.body);
} }
}); });
} }
// A custom category can even be deleted if not used anymore. // A custom category can even be deleted if not used anymore.
// This will remove the category from category-array. // This will remove the category from category-array.
deleteCategory(id: number) { deleteCategory(id: number) {
var category = this.allCategories.find((x) => x.id === id); var category = this.allCategories.find((x) => x.id === id);
this.backendService.deleteCategory(category).subscribe((response) => { this.backendService.deleteCategory(category).subscribe((response) => {
if (response.status > 399) { if (response.status > 399) {
alert('Fehler'); alert('Fehler');
} }
else { else {
const index = this.allCategories.indexOf(category); const index = this.allCategories.indexOf(category);
if (index !== -1) { if (index !== -1) {
this.allCategories.splice(index, 1); this.allCategories.splice(index, 1);
} }
} }
this.userstory.categoryid = null; this.userstory.categoryid = null;
}); });
} }
// Shows the before choosen category in the category-field in the popup window. // Shows the before choosen category in the category-field in the popup window.
getCategoryById(id: number): string { getCategoryById(id: number): string {
if (!id) { if (!id) {
return null; return null;
} }
var category = this.allCategories.find((x) => x.id === id); var category = this.allCategories.find((x) => x.id === id);
if (!category) { if (!category) {
return null; return null;
} }
return category.title; return category.title;
} }
} }

View File

@ -5,10 +5,10 @@ import {
ScrumUserstory, ScrumUserstory,
ScrumStatus, ScrumStatus,
ScrumCategory, ScrumCategory,
} from '../services/backend.service'; } from '../../services/backend.service';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { TableComponentBase } from '../services/table-component.base'; import { TableComponentBase } from '../../services/table-component.base';
import { getNumberForPriority } from '../services/sorting.service'; import { getNumberForPriority } from '../../services/sorting.service';
import { UserstoryFormComponent } from '../userstory-form/userstory-form.component'; import { UserstoryFormComponent } from '../userstory-form/userstory-form.component';
import { ActivatedRoute, ParamMap, Router } from '@angular/router'; import { ActivatedRoute, ParamMap, Router } from '@angular/router';

View File

@ -2,7 +2,7 @@ import { Component } from '@angular/core';
import { import {
BackendService, BackendService,
ScrumUserstory, ScrumUserstory,
} from '../services/backend.service'; } from '../../services/backend.service';
@Component({ @Component({
selector: 'app-userstory-table', selector: 'app-userstory-table',