feat: added delete project option and generic confirm dialog
This commit is contained in:
parent
c9987b48b9
commit
a1fa0141ab
|
@ -27,6 +27,7 @@ import {KeycloakService} from 'keycloak-angular';
|
||||||
import {httpInterceptorProviders} from '@shared/interceptors';
|
import {httpInterceptorProviders} from '@shared/interceptors';
|
||||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||||
|
import {ConfirmDialogModule} from '@shared/modules/confirm-dialog/confirm-dialog.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -45,6 +46,7 @@ import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||||
NbIconModule,
|
NbIconModule,
|
||||||
NbButtonModule,
|
NbButtonModule,
|
||||||
NbEvaIconsModule,
|
NbEvaIconsModule,
|
||||||
|
ConfirmDialogModule,
|
||||||
NgxsModule.forRoot([SessionState], {developmentMode: !environment.production}),
|
NgxsModule.forRoot([SessionState], {developmentMode: !environment.production}),
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
TranslateModule.forRoot({
|
TranslateModule.forRoot({
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<div fxLayout="row" fxLayoutGap="2rem">
|
<div fxLayout="row" fxLayoutGap="2rem">
|
||||||
<div *ngFor="let project of projects | async">
|
<div *ngFor="let project of projects | async">
|
||||||
<nb-card accent="success" class="project-card">
|
<nb-card class="project-card" accent="success">
|
||||||
<nb-card-header fxLayoutAlign="start center"
|
<nb-card-header fxLayoutAlign="start center"
|
||||||
routerLink="id"
|
routerLink="id"
|
||||||
fragment="{{project.id}}"
|
fragment="{{project.id}}"
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
status="danger"
|
status="danger"
|
||||||
size="small"
|
size="small"
|
||||||
class="project-button"
|
class="project-button"
|
||||||
(click)="onClickDeleteProject()">
|
(click)="onClickDeleteProject(project)">
|
||||||
<fa-icon [icon]="fa.faTrash"></fa-icon>
|
<fa-icon [icon]="fa.faTrash"></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
@import '../../assets/@theme/styles/themes';
|
||||||
|
|
||||||
.project-card {
|
.project-card {
|
||||||
max-width: 22rem;
|
max-width: 22rem;
|
||||||
width: 22rem;
|
width: 22rem;
|
||||||
|
@ -33,6 +35,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.project-card:hover {
|
||||||
|
background-color: nb-theme(color-info-transparent-default);
|
||||||
|
margin-top: +0.625rem;
|
||||||
|
transform: scale(1.025)
|
||||||
|
}
|
||||||
|
|
||||||
.project-link:hover {
|
.project-link:hover {
|
||||||
cursor: pointer !important;
|
cursor: pointer !important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,9 @@ import {BehaviorSubject, Observable} from 'rxjs';
|
||||||
import {untilDestroyed} from 'ngx-take-until-destroy';
|
import {untilDestroyed} from 'ngx-take-until-destroy';
|
||||||
import {ProjectService} from '@shared/services/project.service';
|
import {ProjectService} from '@shared/services/project.service';
|
||||||
import {NotificationService, PopupType} from '@shared/services/notification.service';
|
import {NotificationService, PopupType} from '@shared/services/notification.service';
|
||||||
import {filter, mergeMap, tap} from 'rxjs/operators';
|
import {catchError, filter, mergeMap, switchMap, tap} from 'rxjs/operators';
|
||||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||||
import {ProjectDialogComponent} from '@shared/modules/project-dialog/project-dialog.component';
|
import {ProjectDialogComponent} from '@shared/modules/project-dialog/project-dialog.component';
|
||||||
import {NB_DIALOG_CONFIG} from '@nebular/theme/components/dialog/dialog-config';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-project-overview',
|
selector: 'app-project-overview',
|
||||||
|
@ -80,8 +79,30 @@ export class ProjectOverviewComponent implements OnInit, OnDestroy {
|
||||||
console.log('to be implemented...');
|
console.log('to be implemented...');
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickDeleteProject(): void {
|
onClickDeleteProject(project: Project): void {
|
||||||
console.log('to be implemented...');
|
const message = {
|
||||||
|
title: 'project.delete.title',
|
||||||
|
key: 'project.delete.key',
|
||||||
|
data: {name: project.title},
|
||||||
|
};
|
||||||
|
this.dialogService.openConfirmDialog(
|
||||||
|
message
|
||||||
|
).onClose.pipe(
|
||||||
|
filter((confirm) => !!confirm),
|
||||||
|
switchMap(() => this.projectService.deleteProjectById(project.id)),
|
||||||
|
catchError(() => {
|
||||||
|
this.notificationService.showPopup('project.popup.delete.failed', PopupType.FAILURE);
|
||||||
|
return [];
|
||||||
|
}),
|
||||||
|
untilDestroyed(this)
|
||||||
|
).subscribe({
|
||||||
|
next: () => {
|
||||||
|
this.loadProjects();
|
||||||
|
this.notificationService.showPopup('project.popup.delete.success', PopupType.SUCCESS);
|
||||||
|
}, error: error => {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
isLoading(): Observable<boolean> {
|
isLoading(): Observable<boolean> {
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
.dialog-header {
|
||||||
|
height: 6.75vh;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
|
||||||
|
.dialog-headline {
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-body {
|
||||||
|
font-size: 1.15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-button {
|
||||||
|
width: 4.5rem;
|
||||||
|
height: 2.5rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
|
@ -1,9 +1,3 @@
|
||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright Akveo. All Rights Reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@mixin ngx-pace-theme() {
|
@mixin ngx-pace-theme() {
|
||||||
|
|
||||||
.pace .pace-progress {
|
.pace .pace-progress {
|
||||||
|
|
|
@ -3,7 +3,10 @@
|
||||||
"action.login": "Einloggen",
|
"action.login": "Einloggen",
|
||||||
"action.retry": "Erneut Versuchen",
|
"action.retry": "Erneut Versuchen",
|
||||||
"action.save": "Speichern",
|
"action.save": "Speichern",
|
||||||
|
"action.confirm": "Bestätigen",
|
||||||
"action.cancel": "Abbrechen",
|
"action.cancel": "Abbrechen",
|
||||||
|
"action.yes": "Ja",
|
||||||
|
"action.no": "Nein",
|
||||||
"username": "Nutzername",
|
"username": "Nutzername",
|
||||||
"password": "Passwort"
|
"password": "Passwort"
|
||||||
},
|
},
|
||||||
|
@ -33,10 +36,16 @@
|
||||||
"create": {
|
"create": {
|
||||||
"header": "Neues Projekt erstellen"
|
"header": "Neues Projekt erstellen"
|
||||||
},
|
},
|
||||||
|
"delete": {
|
||||||
|
"title": "Projekt löschen",
|
||||||
|
"key": "Möchten Sie das Projekt \"{{name}}\" unwiderruflich löschen?"
|
||||||
|
},
|
||||||
"popup": {
|
"popup": {
|
||||||
"not.found": "Keine Projekte gefunden",
|
"not.found": "Keine Projekte gefunden",
|
||||||
"save.success": "Projekt erfolgreich gespeichert",
|
"save.success": "Projekt erfolgreich gespeichert",
|
||||||
"save.failed": "Projekt konnte nicht gespeichert werden"
|
"save.failed": "Projekt konnte nicht gespeichert werden",
|
||||||
|
"delete.success": "Projekt erfolgreich gelöscht",
|
||||||
|
"delete.failed": "Projekt konnte nicht gelöscht werden"
|
||||||
},
|
},
|
||||||
"title.label": "Projekt Titel",
|
"title.label": "Projekt Titel",
|
||||||
"client.label": "Name des Auftraggebers",
|
"client.label": "Name des Auftraggebers",
|
||||||
|
|
|
@ -2,8 +2,11 @@
|
||||||
"global": {
|
"global": {
|
||||||
"action.login": "Login",
|
"action.login": "Login",
|
||||||
"action.retry": "Try again",
|
"action.retry": "Try again",
|
||||||
|
"action.confirm": "Confirm",
|
||||||
"action.save": "Save",
|
"action.save": "Save",
|
||||||
"action.cancel": "Cancel",
|
"action.cancel": "Cancel",
|
||||||
|
"action.yes": "Yes",
|
||||||
|
"action.no": "No",
|
||||||
"username": "Username",
|
"username": "Username",
|
||||||
"password": "Password"
|
"password": "Password"
|
||||||
},
|
},
|
||||||
|
@ -33,10 +36,16 @@
|
||||||
"create": {
|
"create": {
|
||||||
"header": "Create New Project"
|
"header": "Create New Project"
|
||||||
},
|
},
|
||||||
|
"delete": {
|
||||||
|
"title": "Delete Project",
|
||||||
|
"key": "Do you want to permanently delete the project \"{{name}}\"?"
|
||||||
|
},
|
||||||
"popup": {
|
"popup": {
|
||||||
"not.found": "No projects found",
|
"not.found": "No projects found",
|
||||||
"save.success": "Project saved successfully",
|
"save.success": "Project saved successfully",
|
||||||
"save.failed": "Project could not be saved"
|
"save.failed": "Project could not be saved",
|
||||||
|
"delete.success": "Project deleted successfully",
|
||||||
|
"delete.failed": "Project could not be deleted"
|
||||||
},
|
},
|
||||||
"title.label": "Project Title",
|
"title.label": "Project Title",
|
||||||
"client.label": "Name of Client",
|
"client.label": "Name of Client",
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
<nb-card>
|
||||||
|
<nb-card-header fxLayoutAlign="start center" class="dialog-header confirm">
|
||||||
|
{{ data?.title | translate }}
|
||||||
|
</nb-card-header>
|
||||||
|
<nb-card-body class="dialog-body">
|
||||||
|
{{ data?.key | translate: data?.data }}
|
||||||
|
</nb-card-body>
|
||||||
|
<nb-card-footer fxLayout="row" fxLayoutGap="1.5rem" fxLayoutAlign="end end">
|
||||||
|
<button nbButton size="small"
|
||||||
|
class="dialog-button"
|
||||||
|
status="danger"
|
||||||
|
(click)="onClickConfirm()">
|
||||||
|
{{ 'global.action.yes' | translate }}
|
||||||
|
</button>
|
||||||
|
<button nbButton size="small"
|
||||||
|
class="dialog-button"
|
||||||
|
(click)="onClickClose()">
|
||||||
|
{{ 'global.action.no' | translate }}
|
||||||
|
</button>
|
||||||
|
</nb-card-footer>
|
||||||
|
</nb-card>
|
|
@ -0,0 +1 @@
|
||||||
|
@import "../../../assets/@theme/styles/_dialog.scss";
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ConfirmDialogComponent } from './confirm-dialog.component';
|
||||||
|
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||||
|
import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock';
|
||||||
|
import {NbButtonModule, NbCardModule, NbDialogRef, NbLayoutModule} from '@nebular/theme';
|
||||||
|
import {CommonModule} from '@angular/common';
|
||||||
|
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||||
|
import {HttpLoaderFactory} from '../../../app/common-app.module';
|
||||||
|
import {HttpClient, HttpClientModule} from '@angular/common/http';
|
||||||
|
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||||
|
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||||
|
|
||||||
|
describe('ConfirmDialogComponent', () => {
|
||||||
|
let component: ConfirmDialogComponent;
|
||||||
|
let fixture: ComponentFixture<ConfirmDialogComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [
|
||||||
|
ConfirmDialogComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
NbLayoutModule,
|
||||||
|
NbCardModule,
|
||||||
|
NbButtonModule,
|
||||||
|
FlexLayoutModule,
|
||||||
|
TranslateModule.forRoot({
|
||||||
|
loader: {
|
||||||
|
provide: TranslateLoader,
|
||||||
|
useFactory: HttpLoaderFactory,
|
||||||
|
deps: [HttpClient]
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
HttpClientModule,
|
||||||
|
HttpClientTestingModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{provide: DialogService, useClass: DialogServiceMock},
|
||||||
|
{provide: NbDialogRef, useValue: {}}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ConfirmDialogComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,28 @@
|
||||||
|
import {Component, Input} from '@angular/core';
|
||||||
|
import {NbDialogRef} from '@nebular/theme';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-confirm-dialog',
|
||||||
|
templateUrl: './confirm-dialog.component.html',
|
||||||
|
styleUrls: ['./confirm-dialog.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfirmDialogComponent {
|
||||||
|
/**
|
||||||
|
* @param data contains all relevant information the dialog needs
|
||||||
|
* @param data.title The translation key for the dialog title
|
||||||
|
* @param data.key The translation key for the shown message
|
||||||
|
* @param data.data The data that may be used in the message translation key
|
||||||
|
*/
|
||||||
|
@Input() data: any;
|
||||||
|
|
||||||
|
constructor(protected dialogRef: NbDialogRef<any>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickConfirm(): void {
|
||||||
|
this.dialogRef.close({confirm: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickClose(): void {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import {ConfirmDialogComponent} from '@shared/modules/confirm-dialog/confirm-dialog.component';
|
||||||
|
import {NbButtonModule, NbCardModule} from '@nebular/theme';
|
||||||
|
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||||
|
import {TranslateModule} from '@ngx-translate/core';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
ConfirmDialogComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
NbCardModule,
|
||||||
|
NbButtonModule,
|
||||||
|
FlexLayoutModule,
|
||||||
|
TranslateModule
|
||||||
|
],
|
||||||
|
entryComponents: [
|
||||||
|
ConfirmDialogComponent
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class ConfirmDialogModule { }
|
|
@ -1,5 +1,5 @@
|
||||||
<nb-card #dialog accent="primary" class="project-dialog">
|
<nb-card #dialog accent="primary" class="project-dialog">
|
||||||
<nb-card-header fxLayoutAlign="start center" class="project-dialog-header">
|
<nb-card-header fxLayoutAlign="start center" class="dialog-header">
|
||||||
{{ 'project.create.header' | translate }}
|
{{ 'project.create.header' | translate }}
|
||||||
</nb-card-header>
|
</nb-card-header>
|
||||||
<nb-card-body>
|
<nb-card-body>
|
||||||
|
@ -39,10 +39,10 @@
|
||||||
</form>
|
</form>
|
||||||
</nb-card-body>
|
</nb-card-body>
|
||||||
<nb-card-footer fxLayout="row" fxLayoutGap="1.5rem" fxLayoutAlign="end end">
|
<nb-card-footer fxLayout="row" fxLayoutGap="1.5rem" fxLayoutAlign="end end">
|
||||||
<button nbButton status="success" [disabled]="formIsEmptyOrInvalid()" (click)="onClickSave(projectFormGroup.value)">
|
<button nbButton status="success" size="small" class="dialog-button" [disabled]="formIsEmptyOrInvalid()" (click)="onClickSave(projectFormGroup.value)">
|
||||||
{{ 'global.action.save' | translate}}
|
{{ 'global.action.save' | translate}}
|
||||||
</button>
|
</button>
|
||||||
<button nbButton status="danger" (click)="onClickClose()">
|
<button nbButton status="danger" size="small" class="dialog-button"(click)="onClickClose()">
|
||||||
{{ 'global.action.cancel' | translate }}
|
{{ 'global.action.cancel' | translate }}
|
||||||
</button>
|
</button>
|
||||||
</nb-card-footer>
|
</nb-card-footer>
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
@import "../../../assets/@theme/styles/_dialog.scss";
|
||||||
|
|
||||||
.project-dialog {
|
.project-dialog {
|
||||||
width: 24rem;
|
width: 24rem;
|
||||||
height: 31rem;
|
height: 31rem;
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
export interface DialogMessage {
|
||||||
|
key: string;
|
||||||
|
data?: any;
|
||||||
|
title?: string;
|
||||||
|
inputPlaceholderKey?: string;
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||||
import {ComponentType} from '@angular/cdk/overlay';
|
import {ComponentType} from '@angular/cdk/overlay';
|
||||||
import {TemplateRef} from '@angular/core';
|
import {TemplateRef} from '@angular/core';
|
||||||
import {NbDialogConfig, NbDialogRef} from '@nebular/theme';
|
import {NbDialogConfig, NbDialogRef} from '@nebular/theme';
|
||||||
|
import {DialogMessage} from '@shared/services/dialog-service/dialog-message';
|
||||||
|
|
||||||
export class DialogServiceMock implements Required<DialogService> {
|
export class DialogServiceMock implements Required<DialogService> {
|
||||||
|
|
||||||
|
@ -13,4 +14,8 @@ export class DialogServiceMock implements Required<DialogService> {
|
||||||
): NbDialogRef<T> {
|
): NbDialogRef<T> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openConfirmDialog(message: DialogMessage): NbDialogRef<any> {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import {Injectable, TemplateRef} from '@angular/core';
|
import {Injectable, TemplateRef} from '@angular/core';
|
||||||
import {NbDialogConfig, NbDialogRef, NbDialogService} from '@nebular/theme';
|
import {NbDialogConfig, NbDialogRef, NbDialogService} from '@nebular/theme';
|
||||||
import {ComponentType} from '@angular/cdk/overlay';
|
import {ComponentType} from '@angular/cdk/overlay';
|
||||||
|
import {DialogMessage} from '@shared/services/dialog-service/dialog-message';
|
||||||
|
import {ConfirmDialogComponent} from '@shared/modules/confirm-dialog/confirm-dialog.component';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
|
@ -25,4 +27,19 @@ export class DialogService {
|
||||||
closeOnBackdropClick: config?.closeOnBackdropClick || false,
|
closeOnBackdropClick: config?.closeOnBackdropClick || false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param message.key The translation key for the shown message
|
||||||
|
* @param message.data The data that may be used in the message translation key (Set it null if it's not required in the key)
|
||||||
|
* @param message.title The translation key for the dialog title
|
||||||
|
*/
|
||||||
|
openConfirmDialog(message: DialogMessage): NbDialogRef<ConfirmDialogComponent> {
|
||||||
|
return this.dialog.open(ConfirmDialogComponent, {
|
||||||
|
closeOnEsc: false,
|
||||||
|
hasScroll: false,
|
||||||
|
autoFocus: false,
|
||||||
|
closeOnBackdropClick: false,
|
||||||
|
context: {data: message}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {ProjectService} from '@shared/services/project.service';
|
import {ProjectService} from '@shared/services/project.service';
|
||||||
import {HttpClient} from '@angular/common/http';
|
import {HttpClient} from '@angular/common/http';
|
||||||
import {Observable, of} from 'rxjs';
|
import {Observable, of} from 'rxjs';
|
||||||
import {Project} from '@shared/models/project.model';
|
import {Project, SaveProjectDialogBody} from '@shared/models/project.model';
|
||||||
|
|
||||||
|
|
||||||
export class ProjectServiceMock implements Required<ProjectService> {
|
export class ProjectServiceMock implements Required<ProjectService> {
|
||||||
|
@ -12,7 +12,11 @@ export class ProjectServiceMock implements Required<ProjectService> {
|
||||||
return of([]);
|
return of([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
saveProject(): Observable<Project> {
|
saveProject(saveProject: SaveProjectDialogBody): Observable<Project> {
|
||||||
|
return of();
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteProjectById(projectId: string): Observable<string> {
|
||||||
return of();
|
return of();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ describe('ProjectService', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getProjects', () => {
|
describe('getProjects', () => {
|
||||||
|
// arrange
|
||||||
const mockProject: Project = {
|
const mockProject: Project = {
|
||||||
id: '56c47c56-3bcd-45f1-a05b-c197dbd33111',
|
id: '56c47c56-3bcd-45f1-a05b-c197dbd33111',
|
||||||
client: 'E Corp',
|
client: 'E Corp',
|
||||||
|
@ -52,6 +53,7 @@ describe('ProjectService', () => {
|
||||||
}];
|
}];
|
||||||
|
|
||||||
it('should get Projects', (done) => {
|
it('should get Projects', (done) => {
|
||||||
|
// act
|
||||||
service.getProjects().subscribe((projects) => {
|
service.getProjects().subscribe((projects) => {
|
||||||
expect(projects[0].id).toEqual(mockProject.id);
|
expect(projects[0].id).toEqual(mockProject.id);
|
||||||
expect(projects[0].client).toEqual(mockProject.client);
|
expect(projects[0].client).toEqual(mockProject.client);
|
||||||
|
@ -62,6 +64,7 @@ describe('ProjectService', () => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// assert
|
||||||
const mockReq = httpMock.expectOne(`${apiBaseURL}`);
|
const mockReq = httpMock.expectOne(`${apiBaseURL}`);
|
||||||
expect(mockReq.cancelled).toBe(false);
|
expect(mockReq.cancelled).toBe(false);
|
||||||
expect(mockReq.request.responseType).toEqual('json');
|
expect(mockReq.request.responseType).toEqual('json');
|
||||||
|
@ -72,6 +75,7 @@ describe('ProjectService', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('saveProject', () => {
|
describe('saveProject', () => {
|
||||||
|
// arrange
|
||||||
const mockSaveProjectDialogBody: SaveProjectDialogBody = {
|
const mockSaveProjectDialogBody: SaveProjectDialogBody = {
|
||||||
client: 'E Corp',
|
client: 'E Corp',
|
||||||
title: 'Some Mock API (v1.0) Scanning',
|
title: 'Some Mock API (v1.0) Scanning',
|
||||||
|
@ -97,17 +101,40 @@ describe('ProjectService', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
it('should save project', (done) => {
|
it('should save project', (done) => {
|
||||||
|
// act
|
||||||
service.saveProject(mockSaveProjectDialogBody).subscribe(
|
service.saveProject(mockSaveProjectDialogBody).subscribe(
|
||||||
value => {
|
value => {
|
||||||
expect(value).toEqual(mockProject);
|
expect(value).toEqual(mockProject);
|
||||||
done();
|
done();
|
||||||
},
|
},
|
||||||
fail);
|
fail);
|
||||||
|
// assert
|
||||||
const req = httpMock.expectOne(`${apiBaseURL}`);
|
const req = httpMock.expectOne(`${apiBaseURL}`);
|
||||||
expect(req.request.method).toBe('POST');
|
expect(req.request.method).toBe('POST');
|
||||||
req.flush(mockProject);
|
req.flush(mockProject);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('deleteProject', () => {
|
||||||
|
// arrange
|
||||||
|
const mockProjectId = '56c47c56-3bcd-45f1-a05b-c197dbd33111';
|
||||||
|
|
||||||
|
const httpResponse = {
|
||||||
|
id: '56c47c56-3bcd-45f1-a05b-c197dbd33111'
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should delete project', (done) => {
|
||||||
|
// act
|
||||||
|
service.deleteProjectById(mockProjectId).subscribe(
|
||||||
|
value => {
|
||||||
|
expect(value).toEqual(httpResponse.id);
|
||||||
|
done();
|
||||||
|
},
|
||||||
|
fail);
|
||||||
|
// assert
|
||||||
|
const req = httpMock.expectOne(`${apiBaseURL}/${mockProjectId}`);
|
||||||
|
expect(req.request.method).toBe('DELETE');
|
||||||
|
req.flush(httpResponse.id);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,6 +14,9 @@ export class ProjectService {
|
||||||
constructor(private http: HttpClient) {
|
constructor(private http: HttpClient) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Projects
|
||||||
|
*/
|
||||||
public getProjects(): Observable<Project[]> {
|
public getProjects(): Observable<Project[]> {
|
||||||
return this.http.get<Project[]>(`${this.apiBaseURL}`);
|
return this.http.get<Project[]>(`${this.apiBaseURL}`);
|
||||||
}
|
}
|
||||||
|
@ -25,4 +28,12 @@ export class ProjectService {
|
||||||
public saveProject(project: SaveProjectDialogBody): Observable<Project> {
|
public saveProject(project: SaveProjectDialogBody): Observable<Project> {
|
||||||
return this.http.post<Project>(`${this.apiBaseURL}`, project);
|
return this.http.post<Project>(`${this.apiBaseURL}`, project);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete Project
|
||||||
|
* @param projectId the id of the project
|
||||||
|
*/
|
||||||
|
public deleteProjectById(projectId: string): Observable<string> {
|
||||||
|
return this.http.delete<string>(`${this.apiBaseURL}/${projectId}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue