Users can now be added and deleted

This commit is contained in:
Nicolai Ort 2020-07-20 11:35:04 +02:00
parent b502f7cfe6
commit 12e60097bd
4 changed files with 1116 additions and 984 deletions

View File

@ -1,232 +1,261 @@
<!--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 *ngIf="editing" class="card-title">Task bearbeiten</h4> <h4 *ngIf="editing" class="card-title">Task bearbeiten</h4>
<h4 *ngIf="!editing" class="card-title">Neuen Task anlegen</h4> <h4 *ngIf="!editing" class="card-title">Neuen Task anlegen</h4>
<div ngbDropdown class="dropdown card-text"> <div ngbDropdown class="dropdown card-text">
<span <span
ngbDropdownToggle ngbDropdownToggle
class="dropdown" class="dropdown"
id="dropdownMenuUserstory" id="dropdownMenuUserstory"
data-toggle="dropdown" data-toggle="dropdown"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false" aria-expanded="false"
> >
Gehört zu Story: Gehört zu Story:
{{ getUserstoryTitleById(task.userstoryId) || "Keine" }} {{ getUserstoryTitleById(task.userstoryId) || "Keine" }}
<i class="fa fa-caret-down"></i> <i class="fa fa-caret-down"></i>
</span> </span>
<div <div
ngbDropdownMenu ngbDropdownMenu
class="dropdown-menu" class="dropdown-menu"
aria-labelledby="dropdownMenuUserstory" aria-labelledby="dropdownMenuUserstory"
> >
<option <option
ngbDropdownItem ngbDropdownItem
*ngFor="let userstory of userstories" *ngFor="let userstory of userstories"
(click)="task.userstoryId = userstory.id" (click)="task.userstoryId = userstory.id"
>{{ userstory.title }}</option >{{ userstory.title }}</option
> >
</div> </div>
</div> </div>
</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 <input
type="text" type="text"
class="form-control" class="form-control"
id="Title" id="Title"
required required
name="title" name="title"
[(ngModel)]="task.title" [(ngModel)]="task.title"
id="titleField" id="titleField"
/> />
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="Inhalt">What to do?</label> <label for="Inhalt">What to do?</label>
<textarea <textarea
type="text" type="text"
class="form-control" class="form-control"
id="Story" id="Story"
required required
name="story" name="story"
rows="5" rows="5"
[(ngModel)]="task.content" [(ngModel)]="task.content"
></textarea> ></textarea>
</div> </div>
</div> </div>
<div class="col-4"> <div class="col-4">
<div ngbDropdown class="dropdown"> <div ngbDropdown class="dropdown">
<button <button
ngbDropdownToggle ngbDropdownToggle
class="btn btn-secondary dropdown-toggle" class="btn btn-secondary dropdown-toggle"
type="button" type="button"
id="dropdownMenu2" id="dropdownMenu2"
data-toggle="dropdown" data-toggle="dropdown"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false" aria-expanded="false"
> >
Prio: {{ task.priority }} Prio: {{ task.priority }}
</button> </button>
<div <div
ngbDropdownMenu ngbDropdownMenu
class="dropdown-menu" class="dropdown-menu"
aria-labelledby="dropdownMenu2" aria-labelledby="dropdownMenu2"
> >
<option <option
ngbDropdownItem ngbDropdownItem
*ngFor="let p of getAllPriorities()" *ngFor="let p of getAllPriorities()"
(click)="task.priority = p" (click)="task.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 <button
ngbDropdownToggle ngbDropdownToggle
class="btn btn-secondary dropdown-toggle" class="btn btn-secondary dropdown-toggle"
type="button" type="button"
id="dropdownMenu3" id="dropdownMenu3"
data-toggle="dropdown" data-toggle="dropdown"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false" aria-expanded="false"
> >
Status: {{ getStatusTitleById(task.statusId) }} Status: {{ getStatusTitleById(task.statusId) }}
</button> </button>
<div <div
ngbDropdownMenu ngbDropdownMenu
class="dropdown-menu" class="dropdown-menu"
aria-labelledby="dropdownMenu2" aria-labelledby="dropdownMenu2"
> >
<div class="card-text" for="Inhalt">Status wählen</div> <div class="card-text" for="Inhalt">Status wählen</div>
<option <option
disable-auto-close disable-auto-close
ngbDropdownItem ngbDropdownItem
*ngFor="let status of allStatus" *ngFor="let status of allStatus"
(click)="task.statusId = status.id" (click)="task.statusId = status.id"
>{{ status.title }}</option >{{ 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 <input
#statusname #statusname
type="text" type="text"
id="statusname" id="statusname"
class="dropdown-item" class="dropdown-item"
(change)="status.title = statusname.value" (change)="status.title = statusname.value"
placeholder="New Title..." placeholder="New Title..."
style="background-color: rgba(211, 211, 211, 0.342);" style="background-color: rgba(211, 211, 211, 0.342);"
/> />
<button <button
disable-auto-close disable-auto-close
ngbDropdownItem ngbDropdownItem
class="dropdown-item" class="dropdown-item"
type="button" type="button"
(click)="createTaskStatus(status)" (click)="createTaskStatus(status)"
> >
Status anlegen Status anlegen
</button> </button>
<button <button
disable-auto-close disable-auto-close
ngbDropdownItem ngbDropdownItem
class="dropdown-item" class="dropdown-item"
type="button" type="button"
(click)="deleteStatus(task.statusId)" (click)="deleteStatus(task.statusId)"
> >
Status löschen Status löschen
</button> </button>
</div> </div>
</div> </div>
<div class="dropdown-menu"> <div class="dropdown-menu">
<select <select
class="form-control custom-select mr-sm-2" class="form-control custom-select mr-sm-2"
id="status" id="status"
required required
name="status" name="status"
[(ngModel)]="task.statusId" [(ngModel)]="task.statusId"
> >
<option <option
*ngFor="let status of allStatus" *ngFor="let status of allStatus"
[value]="status.id" [value]="status.id"
>{{ status.title }}</option >{{ status.title }}</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]="false">
<button <button
ngbDropdownToggle ngbDropdownToggle
class="btn btn-secondary dropdown-toggle" class="btn btn-secondary dropdown-toggle"
type="button" type="button"
id="dropdownMenu4" id="dropdownMenu4"
data-toggle="dropdown" data-toggle="dropdown"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false" aria-expanded="false"
> >
Bearbeiter: {{ getAuthorById(task.assignedtoId) }} Bearbeiter: {{ getAuthorById(task.assignedtoId) }}
</button> </button>
<div <div
ngbDropdownMenu ngbDropdownMenu
class="dropdown-menu" class="dropdown-menu"
aria-labelledby="dropdownMenu2" aria-labelledby="dropdownMenu2"
> >
<div class="card-text" for="Inhalt">User wählen</div> <div class="card-text" for="Inhalt">User wählen</div>
<option <option
disable-auto-close disable-auto-close
ngbDropdownItem ngbDropdownItem
*ngFor="let user of allUser" *ngFor="let user of allUser"
(click)="task.assignedtoId = user.id" (click)="task.assignedtoId = user.id"
>{{ user.name }}</option >{{ user.name }}</option
> >
</div> <div class="dropdown-divider"></div>
</div> <div class="card-text" for="Inhalt">Neuer User</div>
<div class="dropdown-menu"> <input
<select #username
class="form-control custom-select mr-sm-2" type="text"
id="assignedto" id="username"
required class="dropdown-item"
name="assignedto" (change)="user.name = username.value"
[(ngModel)]="task.assignedtoId" placeholder="New Title..."
> style="background-color: rgba(211, 211, 211, 0.342);"
<option *ngFor="let user of allUser" [value]="user.id">{{ />
user.name <button
}}</option> disable-auto-close
</select> ngbDropdownItem
</div> class="dropdown-item"
</div> type="button"
</div> (click)="createUser(user)"
</div> >
<div class="row"> User anlegen
<div class="col-6"> </button>
<button <button
(click)="onClose()" disable-auto-close
type="dismiss" ngbDropdownItem
class="btn btn-secondary" class="dropdown-item"
data-dismiss="modal" type="button"
> (click)="deleteUser(task.assignedtoId)"
Abbrechen >
</button> User löschen
<button *ngIf="editing" type="submit" class="btn btn-primary">Speichern</button> </button>
<button *ngIf="!editing" type="submit" class="btn btn-primary">Erstellen</button> </div>
</div> </div>
</div> <div class="dropdown-menu">
</form> <select
</div> class="form-control custom-select mr-sm-2"
</div> id="assignedto"
</div> required
name="assignedto"
[(ngModel)]="task.assignedtoId"
>
<option *ngFor="let user of allUser" [value]="user.id">{{
user.name
}}</option>
</select>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<button
(click)="onClose()"
type="dismiss"
class="btn btn-secondary"
data-dismiss="modal"
>
Abbrechen
</button>
<button *ngIf="editing" type="submit" class="btn btn-primary">Speichern</button>
<button *ngIf="!editing" type="submit" class="btn btn-primary">Erstellen</button>
</div>
</div>
</form>
</div>
</div>
</div>

View File

@ -1,234 +1,271 @@
// 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' ]
}) })
export // Class implements the logic for a popup window form to create and modify tasks. export // Class implements the logic for a popup window form to create and modify tasks.
class TaskFormComponent implements OnInit { 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 on will be created. * If no task exists a new on 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 the backend (POST). * A new created task will be saved in the 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');
} else { } else {
// Copy properties returned by the API // Copy properties returned by the API
Object.assign(this.task, response.body); Object.assign(this.task, response.body);
} }
}); });
} }
// 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.
* @param status Scrumstatus to store in the database * @param status Scrumstatus to store in the database
*/ */
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. /**
// This will remove the status from status-array. * If desired a new arbitrary user (such as "Testuser") can be created, which will be stored in an array.
/** * The new user is available to all tasks.
* A custom status can even be deleted if not used anymore. * @param user ScrumUser to store in the database
* This will remove the status from status-array */
* @param id the id of the chosen status createUser(user: ScrumUser) {
*/ this.backendService.postUser(user).subscribe((response) => {
deleteStatus(id: number) { if (response.status > 399) {
var status = this.allStatus.find((x) => x.id === id); alert('Fehler');
this.backendService.deleteStatus(status).subscribe((response) => { } else {
if (response.status > 399) { this.allUser.push(response.body);
alert('Fehler'); }
} else { });
const index = this.allStatus.indexOf(status); }
if (index !== -1) {
this.allStatus.splice(index, 1); // A custom status can even be deleted if not used anymore.
} // This will remove the status from status-array.
} /**
this.task.statusId = null; * A custom status can even be deleted if not used anymore.
}); * This will remove the status from status-array
} * @param id the id of the chosen status
*/
/** deleteStatus(id: number) {
* Getting the value of the priority enum to be shown in a dropdown in popup window. var status = this.allStatus.find((x) => x.id === id);
*/ this.backendService.deleteStatus(status).subscribe((response) => {
getAllPriorities(): Priority[] { if (response.status > 399) {
return Object.values(Priority); alert('Fehler');
} } else {
const index = this.allStatus.indexOf(status);
/** if (index !== -1) {
* Shows the before choosen userstory in the userstory-field in the popup window this.allStatus.splice(index, 1);
* @param id reference to the userstory object }
*/ }
getUserstoryTitleById(id: number): string { this.task.statusId = null;
if (!id) { });
return null; }
}
var story = this.userstories.find((x) => x.id === id); // A custom user can even be deleted if not used anymore.
if (!story) { // This will remove the user from user-array.
return null; /**
} * A custom user can even be deleted if not used anymore.
return story.title; * This will remove the user from user-array
} * @param id the id of the chosen user
*/
/** deleteUser(id: number) {
* Shows the before choosen status in the status-field in the popup window. var user = this.allUser.find((x) => x.id === id);
* @param id reference to the status object this.backendService.deleteUser(user).subscribe((response) => {
*/ if (response.status > 399) {
getStatusTitleById(id: number): string { alert('Fehler');
if (!id) { } else {
return null; const index = this.allUser.indexOf(user);
} if (index !== -1) {
var status = this.allStatus.find((x) => x.id === id); this.allUser.splice(index, 1);
if (!status) { }
return null; }
} this.task.assignedtoId = null;
return status.title; });
} }
/** /**
* Getting all taskboard users from the backend to show in a dropdown in popup window. * Getting the value of the priority enum to be shown in a dropdown in popup window.
*/ */
getAllUsers() { getAllPriorities(): Priority[] {
this.backendService.getUsers().subscribe((response) => { return Object.values(Priority);
if (response.status > 399) { }
alert('Fehler');
} else { /**
this.allUser.push(...response.body); * Shows the before choosen userstory in the userstory-field in the popup window
} * @param id reference to the userstory object
}); */
} getUserstoryTitleById(id: number): string {
if (!id) {
/** return null;
* Shows the before assigned user in the author-field in the popup window. }
* @param id reference to the author object var story = this.userstories.find((x) => x.id === id);
*/ if (!story) {
getAuthorById(id: number): string { return null;
if (!id) { }
return null; return story.title;
} }
var user = this.allUser.find((x) => x.id === id);
if (!user) { /**
return null; * Shows the before choosen status in the status-field in the popup window.
} * @param id reference to the status object
return user.name; */
} getStatusTitleById(id: number): string {
} if (!id) {
return null;
}
var status = this.allStatus.find((x) => x.id === id);
if (!status) {
return null;
}
return status.title;
}
/**
* Getting all taskboard users from the backend to show in a dropdown in popup window.
*/
getAllUsers() {
this.backendService.getUsers().subscribe((response) => {
if (response.status > 399) {
alert('Fehler');
} else {
this.allUser.push(...response.body);
}
});
}
/**
* Shows the before assigned user in the author-field in the popup window.
* @param id reference to the author object
*/
getAuthorById(id: number): string {
if (!id) {
return null;
}
var user = this.allUser.find((x) => x.id === id);
if (!user) {
return null;
}
return user.name;
}
}

View File

@ -1,280 +1,309 @@
<!--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 *ngIf="editing" class="card-title">Userstory #{{ userstory.id }} bearbeiten</h4> <h4 *ngIf="editing" class="card-title">Userstory #{{ userstory.id }} bearbeiten</h4>
<h4 *ngIf="!editing" class="card-title">Neue Userstory anlegen</h4> <h4 *ngIf="!editing" 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 <input
type="text" type="text"
class="form-control" class="form-control"
id="Title" id="Title"
required required
name="title" name="title"
[(ngModel)]="userstory.title" [(ngModel)]="userstory.title"
id="titleField" id="titleField"
/> />
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="Inhalt">Story</label> <label for="Inhalt">Story</label>
<textarea <textarea
type="text" type="text"
class="form-control" class="form-control"
id="Story" id="Story"
required required
name="story" name="story"
rows="5" rows="5"
[(ngModel)]="userstory.content" [(ngModel)]="userstory.content"
></textarea> ></textarea>
</div> </div>
</div> </div>
<div class="col-4"> <div class="col-4">
<div ngbDropdown class="dropdown"> <div ngbDropdown class="dropdown">
<button <button
ngbDropdownToggle ngbDropdownToggle
class="btn btn-secondary dropdown-toggle" class="btn btn-secondary dropdown-toggle"
type="button" type="button"
id="dropdownMenu2" id="dropdownMenu2"
data-toggle="dropdown" data-toggle="dropdown"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false" aria-expanded="false"
> >
Prio: {{ userstory.priority }} Prio: {{ userstory.priority }}
</button> </button>
<div <div
ngbDropdownMenu ngbDropdownMenu
class="dropdown-menu" class="dropdown-menu"
aria-labelledby="dropdownMenu2" aria-labelledby="dropdownMenu2"
> >
<option <option
ngbDropdownItem ngbDropdownItem
*ngFor="let p of getAllPriorities()" *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 <button
ngbDropdownToggle ngbDropdownToggle
class="btn btn-secondary dropdown-toggle" class="btn btn-secondary dropdown-toggle"
type="button" type="button"
id="dropdownMenu2" id="dropdownMenu2"
data-toggle="dropdown" data-toggle="dropdown"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false" aria-expanded="false"
> >
Status: {{ getStatusTitleById(userstory.statusId) }} Status: {{ getStatusTitleById(userstory.statusId) }}
</button> </button>
<div <div
ngbDropdownMenu ngbDropdownMenu
class="dropdown-menu" class="dropdown-menu"
aria-labelledby="dropdownMenu2" aria-labelledby="dropdownMenu2"
> >
<div class="card-text" for="Inhalt">Status wählen</div> <div class="card-text" for="Inhalt">Status wählen</div>
<option <option
disable-auto-close disable-auto-close
ngbDropdownItem ngbDropdownItem
*ngFor="let status of allStatus" *ngFor="let status of allStatus"
(click)="userstory.statusId = status.id" (click)="userstory.statusId = status.id"
>{{ status.title }}</option >{{ 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 <input
#statusname #statusname
type="text" type="text"
id="statusname" id="statusname"
class="dropdown-item" class="dropdown-item"
(change)="status.title = statusname.value" (change)="status.title = statusname.value"
placeholder="New Title..." placeholder="New Title..."
style="background-color: rgba(211, 211, 211, 0.342);" style="background-color: rgba(211, 211, 211, 0.342);"
/> />
<button <button
disable-auto-close disable-auto-close
ngbDropdownItem ngbDropdownItem
class="dropdown-item" class="dropdown-item"
type="button" type="button"
(click)="createUserstoryStatus(status)" (click)="createUserstoryStatus(status)"
> >
Status anlegen Status anlegen
</button> </button>
<button <button
disable-auto-close disable-auto-close
ngbDropdownItem ngbDropdownItem
class="dropdown-item" class="dropdown-item"
type="button" type="button"
(click)="deleteStatus(userstory.statusId)" (click)="deleteStatus(userstory.statusId)"
> >
Status löschen Status löschen
</button> </button>
</div> </div>
</div> </div>
<div class="dropdown-menu"> <div class="dropdown-menu">
<select <select
class="form-control custom-select mr-sm-2" class="form-control custom-select mr-sm-2"
id="prio" id="prio"
required required
name="prio" name="prio"
[(ngModel)]="userstory.statusId" [(ngModel)]="userstory.statusId"
> >
<option <option
*ngFor="let status of allStatus" *ngFor="let status of allStatus"
[value]="status.id" [value]="status.id"
>{{ status.title }}</option >{{ status.title }}</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 <button
ngbDropdownToggle ngbDropdownToggle
class="btn btn-secondary dropdown-toggle" class="btn btn-secondary dropdown-toggle"
type="button" type="button"
id="dropdownMenu2" id="dropdownMenu2"
data-toggle="dropdown" data-toggle="dropdown"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false" aria-expanded="false"
> >
Kategorie: {{ getCategoryById(userstory.categoryId) }} Kategorie: {{ getCategoryById(userstory.categoryId) }}
</button> </button>
<div <div
ngbDropdownMenu ngbDropdownMenu
class="dropdown-menu" class="dropdown-menu"
aria-labelledby="dropdownMenu2" aria-labelledby="dropdownMenu2"
> >
<div class="card-text" for="Inhalt">Kategorie wählen</div> <div class="card-text" for="Inhalt">Kategorie wählen</div>
<option <option
disable-auto-close disable-auto-close
ngbDropdownItem ngbDropdownItem
*ngFor="let category of allCategories" *ngFor="let category of allCategories"
(click)="userstory.categoryId = category.id" (click)="userstory.categoryId = category.id"
>{{ category.title }}</option >{{ 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 <input
#categoryname #categoryname
type="text" type="text"
id="categoryname" id="categoryname"
class="dropdown-item" class="dropdown-item"
(change)="category.title = categoryname.value" (change)="category.title = categoryname.value"
placeholder="New Title..." placeholder="New Title..."
style="background-color: rgba(211, 211, 211, 0.342);" style="background-color: rgba(211, 211, 211, 0.342);"
/> />
<button <button
disable-auto-close disable-auto-close
ngbDropdownItem ngbDropdownItem
class="dropdown-item" class="dropdown-item"
type="button" type="button"
(click)="createUserstoryCategory(category)" (click)="createUserstoryCategory(category)"
> >
Kategorie anlegen Kategorie anlegen
</button> </button>
<button <button
disable-auto-close disable-auto-close
ngbDropdownItem ngbDropdownItem
class="dropdown-item" class="dropdown-item"
type="button" type="button"
(click)="deleteCategory(userstory.categoryId)" (click)="deleteCategory(userstory.categoryId)"
> >
Kategorie löschen Kategorie löschen
</button> </button>
</div> </div>
</div> </div>
<div class="dropdown-menu"> <div class="dropdown-menu">
<select <select
class="form-control custom-select mr-sm-2" class="form-control custom-select mr-sm-2"
id="prio" id="prio"
required required
name="prio" name="prio"
[(ngModel)]="userstory.categoryId" [(ngModel)]="userstory.categoryId"
> >
<option <option
*ngFor="let category of allCategories" *ngFor="let category of allCategories"
[value]="category.id" [value]="category.id"
>{{ category.title }}</option >{{ category.title }}</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]="false">
<button <button
ngbDropdownToggle ngbDropdownToggle
class="btn btn-secondary dropdown-toggle" class="btn btn-secondary dropdown-toggle"
type="button" type="button"
id="dropdownMenu2" id="dropdownMenu4"
data-toggle="dropdown" data-toggle="dropdown"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false" aria-expanded="false"
> >
Autor: {{ getAuthorById(userstory.createdbyId) }} Bearbeiter: {{ getAuthorById(userstory.createdbyId) }}
</button> </button>
<div <div
ngbDropdownMenu ngbDropdownMenu
class="dropdown-menu" class="dropdown-menu"
aria-labelledby="dropdownMenu2" aria-labelledby="dropdownMenu2"
> >
<div class="card-text" for="Inhalt">User wählen</div> <div class="card-text" for="Inhalt">User wählen</div>
<option <option
disable-auto-close disable-auto-close
ngbDropdownItem ngbDropdownItem
*ngFor="let user of allUser" *ngFor="let user of allUser"
(click)="userstory.createdbyId = user.id" (click)="userstory.createdbyId = user.id"
>{{ user.name }}</option >{{ user.name }}</option
> >
</div> <div class="dropdown-divider"></div>
</div> <div class="card-text" for="Inhalt">Neuer User</div>
<div class="dropdown-menu"> <input
<select #username
class="form-control custom-select mr-sm-2" type="text"
id="prio" id="username"
required class="dropdown-item"
name="prio" (change)="user.name = username.value"
[(ngModel)]="userstory.createdbyId" placeholder="New Title..."
> style="background-color: rgba(211, 211, 211, 0.342);"
<option *ngFor="let user of allUser" [value]="user.id">{{ />
user.name <button
}}</option> disable-auto-close
</select> ngbDropdownItem
</div> class="dropdown-item"
</div> type="button"
</div> (click)="createUser(user)"
</div> >
<div class="row"> User anlegen
<div class="col-6"> </button>
<button <button
(click)="onClose()" disable-auto-close
type="dismiss" ngbDropdownItem
class="btn btn-secondary" class="dropdown-item"
data-dismiss="modal" type="button"
> (click)="deleteUser(task.assignedtoId)"
Abbrechen >
</button> User löschen
<button *ngIf="editing" type="submit" class="btn btn-primary">Speichern</button> </button>
<button *ngIf="!editing" type="submit" class="btn btn-primary">Erstellen</button> </div>
</div> </div>
</div> <div class="dropdown-menu">
</form> <select
</div> class="form-control custom-select mr-sm-2"
</div> id="prio"
</div> required
name="prio"
[(ngModel)]="userstory.createdbyId"
>
<option *ngFor="let user of allUser" [value]="user.id">{{
user.name
}}</option>
</select>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<button
(click)="onClose()"
type="dismiss"
class="btn btn-secondary"
data-dismiss="modal"
>
Abbrechen
</button>
<button *ngIf="editing" type="submit" class="btn btn-primary">Speichern</button>
<button *ngIf="!editing" type="submit" class="btn btn-primary">Erstellen</button>
</div>
</div>
</form>
</div>
</div>
</div>

View File

@ -1,238 +1,275 @@
// 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, ScrumStatus, ScrumCategory, ScrumUser } from '../../../services/backend.service'; import { BackendService, ScrumUserstory, Priority, ScrumStatus, ScrumCategory, ScrumUser } 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' ]
}) })
export // Class implements the logic for a popup window form to create and modify userstories. export // Class implements the logic for a popup window form to create and modify userstories.
class UserstoryFormComponent implements OnInit { 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: '' };
public editing: boolean; public 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 the backend (POST). * A new created userstory will be saved in the 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');
} else { } else {
// Copy properties returned by the API // Copy properties returned by the API
Object.assign(this.userstory, response.body); Object.assign(this.userstory, response.body);
} }
}); });
} }
// 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.
* @param status the status object which will be created * @param status the status object which will be created
*/ */
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
* @param id reference to the deletable status object * @param id reference to the deletable status object
*/ */
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.
* @param id reference to the status object * @param id reference to the status object
*/ */
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.
* @param id reference to the author object * @param id reference to the author object
*/ */
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.
/** /**
* 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.
* @param category the category object which will be created * @param category the category object which will be created
*/ */
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. /**
// This will remove the category from category-array. * If desired a new arbitrary user (such as "Testuser") can be created, which will be stored in an array.
/** * The new user is available to all userstories.
* A custom category can even be deleted if not used anymore. * @param user ScrumUser to store in the database
* This will remove the category from category-array. */
* @param id reference to the deletable category createUser(user: ScrumUser) {
*/ this.backendService.postUser(user).subscribe((response) => {
deleteCategory(id: number) { if (response.status > 399) {
var category = this.allCategories.find((x) => x.id === id); alert('Fehler');
this.backendService.deleteCategory(category).subscribe((response) => { } else {
if (response.status > 399) { this.allUser.push(response.body);
alert('Fehler'); }
} else { });
const index = this.allCategories.indexOf(category); }
if (index !== -1) {
this.allCategories.splice(index, 1); // A custom category can even be deleted if not used anymore.
} // This will remove the category from category-array.
} /**
this.userstory.categoryId = null; * A custom category can even be deleted if not used anymore.
}); * This will remove the category from category-array.
} * @param id reference to the deletable category
*/
/** deleteCategory(id: number) {
* Shows the before choosen category in the category-field in the popup window. var category = this.allCategories.find((x) => x.id === id);
* @param id reference to the category this.backendService.deleteCategory(category).subscribe((response) => {
*/ if (response.status > 399) {
getCategoryById(id: number): string { alert('Fehler');
if (!id) { } else {
return null; const index = this.allCategories.indexOf(category);
} if (index !== -1) {
var category = this.allCategories.find((x) => x.id === id); this.allCategories.splice(index, 1);
if (!category) { }
return null; }
} this.userstory.categoryId = null;
return category.title; });
} }
}
// A custom user can even be deleted if not used anymore.
// This will remove the user from user-array.
/**
* A custom user can even be deleted if not used anymore.
* This will remove the user from user-array
* @param id the id of the chosen user
*/
deleteUser(id: number) {
var user = this.allUser.find((x) => x.id === id);
this.backendService.deleteUser(user).subscribe((response) => {
if (response.status > 399) {
alert('Fehler');
} else {
const index = this.allUser.indexOf(user);
if (index !== -1) {
this.allUser.splice(index, 1);
}
}
this.userstory.createdbyId = null;
});
}
/**
* Shows the before choosen category in the category-field in the popup window.
* @param id reference to the category
*/
getCategoryById(id: number): string {
if (!id) {
return null;
}
var category = this.allCategories.find((x) => x.id === id);
if (!category) {
return null;
}
return category.title;
}
}