From 03e8c96a1e647a9c51d940fa0d44668831513d93 Mon Sep 17 00:00:00 2001 From: Jakob Fahr Date: Mon, 22 Jun 2020 03:38:23 +0200 Subject: [PATCH] Replace task-list/userstory-list with task-table/userstory-table --- src/app/app-routing.module.ts | 8 +- src/app/app.module.ts | 11 +- src/app/services/backend.service.ts | 32 +++--- src/app/services/sorting.service.ts | 20 ++++ src/app/services/table-component.base.ts | 33 ++++++ src/app/task-list/task-list.component.css | 0 src/app/task-list/task-list.component.html | 14 --- src/app/task-list/task-list.component.ts | 54 --------- src/app/task-table/task-table.component.css | 4 + src/app/task-table/task-table.component.html | 77 +++++++++++++ src/app/task-table/task-table.component.ts | 105 ++++++++++++++++++ .../userstory-list.component.css | 0 .../userstory-list.component.html | 14 --- .../userstory-list.component.ts | 54 --------- .../userstory-table.component.css | 4 + .../userstory-table.component.html | 69 ++++++++++++ .../userstory-table.component.ts | 103 +++++++++++++++++ src/assets/env.js | 6 +- 18 files changed, 444 insertions(+), 164 deletions(-) create mode 100644 src/app/services/sorting.service.ts create mode 100644 src/app/services/table-component.base.ts delete mode 100644 src/app/task-list/task-list.component.css delete mode 100644 src/app/task-list/task-list.component.html delete mode 100644 src/app/task-list/task-list.component.ts create mode 100644 src/app/task-table/task-table.component.css create mode 100644 src/app/task-table/task-table.component.html create mode 100644 src/app/task-table/task-table.component.ts delete mode 100644 src/app/userstory-list/userstory-list.component.css delete mode 100644 src/app/userstory-list/userstory-list.component.html delete mode 100644 src/app/userstory-list/userstory-list.component.ts create mode 100644 src/app/userstory-table/userstory-table.component.css create mode 100644 src/app/userstory-table/userstory-table.component.html create mode 100644 src/app/userstory-table/userstory-table.component.ts diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 7e0c37c..3df3eb8 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,13 +1,13 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; -import { TaskListComponent } from './task-list/task-list.component'; -import { UserstoryListComponent } from './userstory-list/userstory-list.component'; +import {UserstoryTableComponent} from './userstory-table/userstory-table.component'; +import {TaskTableComponent} from './task-table/task-table.component'; const routes: Routes = [ - { path: 'tasks', component: TaskListComponent }, - { path: 'userstories', component: UserstoryListComponent }, + { path: 'tasks', component: TaskTableComponent }, + { path: 'userstories', component: UserstoryTableComponent }, { path: '', redirectTo: '/tasks', pathMatch: 'full' }, ]; diff --git a/src/app/app.module.ts b/src/app/app.module.ts index e6c683f..3824996 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -7,19 +7,20 @@ import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { BackendService } from './services/backend.service'; -import { TaskListComponent } from './task-list/task-list.component'; import { TaskFormComponent } from './task-form/task-form.component'; -import { UserstoryListComponent } from './userstory-list/userstory-list.component'; import { UserstoryFormComponent } from './userstory-form/userstory-form.component'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { UserstoryTableComponent } from './userstory-table/userstory-table.component'; +import { TaskTableComponent } from './task-table/task-table.component'; @NgModule({ declarations: [ AppComponent, - TaskListComponent, + TaskTableComponent, TaskFormComponent, - UserstoryListComponent, - UserstoryFormComponent + UserstoryTableComponent, + UserstoryFormComponent, + UserstoryTableComponent ], imports: [ BrowserModule, diff --git a/src/app/services/backend.service.ts b/src/app/services/backend.service.ts index 239f82a..6d52bf4 100644 --- a/src/app/services/backend.service.ts +++ b/src/app/services/backend.service.ts @@ -9,7 +9,7 @@ export class BackendService { constructor(private httpClient: HttpClient) {} - + // Tasks public getTasks(): Observable> { const url = `${environment.apiUrl}/tasks`; @@ -117,7 +117,7 @@ export class BackendService { return this.httpClient.delete(url, { observe: 'response' }); } - + // Status public getAllStatus(): Observable> { const url = `${environment.apiUrl}/status`; @@ -143,8 +143,8 @@ export class BackendService { const url = `${environment.apiUrl}/status/${status.id}`; return this.httpClient.delete(url, { observe: 'response' }); } - - + + // Users public getUsers(): Observable> { const url = `${environment.apiUrl}/users`; @@ -171,7 +171,7 @@ export class BackendService { return this.httpClient.delete(url, { observe: 'response' }); } - + // Projects public getProjects(): Observable> { const url = `${environment.apiUrl}/projects`; @@ -209,12 +209,12 @@ export interface ScrumTask { id?: number; title: string; content?: string; - status?: number; - category?: number; - assignedto?: number; - sprint?: number; - project?: number; - userstory?: number; + statusid?: number; + categoryid?: number; + assignedtoid?: number; + sprintid?: number; + projectid?: number; + userstoryid?: number; priority?: Priority; } @@ -223,10 +223,10 @@ export interface ScrumUserstory { title: string; content?: string; priority?: Priority; - status?: number; - category?: number; - createdby?: number; - project?: number; + statusid?: number; + categoryid?: number; + createdbyid?: number; + projectid?: number; } export interface ScrumSprint{ @@ -262,4 +262,4 @@ export interface ScrumProject { id?: number; title: string; isprivate: boolean; -} \ No newline at end of file +} diff --git a/src/app/services/sorting.service.ts b/src/app/services/sorting.service.ts new file mode 100644 index 0000000..9837ffe --- /dev/null +++ b/src/app/services/sorting.service.ts @@ -0,0 +1,20 @@ +import {Priority} from './backend.service'; + +export function sortByNumberAscending(items: T[], key: (T) => number) { + return items.sort((a, b) => key(a) - key(b)); +} + +export function sortByStringAscending(items: T[], key: (T) => string) { + return items.sort((a, b) => key(a).localeCompare(key(b))); +} + +export function getNumberForPriority(priority: Priority): number { + switch (priority) { + case Priority.High: + return 2; + case Priority.Medium: + return 1; + case Priority.Low: + return 0; + } +}; diff --git a/src/app/services/table-component.base.ts b/src/app/services/table-component.base.ts new file mode 100644 index 0000000..4e22e3f --- /dev/null +++ b/src/app/services/table-component.base.ts @@ -0,0 +1,33 @@ +import {sortByNumberAscending, sortByStringAscending} from './sorting.service'; + +export abstract class TableComponentBase { + public sortBy: string; + public sortDescending = false; + public items: T[] = []; + + protected doNumericSort(by: string, key: (ScrumTask) => number) { + if (this.sortBy === by) { + this.sortDescending = !this.sortDescending; + } else { + this.sortBy = by; + } + + this.items = sortByNumberAscending(this.items, key); + if (this.sortDescending) { + this.items = this.items.reverse(); + } + } + + protected doStringSort(by: string, key: (ScrumTask) => string) { + if (this.sortBy === by) { + this.sortDescending = !this.sortDescending; + } else { + this.sortBy = by; + } + + this.items = sortByStringAscending(this.items, key); + if (this.sortDescending) { + this.items = this.items.reverse(); + } + } +} diff --git a/src/app/task-list/task-list.component.css b/src/app/task-list/task-list.component.css deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/task-list/task-list.component.html b/src/app/task-list/task-list.component.html deleted file mode 100644 index 1f501a3..0000000 --- a/src/app/task-list/task-list.component.html +++ /dev/null @@ -1,14 +0,0 @@ - - -
    -
  • - Titel: {{task.title}} -
    - Inhalt: {{task.content}} -
    - Priotität: {{task.priority}} -
    - - -
  • -
diff --git a/src/app/task-list/task-list.component.ts b/src/app/task-list/task-list.component.ts deleted file mode 100644 index b8daf28..0000000 --- a/src/app/task-list/task-list.component.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { BackendService, ScrumTask } from '../services/backend.service'; -import { TaskFormComponent } from '../task-form/task-form.component'; - -@Component({ - selector: 'app-task-list', - templateUrl: './task-list.component.html', - styleUrls: ['./task-list.component.css'] -}) -export class TaskListComponent implements OnInit { - - public tasks: ScrumTask[] = []; - - constructor(private backendService: BackendService, private modalService: NgbModal) { - backendService.getTasks().subscribe(response => { - if (response.status > 399) { - alert('Fehler'); - } - else { - this.tasks.push(...response.body); - } - }); - } - - ngOnInit(): void { - } - - public deleteTask(task: ScrumTask) { - this.backendService.deleteTask(task).subscribe(response => { - if (response.status > 399) { - alert('Fehler'); - } - }); - const index = this.tasks.indexOf(task); - if (index !== -1) { - this.tasks.splice(index, 1); - } - } - - public openTaskForm(editTask: ScrumTask) { - const modalRef = this.modalService.open(TaskFormComponent, { - backdrop: 'static', - keyboard: true, - }); - if (editTask === null) { - modalRef.result.then(result => { - this.tasks.push(result); - }); - } - modalRef.componentInstance.task = editTask; - } - -} diff --git a/src/app/task-table/task-table.component.css b/src/app/task-table/task-table.component.css new file mode 100644 index 0000000..c1ce646 --- /dev/null +++ b/src/app/task-table/task-table.component.css @@ -0,0 +1,4 @@ +table { + table-layout: fixed; +} + diff --git a/src/app/task-table/task-table.component.html b/src/app/task-table/task-table.component.html new file mode 100644 index 0000000..4a2df3e --- /dev/null +++ b/src/app/task-table/task-table.component.html @@ -0,0 +1,77 @@ +
+ +

+ + Userstory #{{filterUserstoryId}} > + + Tasks +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ ID + + + + + + Titel + + + + + + Inhalt + + + + + + Tasks + + + + + + Priorität + + + + +
{{task.id}}{{task.title}}{{task.content}} + + US #{{task.userstoryid}} + + {{task.priority}} + + +
+
diff --git a/src/app/task-table/task-table.component.ts b/src/app/task-table/task-table.component.ts new file mode 100644 index 0000000..c4d7434 --- /dev/null +++ b/src/app/task-table/task-table.component.ts @@ -0,0 +1,105 @@ +import {Component} from '@angular/core'; +import {BackendService, Priority, ScrumTask, ScrumUserstory} from '../services/backend.service'; +import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; +import {TaskFormComponent} from '../task-form/task-form.component'; +import {TableComponentBase} from '../services/table-component.base'; +import {ActivatedRoute, Router} from '@angular/router'; + +@Component({ + selector: 'app-userstory-table', + templateUrl: './task-table.component.html', + styleUrls: ['./task-table.component.css'] +}) +export class TaskTableComponent extends TableComponentBase { + public filterUserstoryId: number | null = null; + public get filteredItems() { + if (this.filterUserstoryId === null || isNaN(this.filterUserstoryId)) { + return this.items; + } + return this.items.filter(task => task.userstoryid === this.filterUserstoryId); + } + + constructor( + private backendService: BackendService, private modalService: NgbModal, + private route: ActivatedRoute, private router: Router + ) { + super(); + + const params = route.snapshot.paramMap; + if (params.has('userstoryId')) { + this.filterUserstoryId = parseInt(params.get('userstoryId')); + } + if (params.has('id')) { + const id = parseInt(params.get('id')); + this.openTaskForm(this.items.find(t => t.id === id)); + } + + backendService.getTasks().subscribe(response => { + if (response.status > 399) { + alert('Fehler'); + } else { + this.items.push(...response.body); + } + }); + } + + public deleteTask(task: ScrumTask) { + this.backendService.deleteTask(task).subscribe(response => { + if (response.status > 399) { + alert('Fehler'); + } + }); + const index = this.items.indexOf(task); + if (index !== -1) { + this.items.splice(index, 1); + } + } + + public openTaskForm(editTask?: ScrumTask) { + const modalRef = this.modalService.open(TaskFormComponent, { + backdrop: 'static', + keyboard: true, + }); + if (editTask === null) { + modalRef.result.then(result => { + this.items.push(result); + }); + } + modalRef.componentInstance.task = editTask; + } + + sortById() { + this.doNumericSort('id', us => us.id); + } + + sortByTitle() { + this.doStringSort('title', us => us.title); + } + + sortByContent() { + this.doStringSort('content', us => us.content); + } + + private getNumberForPriority(priority: Priority): number { + switch (priority) { + case Priority.High: + return 2; + case Priority.Medium: + return 1; + case Priority.Low: + return 0; + } + } + + sortByPrio() { + this.doNumericSort('priority', us => this.getNumberForPriority(us.priority)); + } + + getNumberOfTasks(userstory: ScrumUserstory) { + return this.items.filter(t => t.userstoryid === userstory.id).length; + } + + sortByTasks() { + this.doNumericSort('tasks', us => this.getNumberOfTasks(us)); + } +} diff --git a/src/app/userstory-list/userstory-list.component.css b/src/app/userstory-list/userstory-list.component.css deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/userstory-list/userstory-list.component.html b/src/app/userstory-list/userstory-list.component.html deleted file mode 100644 index fbee073..0000000 --- a/src/app/userstory-list/userstory-list.component.html +++ /dev/null @@ -1,14 +0,0 @@ - - -
    -
  • - Titel: {{userstory.title}} -
    - Inhalt: {{userstory.content}} -
    - Priotität: {{userstory.priority}} -
    - - -
  • -
diff --git a/src/app/userstory-list/userstory-list.component.ts b/src/app/userstory-list/userstory-list.component.ts deleted file mode 100644 index 526f825..0000000 --- a/src/app/userstory-list/userstory-list.component.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { BackendService, ScrumUserstory } from '../services/backend.service'; -import { UserstoryFormComponent } from '../userstory-form/userstory-form.component'; - -@Component({ - selector: 'app-userstory-list', - templateUrl: './userstory-list.component.html', - styleUrls: ['./userstory-list.component.css'] -}) -export class UserstoryListComponent implements OnInit { - - public userstories: ScrumUserstory[] = []; - - constructor(private backendService: BackendService, private modalService: NgbModal) { - backendService.getUserstories().subscribe(response => { - if (response.status > 399) { - alert('Fehler'); - } - else { - this.userstories.push(...response.body); - } - }); - } - - ngOnInit(): void { - } - - public deleteUserstory(userstory: ScrumUserstory) { - this.backendService.deleteUserstory(userstory).subscribe(response => { - if (response.status > 399) { - alert('Fehler'); - } - }); - const index = this.userstories.indexOf(userstory); - if (index !== -1) { - this.userstories.splice(index, 1); - } - } - - public openUserstoryForm(editUserstory: ScrumUserstory) { - const modalRef = this.modalService.open(UserstoryFormComponent, { - backdrop: 'static', - keyboard: true, - }); - if (editUserstory === null) { - modalRef.result.then(result => { - this.userstories.push(result); - }); - } - modalRef.componentInstance.userstory = editUserstory; - } - -} diff --git a/src/app/userstory-table/userstory-table.component.css b/src/app/userstory-table/userstory-table.component.css new file mode 100644 index 0000000..c1ce646 --- /dev/null +++ b/src/app/userstory-table/userstory-table.component.css @@ -0,0 +1,4 @@ +table { + table-layout: fixed; +} + diff --git a/src/app/userstory-table/userstory-table.component.html b/src/app/userstory-table/userstory-table.component.html new file mode 100644 index 0000000..4dfcdff --- /dev/null +++ b/src/app/userstory-table/userstory-table.component.html @@ -0,0 +1,69 @@ +
+ +

Userstories

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ ID + + + + + + Titel + + + + + + Inhalt + + + + + + Tasks + + + + + + Priorität + + + + +
{{userstory.id}}{{userstory.title}}{{userstory.content}} + + {{getNumberOfTasks(userstory)}} Tasks + + {{userstory.priority}} + + +
+
diff --git a/src/app/userstory-table/userstory-table.component.ts b/src/app/userstory-table/userstory-table.component.ts new file mode 100644 index 0000000..7d03e10 --- /dev/null +++ b/src/app/userstory-table/userstory-table.component.ts @@ -0,0 +1,103 @@ +import {Component} from '@angular/core'; +import {BackendService, ScrumTask, ScrumUserstory} from '../services/backend.service'; +import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; +import {TableComponentBase} from '../services/table-component.base'; +import {getNumberForPriority} from '../services/sorting.service'; +import {UserstoryFormComponent} from '../userstory-form/userstory-form.component'; +import {ActivatedRoute, Router} from '@angular/router'; + +@Component({ + selector: 'app-userstory-table', + templateUrl: './userstory-table.component.html', + styleUrls: ['./userstory-table.component.css'] +}) +export class UserstoryTableComponent extends TableComponentBase { + public tasks: ScrumTask[] = []; + + constructor( + private backendService: BackendService, private modalService: NgbModal, + private route: ActivatedRoute, private router: Router + ) { + super(); + + const params = route.snapshot.paramMap; + + backendService.getUserstories().subscribe(response => { + if (response.status > 399) { + alert('Fehler'); + } else { + this.items.push(...response.body); + + // Wenn /userstories;id=3 aufgerufen wird, öffne die Userstory mit ID 3 + const userstory = this.findUserstoryById(parseInt(params.get('id'))); + if (userstory !== null) { + this.openUserstoryForm(userstory); + } + } + }); + backendService.getTasks().subscribe(response => { + if (response.status > 399) { + alert('Fehler'); + } else { + this.tasks.push(...response.body); + } + }); + } + + private findUserstoryById(id: number): ScrumUserstory { + const userstoriesWithId = this.items.filter(us => us.id === id); + if (userstoriesWithId.length === 0) { + return null; + } + return userstoriesWithId[0]; + } + + public deleteUserstory(userstory: ScrumUserstory) { + this.backendService.deleteUserstory(userstory).subscribe(response => { + if (response.status > 399) { + alert('Fehler'); + } + }); + const index = this.items.indexOf(userstory); + if (index !== -1) { + this.items.splice(index, 1); + } + } + + public openUserstoryForm(editUserstory?: ScrumUserstory) { + const modalRef = this.modalService.open(UserstoryFormComponent, { + backdrop: 'static', + keyboard: true, + }); + if (editUserstory === null) { + modalRef.result.then(result => { + this.items.push(result); + }); + } + modalRef.componentInstance.userstory = editUserstory; + } + + public getNumberOfTasks(userstory: ScrumUserstory) { + return this.tasks.filter(t => t.userstoryid === userstory.id).length; + } + + public sortById() { + this.doNumericSort('id', us => us.id); + } + + public sortByTitle() { + this.doStringSort('title', us => us.title); + } + + public sortByContent() { + this.doStringSort('content', us => us.content); + } + + public sortByPrio() { + this.doNumericSort('priority', us => getNumberForPriority(us.priority)); + } + + public sortByTasks() { + this.doNumericSort('tasks', us => this.getNumberOfTasks(us)); + } +} diff --git a/src/assets/env.js b/src/assets/env.js index 5b334ef..8c8469b 100644 --- a/src/assets/env.js +++ b/src/assets/env.js @@ -1,7 +1,7 @@ (function(window) { window["env"] = window["env"] || {}; - + // Environment variables - window["env"]["apiUrl"] = "http://localhost:5001"; + window["env"]["apiUrl"] = "https://localhost:5001"; window["env"]["debug"] = false; - })(this); \ No newline at end of file + })(this);