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
+
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 @@
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%;
}