diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 5b68d94c..74e82e1a 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -28,8 +28,9 @@ import { ApplianceService } from "./services/appliance.service"; import { LinkService } from "./services/link.service"; import { ProjectsComponent } from './components/projects/projects.component'; +import { AddBlankProjectDialogComponent } from './components/projects/add-blank-project-dialog/add-blank-project-dialog.component'; import { ImportProjectDialogComponent } from './components/projects/import-project-dialog/import-project-dialog.component'; -import { ImportProjectConfirmationDialogComponent} from './components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component'; +import { ConfirmationDialogComponent} from './components/projects/confirmation-dialog/confirmation-dialog.component'; import { DefaultLayoutComponent } from './layouts/default-layout/default-layout.component'; import { ProgressDialogComponent } from './common/progress-dialog/progress-dialog.component'; import { AppComponent } from './app.component'; @@ -70,6 +71,7 @@ import { SnapshotsComponent } from './components/snapshots/snapshots.component'; import { SnapshotMenuItemComponent } from './components/snapshots/snapshot-menu-item/snapshot-menu-item.component'; import { MATERIAL_IMPORTS } from './material.imports'; import { DrawingService } from './services/drawing.service'; +import { ProjectNameValidator } from './components/projects/models/projectNameValidator'; if (environment.production) { @@ -94,8 +96,9 @@ if (environment.production) { SnapshotMenuItemComponent, SnapshotsComponent, ProjectsComponent, + AddBlankProjectDialogComponent, ImportProjectDialogComponent, - ImportProjectConfirmationDialogComponent, + ConfirmationDialogComponent, DefaultLayoutComponent, ProgressDialogComponent, NodeContextMenuComponent, @@ -153,15 +156,17 @@ if (environment.production) { InRectangleHelper, DrawingsDataSource, ServerErrorHandler, - ServerDatabase + ServerDatabase, + ProjectNameValidator ], entryComponents: [ AddServerDialogComponent, CreateSnapshotDialogComponent, ProgressDialogComponent, ApplianceListDialogComponent, + AddBlankProjectDialogComponent, ImportProjectDialogComponent, - ImportProjectConfirmationDialogComponent + ConfirmationDialogComponent ], bootstrap: [ AppComponent ] }) diff --git a/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.css b/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.css new file mode 100644 index 00000000..fd32953d --- /dev/null +++ b/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.css @@ -0,0 +1,7 @@ +.file-name-form-field { + width: 100%; +} + +.project-snackbar { + background: #2196F3; +} \ No newline at end of file diff --git a/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.html b/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.html new file mode 100644 index 00000000..83c83b24 --- /dev/null +++ b/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.html @@ -0,0 +1,12 @@ +

Create new project

+
+ + + Project name is required + Project name is incorrect + +
+ + +
+
diff --git a/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.spec.ts b/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.spec.ts new file mode 100644 index 00000000..800718e0 --- /dev/null +++ b/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.spec.ts @@ -0,0 +1,132 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { AddBlankProjectDialogComponent } from "./add-blank-project-dialog.component"; +import { Server } from "../../../models/server"; +import { ReactiveFormsModule, FormsModule } from '@angular/forms'; +import { MatDialogModule, MatInputModule, MatFormFieldModule, MatDialogRef, MAT_DIALOG_DATA, MatSnackBarModule } from '@angular/material'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { ProjectService } from '../../../services/project.service'; +import { ToasterService } from '../../../services/toaster.service'; +import { of } from 'rxjs/internal/observable/of'; +import { Project } from '../../../models/project'; +import { Router } from '@angular/router'; + +export class MockedProjectService { + public projects: Project[] = [{ + auto_close: false, + auto_open: false, + auto_start: false, + filename: "blank", + name: "blank", + path: "", + project_id: "", + scene_height: 100, + scene_width: 100, + status: "opened", + readonly: false, + show_interface_labels: false, + show_layers: false, + show_grid: false, + snap_to_grid: false, + }]; + + list() { + return of(this.projects); + } + + add(){ + return of(this.projects.pop); + } +} + +describe('AddBlankProjectDialogComponent', () => { + let component: AddBlankProjectDialogComponent; + let fixture: ComponentFixture; + let server: Server; + let router = { + navigate: jasmine.createSpy('navigate') + }; + let toaster = { + success: jasmine.createSpy('success') + }; + let dialogRef = { + close: jasmine.createSpy('close') + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + MatDialogModule, + MatFormFieldModule, + MatInputModule, + NoopAnimationsModule, + FormsModule, + ReactiveFormsModule, + MatSnackBarModule + ], + providers: [ + { provide: MatDialogRef, useValue: dialogRef }, + { provide: MAT_DIALOG_DATA }, + { provide: ProjectService, useClass: MockedProjectService }, + { provide: ToasterService, useValue: toaster }, + { provide: Router, useValue: router } + ], + declarations : [AddBlankProjectDialogComponent] + }) + .compileComponents(); + + server = new Server(); + server.ip = "localhost"; + server.port = 80; + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AddBlankProjectDialogComponent); + component = fixture.componentInstance; + component.server = server; + component.projectNameForm.controls['projectName'].setValue("ValidName"); + fixture.detectChanges(); + }) + + it('should be created', () => { + expect(fixture).toBeDefined(); + expect(component).toBeTruthy(); + }); + + it('should call adding project when name is valid', () => { + spyOn(component, "addProject"); + + component.onAddClick(); + + expect(component.addProject).toHaveBeenCalled(); + }); + + it('should sanitize file name input', () => { + component.projectNameForm.controls['projectName'].setValue("[][]"); + fixture.detectChanges(); + spyOn(component, "addProject"); + + component.onAddClick(); + + expect(component.addProject).not.toHaveBeenCalled(); + expect(component.projectNameForm.valid).toBeFalsy(); + }); + + it('should open confirmation dialog if project with the same exists', () => { + component.projectNameForm.controls['projectName'].setValue("blank"); + spyOn(component, "openConfirmationDialog"); + + component.onAddClick(); + + expect(component.openConfirmationDialog).toHaveBeenCalled(); + }); + + it('should redirect to newly created project', () => { + component.projectNameForm.controls['projectName'].setValue("validName"); + + component.addProject(); + + expect(dialogRef.close).toHaveBeenCalled(); + expect(toaster.success).toHaveBeenCalled(); + expect(router.navigate).toHaveBeenCalled(); + }); +}); diff --git a/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.ts b/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.ts new file mode 100644 index 00000000..ca41ece5 --- /dev/null +++ b/src/app/components/projects/add-blank-project-dialog/add-blank-project-dialog.component.ts @@ -0,0 +1,92 @@ +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { MatDialog, MatDialogRef } from '@angular/material'; +import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms'; +import { Project } from '../../../models/project'; +import { Server } from '../../../models/server'; +import { ProjectService } from '../../../services/project.service'; +import { v4 as uuid } from 'uuid'; +import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component'; +import { ProjectNameValidator } from '../models/projectNameValidator'; +import { ToasterService } from '../../../services/toaster.service'; + +@Component({ + selector: 'app-add-blank-project-dialog', + templateUrl: './add-blank-project-dialog.component.html', + styleUrls: ['./add-blank-project-dialog.component.css'], + providers: [ProjectNameValidator] +}) +export class AddBlankProjectDialogComponent implements OnInit { + server: Server; + projectNameForm: FormGroup; + + constructor( + public dialogRef: MatDialogRef, + private router: Router, + private dialog: MatDialog, + private projectService: ProjectService, + private toasterService: ToasterService, + private formBuilder: FormBuilder, + private projectNameValidator: ProjectNameValidator) { + this.projectNameForm = this.formBuilder.group({ + projectName: new FormControl(null, [Validators.required, projectNameValidator.get]) + }); + } + + ngOnInit() {} + + get form() { + return this.projectNameForm.controls; + } + + onAddClick() : void{ + if (this.projectNameForm.invalid){ + return; + } + this.projectService + .list(this.server) + .subscribe((projects: Project[]) => { + const projectName = this.projectNameForm.controls['projectName'].value; + let existingProject = projects.find(project => project.name === projectName); + + if (existingProject){ + this.openConfirmationDialog(existingProject); + } else { + this.addProject(); + } + }); + } + + onNoClick() : void{ + this.dialogRef.close(); + } + + addProject() : void{ + this.projectService.add(this.server, this.projectNameForm.controls['projectName'].value, uuid()) + .subscribe((project: Project) => { + this.dialogRef.close(); + this.toasterService.success(`Project ${project.name} added`) + this.router.navigate(['/server', this.server.id, 'project', project.project_id]); + }); + } + + openConfirmationDialog(existingProject: Project) { + const dialogRef = this.dialog.open(ConfirmationDialogComponent, { + width: '300px', + height: '150px', + data: { + 'existingProject': existingProject + } + }); + + dialogRef.afterClosed().subscribe((answer: boolean) => { + if (answer) { + this.projectService.close(this.server, existingProject.project_id).subscribe(() => { + this.projectService.delete(this.server, existingProject.project_id).subscribe(() => { + this.addProject(); + }); + }); + } + }); + } +} diff --git a/src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.css b/src/app/components/projects/confirmation-dialog/confirmation-dialog.component.css similarity index 100% rename from src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.css rename to src/app/components/projects/confirmation-dialog/confirmation-dialog.component.css diff --git a/src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.html b/src/app/components/projects/confirmation-dialog/confirmation-dialog.component.html similarity index 98% rename from src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.html rename to src/app/components/projects/confirmation-dialog/confirmation-dialog.component.html index 6d10a1db..34ebc2b1 100644 --- a/src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.html +++ b/src/app/components/projects/confirmation-dialog/confirmation-dialog.component.html @@ -5,4 +5,4 @@
-
+ \ No newline at end of file diff --git a/src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.spec.ts b/src/app/components/projects/confirmation-dialog/confirmation-dialog.component.spec.ts similarity index 84% rename from src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.spec.ts rename to src/app/components/projects/confirmation-dialog/confirmation-dialog.component.spec.ts index b51e949d..e548d4c5 100644 --- a/src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.spec.ts +++ b/src/app/components/projects/confirmation-dialog/confirmation-dialog.component.spec.ts @@ -2,11 +2,11 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatDialogModule, MatDialog } from "@angular/material"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; import { Component, NgModule } from '@angular/core'; -import { Project } from '../../../../models/project'; -import { ImportProjectConfirmationDialogComponent } from './import-project-confirmation-dialog.component'; +import { Project } from '../../../models/project'; +import { ConfirmationDialogComponent } from './confirmation-dialog.component'; import { OverlayContainer } from '@angular/cdk/overlay'; -describe('ImportProjectConfirmationDialogComponent', () => { +describe('ConfirmationDialogComponent', () => { let dialog: MatDialog; let overlayContainerElement: HTMLElement; @@ -53,7 +53,7 @@ describe('ImportProjectConfirmationDialogComponent', () => { } }; - dialog.open(ImportProjectConfirmationDialogComponent, config); + dialog.open(ConfirmationDialogComponent, config); noop.detectChanges(); const message = overlayContainerElement.querySelector('span'); @@ -68,7 +68,7 @@ describe('ImportProjectConfirmationDialogComponent', () => { } }; - dialog.open(ImportProjectConfirmationDialogComponent, config); + dialog.open(ConfirmationDialogComponent, config); noop.detectChanges(); const message = overlayContainerElement.querySelector('span'); @@ -83,7 +83,7 @@ describe('ImportProjectConfirmationDialogComponent', () => { } }; - let dialogRef = dialog.open(ImportProjectConfirmationDialogComponent, config); + let dialogRef = dialog.open(ConfirmationDialogComponent, config); noop.detectChanges(); const button = overlayContainerElement.querySelector('button'); spyOn(dialogRef.componentInstance.dialogRef, 'close'); @@ -100,7 +100,7 @@ describe('ImportProjectConfirmationDialogComponent', () => { } }; - let dialogRef = dialog.open(ImportProjectConfirmationDialogComponent, config); + let dialogRef = dialog.open(ConfirmationDialogComponent, config); noop.detectChanges(); const button: HTMLButtonElement = overlayContainerElement.querySelector('.confirmButton'); spyOn(dialogRef.componentInstance.dialogRef, 'close'); @@ -116,7 +116,7 @@ describe('ImportProjectConfirmationDialogComponent', () => { class NoopComponent {} const TEST_DIRECTIVES = [ - ImportProjectConfirmationDialogComponent, + ConfirmationDialogComponent, NoopComponent ]; @@ -125,7 +125,7 @@ const TEST_DIRECTIVES = [ exports: TEST_DIRECTIVES, declarations: TEST_DIRECTIVES, entryComponents: [ - ImportProjectConfirmationDialogComponent + ConfirmationDialogComponent ], }) class DialogTestModule { } diff --git a/src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.ts b/src/app/components/projects/confirmation-dialog/confirmation-dialog.component.ts similarity index 72% rename from src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.ts rename to src/app/components/projects/confirmation-dialog/confirmation-dialog.component.ts index 48036d07..645b53e7 100644 --- a/src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.ts +++ b/src/app/components/projects/confirmation-dialog/confirmation-dialog.component.ts @@ -1,18 +1,18 @@ import { Component, OnInit, Inject } from '@angular/core'; import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material"; -import { Project } from '../../../../models/project'; +import { Project } from '../../../models/project'; @Component({ selector: 'app-import-project-dialog', - templateUrl: 'import-project-confirmation-dialog.component.html', - styleUrls: ['import-project-confirmation-dialog.component.css'] + templateUrl: 'confirmation-dialog.component.html', + styleUrls: ['confirmation-dialog.component.css'] }) -export class ImportProjectConfirmationDialogComponent implements OnInit { +export class ConfirmationDialogComponent implements OnInit { private existingProject : Project; public confirmationMessage : string; public isOpen : boolean; constructor( - public dialogRef: MatDialogRef, + public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: any ){ this.existingProject = data['existingProject'] diff --git a/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts b/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts index 7ee72a8a..9840cdeb 100644 --- a/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts +++ b/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts @@ -1,11 +1,11 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { ImportProjectDialogComponent, Validator } from "./import-project-dialog.component"; +import { ImportProjectDialogComponent } from "./import-project-dialog.component"; import { Server } from "../../../models/server"; -import { MatInputModule, MatIconModule, MatSortModule, MatTableModule, MatTooltipModule, MatDialogModule, MatStepperModule, MatFormFieldModule, MatDialogRef, MatDialog, MAT_DIALOG_DATA } from "@angular/material"; +import { MatInputModule, MatIconModule, MatSortModule, MatTableModule, MatTooltipModule, MatDialogModule, MatFormFieldModule, MatDialogRef, MAT_DIALOG_DATA } from "@angular/material"; import { RouterTestingModule } from "@angular/router/testing"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -import { FileUploadModule, FileSelectDirective, FileItem, FileUploader, ParsedResponseHeaders } from "ng2-file-upload"; -import { FormsModule, ReactiveFormsModule, FormBuilder, FormControl, Validators } from '@angular/forms'; +import { FileUploadModule, FileSelectDirective, FileItem, ParsedResponseHeaders } from "ng2-file-upload"; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { DebugElement } from '@angular/core'; import { By } from '@angular/platform-browser'; import { ProjectService } from '../../../services/project.service'; @@ -31,7 +31,7 @@ export class MockedProjectService { snap_to_grid: false, }]; - list(server: Server) { + list() { return of(this.projects); } } @@ -42,7 +42,6 @@ describe('ImportProjectDialogComponent', () => { let server: Server; let debugElement: DebugElement; let fileSelectDirective: FileSelectDirective; - let formBuilder: FormBuilder; beforeEach(async(() => { TestBed.configureTestingModule({ @@ -52,7 +51,6 @@ describe('ImportProjectDialogComponent', () => { MatIconModule, MatSortModule, MatDialogModule, - MatStepperModule, MatFormFieldModule, MatInputModule, NoopAnimationsModule, @@ -73,7 +71,6 @@ describe('ImportProjectDialogComponent', () => { server = new Server(); server.ip = "localhost"; server.port = 80; - formBuilder = new FormBuilder(); })); beforeEach(() => { @@ -81,15 +78,12 @@ describe('ImportProjectDialogComponent', () => { debugElement = fixture.debugElement; component = fixture.componentInstance; component.server = server; - component.projectNameForm = formBuilder.group({ - projectName: new FormControl(null, [Validators.required, Validator.projectNameValidator]) - }); component.projectNameForm.controls['projectName'].setValue("ValidName"); fixture.detectChanges(); debugElement = fixture.debugElement.query(By.directive(FileSelectDirective)); fileSelectDirective = debugElement.injector.get(FileSelectDirective) as FileSelectDirective; - component.uploader.onErrorItem = (item: FileItem, response: string, status: number, headers: ParsedResponseHeaders) => {}; + component.uploader.onErrorItem = () => {}; }); it('should be created', () => { diff --git a/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts b/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts index e6a3ddbc..67daa81e 100644 --- a/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts +++ b/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts @@ -1,30 +1,20 @@ -import { Component, OnInit, Inject, ViewChild } from '@angular/core'; -import { MatStepper, MatDialogRef, MAT_DIALOG_DATA, MatDialog } from "@angular/material"; +import { Component, OnInit, Inject } from '@angular/core'; +import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from "@angular/material"; import { FileUploader, ParsedResponseHeaders, FileItem } from 'ng2-file-upload'; import { Server } from '../../../models/server'; import { v4 as uuid } from 'uuid'; import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms'; import { ProjectService } from '../../../services/project.service'; import { Project } from '../../../models/project'; -import { ImportProjectConfirmationDialogComponent } from './import-project-confirmation-dialog/import-project-confirmation-dialog.component'; +import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component'; import { ServerResponse } from '../../../models/serverResponse'; - -export class Validator { - static projectNameValidator(projectName) { - var pattern = new RegExp(/[~`!#$%\^&*+=\[\]\\';,/{}|\\":<>\?]/); - - if(!pattern.test(projectName.value)) { - return null; - } - - return { invalidName: true } - } -} +import { ProjectNameValidator } from '../models/projectNameValidator'; @Component({ selector: 'app-import-project-dialog', templateUrl: 'import-project-dialog.component.html', - styleUrls: ['import-project-dialog.component.css'] + styleUrls: ['import-project-dialog.component.css'], + providers: [ProjectNameValidator] }) export class ImportProjectDialogComponent implements OnInit { uploader: FileUploader; @@ -42,9 +32,10 @@ export class ImportProjectDialogComponent implements OnInit { public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: any, private formBuilder: FormBuilder, - private projectService: ProjectService){ + private projectService: ProjectService, + private projectNameValidator: ProjectNameValidator){ this.projectNameForm = this.formBuilder.group({ - projectName: new FormControl(null, [Validators.required, Validator.projectNameValidator]) + projectName: new FormControl(null, [Validators.required, projectNameValidator.get]) }); } @@ -104,7 +95,7 @@ export class ImportProjectDialogComponent implements OnInit { } openConfirmationDialog(existingProject: Project) { - const dialogRef = this.dialog.open(ImportProjectConfirmationDialogComponent, { + const dialogRef = this.dialog.open(ConfirmationDialogComponent, { width: '300px', height: '150px', data: { diff --git a/src/app/components/projects/models/projectNameValidator.ts b/src/app/components/projects/models/projectNameValidator.ts new file mode 100644 index 00000000..38725ac8 --- /dev/null +++ b/src/app/components/projects/models/projectNameValidator.ts @@ -0,0 +1,14 @@ +import { Injectable } from "@angular/core"; + +@Injectable() +export class ProjectNameValidator { + get(projectName) { + var pattern = new RegExp(/[~`!#$%\^&*+=\[\]\\';,/{}|\\":<>\?]/); + + if(!pattern.test(projectName.value)) { + return null; + } + + return { invalidName: true } + } +} \ No newline at end of file diff --git a/src/app/components/projects/projects.component.css b/src/app/components/projects/projects.component.css index d49aad69..d7d423ad 100644 --- a/src/app/components/projects/projects.component.css +++ b/src/app/components/projects/projects.component.css @@ -2,3 +2,8 @@ height: 40px; margin: 20px; } + +.add-button { + height: 40px; + margin: 20px; +} diff --git a/src/app/components/projects/projects.component.html b/src/app/components/projects/projects.component.html index e14ad2d6..2726427b 100644 --- a/src/app/components/projects/projects.component.html +++ b/src/app/components/projects/projects.component.html @@ -2,6 +2,7 @@

Projects

+
diff --git a/src/app/components/projects/projects.component.ts b/src/app/components/projects/projects.component.ts index 571d8364..fc8bead2 100644 --- a/src/app/components/projects/projects.component.ts +++ b/src/app/components/projects/projects.component.ts @@ -15,6 +15,7 @@ import { SettingsService, Settings } from "../../services/settings.service"; import { ProgressService } from "../../common/progress/progress.service"; import { ImportProjectDialogComponent } from './import-project-dialog/import-project-dialog.component'; +import { AddBlankProjectDialogComponent } from './add-blank-project-dialog/add-blank-project-dialog.component'; @Component({ selector: 'app-projects', @@ -99,6 +100,14 @@ export class ProjectsComponent implements OnInit { }); } + addBlankProject(){ + const dialogRef = this.dialog.open(AddBlankProjectDialogComponent, { + width: '550px', + }) + let instance = dialogRef.componentInstance; + instance.server = this.server; + } + importProject(){ const dialogRef = this.dialog.open(ImportProjectDialogComponent, { width: '550px', diff --git a/src/app/services/project.service.ts b/src/app/services/project.service.ts index 8fe36f63..4d4236d3 100644 --- a/src/app/services/project.service.ts +++ b/src/app/services/project.service.ts @@ -51,6 +51,11 @@ export class ProjectService { .get(server, `/projects/${project_id}/drawings`); } + add(server: Server, project_name: string, project_id: string): Observable{ + return this.httpServer + .post(server, `/projects`, { "name": project_name, "project_id": project_id}); + } + delete(server: Server, project_id: string): Observable { return this.httpServer .delete(server, `/projects/${project_id}`); diff --git a/src/app/services/toaster.service.spec.ts b/src/app/services/toaster.service.spec.ts index a5bdafd4..3c4f5c0b 100644 --- a/src/app/services/toaster.service.spec.ts +++ b/src/app/services/toaster.service.spec.ts @@ -7,6 +7,18 @@ import { ToasterService } from './toaster.service'; export class MockedToasterService { public errors: string[]; public successes: string[]; + snackBarConfigForSuccess = { + duration: 2000, + panelClass: ['snackabar-success'], + MatSnackBarHorizontalPosition : 'center', + MatSnackBarVerticalPosition : 'bottom' + }; + snackBarConfigForError = { + duration: 2000, + panelClass: ['snackabar-error'], + MatSnackBarHorizontalPosition : 'center', + MatSnackBarVerticalPosition : 'bottom' + }; constructor() { this.errors = []; @@ -41,12 +53,12 @@ describe('ToasterService', () => { it('should open when success', inject([ToasterService, MatSnackBar], (service: ToasterService, snackBar: MatSnackBar) => { const spy = spyOn(snackBar, 'open'); service.success("message"); - expect(snackBar.open).toHaveBeenCalledWith("message", null, { duration: 2000 }); + expect(snackBar.open).toHaveBeenCalledWith("message", 'Close', service.snackBarConfigForSuccess); })); it('should open when error', inject([ToasterService, MatSnackBar], (service: ToasterService, snackBar: MatSnackBar) => { const spy = spyOn(snackBar, 'open'); service.error("message"); - expect(snackBar.open).toHaveBeenCalledWith("message", null, { duration: 2000 }); + expect(snackBar.open).toHaveBeenCalledWith("message", 'Close', service.snackBarConfigForError); })); }); diff --git a/src/app/services/toaster.service.ts b/src/app/services/toaster.service.ts index d85e7b08..513406ea 100644 --- a/src/app/services/toaster.service.ts +++ b/src/app/services/toaster.service.ts @@ -3,14 +3,25 @@ import { MatSnackBar } from '@angular/material'; @Injectable() export class ToasterService { + snackBarConfigForSuccess = { + duration: 2000, + panelClass: ['snackabar-success'], + MatSnackBarHorizontalPosition : 'center', + MatSnackBarVerticalPosition : 'bottom' + }; + snackBarConfigForError = { + duration: 2000, + panelClass: ['snackabar-error'], + MatSnackBarHorizontalPosition : 'center', + MatSnackBarVerticalPosition : 'bottom' + }; constructor(private snackbar: MatSnackBar) { } public error(message: string) { - this.snackbar.open(message, null, { duration: 2000 }); + this.snackbar.open(message, 'Close', this.snackBarConfigForError); } public success(message: string) { - this.snackbar.open(message, null, { duration: 2000 }); + this.snackbar.open(message, 'Close', this.snackBarConfigForSuccess); } } - diff --git a/src/styles.css b/src/styles.css index bab361e4..cb956273 100644 --- a/src/styles.css +++ b/src/styles.css @@ -6,6 +6,16 @@ a.table-link { color: #0097a7; } +.snackabar-success { + background:#0097a7!important; + color: white!important; +} + +.snackbar-error { + background: #B00020!important; + color: white!important; +} + app-root { width: 100%; }