diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..bb7c22f --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,29 @@ +image: docker:dind + +services: + - name: docker:dind + entrypoint: ["env", "-u", "DOCKER_HOST"] + command: ["dockerd-entrypoint.sh"] +variables: + DOCKER_HOST: tcp://docker:2375/ + DOCKER_DRIVER: overlay2 + DOCKER_TLS_CERTDIR: "" + +before_script: + - echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY + + +build: + stage: build + script: + - docker build . -t frontend:$CI_COMMIT_SHORT_SHA + - docker tag frontend:$CI_COMMIT_SHORT_SHA $CI_REGISTRY/taskboard/frontend:$CI_COMMIT_SHORT_SHA + - docker push $CI_REGISTRY/taskboard/frontend:$CI_COMMIT_SHORT_SHA + - docker tag frontend:$CI_COMMIT_SHORT_SHA $CI_REGISTRY/taskboard/frontend:latest + - docker push $CI_REGISTRY/taskboard/frontend:latest + tags: + - frontend + only: + refs: + - tags + - master diff --git a/Dockerfile b/Dockerfile index 5a0fa3e..2bccf44 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,5 +14,7 @@ RUN npm run build # Stage 2: Package up with the webserver FROM nginx:alpine AS final +ENV API_URL "http://localhost:5001" COPY --from=build /build/dist/frontend /usr/share/nginx/html +COPY nginx.conf /etc/nginx/nginx.conf CMD ["/bin/sh", "-c", "envsubst < /usr/share/nginx/html/assets/env.template.js > /usr/share/nginx/html/assets/env.js && exec nginx -g 'daemon off;'"] \ No newline at end of file diff --git a/README.md b/README.md index 2a8d22d..cf08cb1 100644 --- a/README.md +++ b/README.md @@ -31,15 +31,14 @@ To get more help on the Angular CLI use `ng help` or go check out the [Angular C > Prerequisite: Docker and/or Docker Compose have to be installed on your system
> The Docker installation instructions for most operation systems can be found here: [https://docs.docker.com/get-docker/](https://docs.docker.com/get-docker/)
> The Docker Compose installation instructions for most operation systems can be found here: [https://docs.docker.com/compose/install/](https://docs.docker.com/compose/install/) +> To use the prebuild images log into the private registry: docker login -u testuser -p LpH2v1mShPpC8Xeimkd2AISA03zaC+vq scrumdev.azurecr.io ### Quick Deployment with Docker Compose 1. Clone the git repo 2. Open the cloned repo's folder in a shell of your choice (as long as it supports Docker) -3. Tell Docker Compose to build - if it hasn't already been built - and run the app with `docker-compose up` +3. Tell Docker Compose to run the app alongside a database with `docker-compose up` Other useful commands: -* Just build: `docker-compose build` -* Build before running: `docker-compose up --build` * Run attached (in the background): `docker-compose up -d` * Stop: `docker-compose down` * Restart: `docker-compose restart` @@ -47,9 +46,9 @@ Other useful commands: ### Build the Container yourself (and run it) 1. Clone the git repo 2. Open the cloned repo's folder in a shell of your choice (as long as it supports Docker) -3. Tell Docker to build the app under the name "frontend" with `docker build -t taskboard_frontend .` -4. Tell Docker to run the app on port 8080 with `docker run -p 8080:80 taskboard_frontend` +3. Tell Docker to build the app under the name "taskboard/frontend" with `docker build -t taskboard/frontend .` +4. Tell Docker to run the app on port 8080 with `docker run -p 8080:80 taskboard/frontend` Other useful commands: -* Run detached: `docker run -d -p 8080:80 taskboard_frontend` -* Run under specified name: `docker run -p 8080:80 --name frontend taskboard_frontend` \ No newline at end of file +* Run detached: `docker run -d -p 8080:80 taskboard/frontend` +* Run under specified name: `docker run -p 8080:80 --name frontend taskboard/frontend` \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index d542488..5ea3353 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,10 +2,11 @@ version: "3" services: app: - build: - context: . + image: scrumdev.azurecr.io/taskboard/frontend:latest restart: unless-stopped networks: - default ports: - - "8080:80" \ No newline at end of file + - "8080:80" + environment: + API_URL: http://localhost:5001 \ No newline at end of file diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..6679ffa --- /dev/null +++ b/nginx.conf @@ -0,0 +1,15 @@ +worker_processes 1; + +events { worker_connections 1024; } + +http { + server { + listen 80; + root /usr/share/nginx/html; + include /etc/nginx/mime.types; + + location / { + try_files $uri /index.html; + } + } +} \ No newline at end of file diff --git a/package.json b/package.json index 22bbf00..f1353ed 100644 --- a/package.json +++ b/package.json @@ -45,5 +45,13 @@ "ts-node": "~8.3.0", "tslint": "~6.1.0", "typescript": "~3.8.3" - } + }, + "description": "This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 9.1.7.", + "main": "karma.conf.js", + "repository": { + "type": "git", + "url": "https://git.informatik.fh-nuernberg.de/scrum-taskboard/frontend.git" + }, + "author": "", + "license": "ISC" } diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 3df3eb8..959d1cd 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -4,7 +4,6 @@ import { Routes, RouterModule } from '@angular/router'; import {UserstoryTableComponent} from './userstory-table/userstory-table.component'; import {TaskTableComponent} from './task-table/task-table.component'; - const routes: Routes = [ { path: 'tasks', component: TaskTableComponent }, { path: 'userstories', component: UserstoryTableComponent }, @@ -12,7 +11,7 @@ const routes: Routes = [ ]; @NgModule({ - imports: [RouterModule.forRoot(routes)], - exports: [RouterModule] + imports: [ RouterModule.forRoot(routes) ], + exports: [ RouterModule ] }) -export class AppRoutingModule { } +export class AppRoutingModule {} diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 3824996..95551f4 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -9,6 +9,7 @@ import { AppComponent } from './app.component'; import { BackendService } from './services/backend.service'; import { TaskFormComponent } from './task-form/task-form.component'; import { UserstoryFormComponent } from './userstory-form/userstory-form.component'; +import { SprintFormComponent } from './sprint-form/sprint-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'; @@ -20,7 +21,8 @@ import { TaskTableComponent } from './task-table/task-table.component'; TaskFormComponent, UserstoryTableComponent, UserstoryFormComponent, - UserstoryTableComponent + UserstoryTableComponent, + SprintFormComponent ], imports: [ BrowserModule, diff --git a/src/app/services/backend.service.ts b/src/app/services/backend.service.ts index 6d52bf4..ed9c838 100644 --- a/src/app/services/backend.service.ts +++ b/src/app/services/backend.service.ts @@ -232,7 +232,7 @@ export interface ScrumUserstory { export interface ScrumSprint{ id?: number; title: string; - description: string; + description?: string; startDate: Date; endDate: Date; project: number; diff --git a/src/app/sprint-component/sprint.component.css b/src/app/sprint-component/sprint.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/sprint-component/sprint.component.html b/src/app/sprint-component/sprint.component.html new file mode 100644 index 0000000..9190d3a --- /dev/null +++ b/src/app/sprint-component/sprint.component.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/app/sprint-component/sprint.component.ts b/src/app/sprint-component/sprint.component.ts new file mode 100644 index 0000000..d47b86b --- /dev/null +++ b/src/app/sprint-component/sprint.component.ts @@ -0,0 +1,54 @@ +import { Component, OnInit } from '@angular/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { BackendService, ScrumSprint } from '../services/backend.service'; +import { SprintFormComponent } from '../sprint-form/sprint-form.component'; + +@Component({ + selector: 'app-sprint', + templateUrl: './sprint.component.html', + styleUrls: ['./sprint.component.css'] +}) +export class SprintComponent implements OnInit { + + public sprints: ScrumSprint[] = []; + + constructor(private backendService: BackendService, private modalService: NgbModal) { + backendService.getSprints().subscribe(response => { + if (response.status > 399) { + alert('Fehler'); + } + else { + this.sprints.push(...response.body); + } + }); + } + + ngOnInit(): void { + } + + public deleteSprint(sprint: ScrumSprint) { + this.backendService.deleteSprint(sprint).subscribe(response => { + if (response.status > 399) { + alert('Fehler'); + } + }); + const index = this.sprints.indexOf(sprint); + if (index !== -1) { + this.sprints.splice(index, 1); + } + } + + public openSprintForm(editSprint: ScrumSprint) { + const modalRef = this.modalService.open(SprintFormComponent, { + backdrop: 'static', + keyboard: true, + }); + if (editSprint === null) { + modalRef.result.then(result => { + this.sprints.push(result); + }); + } + modalRef.componentInstance.userstory = editSprint; + } + +} diff --git a/src/app/sprint-form/sprint-form.component.css b/src/app/sprint-form/sprint-form.component.css new file mode 100644 index 0000000..717de4c --- /dev/null +++ b/src/app/sprint-form/sprint-form.component.css @@ -0,0 +1,4 @@ +.modal-footer { + border-top: 0px solid; + padding-top: 5%; +} \ No newline at end of file diff --git a/src/app/sprint-form/sprint-form.component.html b/src/app/sprint-form/sprint-form.component.html new file mode 100644 index 0000000..d8b7ecd --- /dev/null +++ b/src/app/sprint-form/sprint-form.component.html @@ -0,0 +1,33 @@ + \ No newline at end of file diff --git a/src/app/sprint-form/sprint-form.component.ts b/src/app/sprint-form/sprint-form.component.ts new file mode 100644 index 0000000..f19c1bb --- /dev/null +++ b/src/app/sprint-form/sprint-form.component.ts @@ -0,0 +1,62 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { + BackendService, + ScrumTask, + Priority, + ScrumStatus, + ScrumCategory, + ScrumUser, + ScrumProject, + ScrumUserstory, + ScrumSprint +} from '../services/backend.service'; +import { Observable } from 'rxjs'; +import { HttpResponse } from '@angular/common/http'; + +@Component({ + selector: 'app-task-form', + templateUrl: './sprint-form.component.html', + styleUrls: ['./sprint-form.component.css'], +}) +export class SprintFormComponent implements OnInit { + @Input() public sprint: ScrumSprint; + public editing: Boolean; + public sprintid: string; + + constructor( + private backendService: BackendService, + private activeModalService: NgbActiveModal + ) { } + + ngOnInit(): void { + if (this.sprint === null || this.sprint === undefined) { + this.sprint = { title: '', startDate: new Date(), endDate: new Date(), project: 0 }; //project id: static counter? + this.editing = false; + } else { + this.editing = true; + } + document.getElementById('titleField').focus(); + } + + onSubmit() { + if (this.editing) { + this.backendService.putSprint(this.sprint).subscribe((response) => { + if (response.status > 399) { + alert('Fehler'); + } + }); + } else { + this.backendService.postSprint(this.sprint).subscribe((response) => { + if (response.status > 399) { + alert('Fehler'); + } + }); + } + this.activeModalService.close(this.sprint); + } + + onClose() { + this.activeModalService.dismiss(this.sprint); + } +} diff --git a/src/app/task-form/task-form.component.css b/src/app/task-form/task-form.component.css index e69de29..2b8a6fe 100644 --- a/src/app/task-form/task-form.component.css +++ b/src/app/task-form/task-form.component.css @@ -0,0 +1,13 @@ +.modal-footer { + border-top: 0px solid; + padding-top: 5%; +} +.modal-content { + width: 1040px; + right: 55%; + border: 0px; +} + +.modal { + margin: 0 auto; +} diff --git a/src/app/task-form/task-form.component.html b/src/app/task-form/task-form.component.html index b0a5f4e..d63239f 100644 --- a/src/app/task-form/task-form.component.html +++ b/src/app/task-form/task-form.component.html @@ -1,30 +1,68 @@