From 5a2b73f50fd308f070ebc2852d4994139eee96b1 Mon Sep 17 00:00:00 2001 From: Tobias Linn Date: Sun, 15 Nov 2020 20:42:55 +0100 Subject: [PATCH 1/6] Check project name input for duplicates # Disable create button if error # Update error messages --- .../create-project-dialog.component.html | 35 ++++++---- .../create-project-dialog.component.ts | 66 ++++++++++++------- 2 files changed, 65 insertions(+), 36 deletions(-) diff --git a/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.html b/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.html index 846bcaf..cbcb2dc 100644 --- a/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.html +++ b/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.html @@ -7,11 +7,14 @@

Create a new Project

[formControl]="name" required autofocus> - - Please enter a name - - - Name too long + + + + + + + + {{ getNameErrorMsg() }} @@ -23,9 +26,9 @@

Create a new Project

Owners too long
- + - - - Description too long - - -
- + + Description + + + Description too long + + +
+ - Select all regions, which are neccessary for your cloud application. + Select all regions, which are neccessary for your cloud application. -
- - - - - - {{item.provider.title}} - - - +
+ + + + + + {{item.provider.title}} + + + - -
    -
  • - - {{option.region.name}} - -
  • -
-
-
-
-
+ +
    +
  • + + {{option.region.name}} + +
  • +
+
+
+
+
diff --git a/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.ts b/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.ts index 1374e47..f9ac7d9 100644 --- a/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.ts +++ b/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.ts @@ -103,6 +103,10 @@ export class CreateProjectDialogComponent implements OnInit { this.dialogRef.close(project); } + /** + * Check if the current input name already exists in the project manager and return error if it is the case. + * @param newName FormControl of the current name input + */ duplicateNameValidator(newName: FormControl) { for (const project of ProjectManager.projectMetas) { const name = project.name.toLowerCase() @@ -113,6 +117,9 @@ export class CreateProjectDialogComponent implements OnInit { return null; } + /** + * Return the appropriate error message for the name input form field. + */ getNameErrorMsg() { return this.name.hasError('required') ? 'Please enter a name' : this.name.hasError('maxlength') ? 'Name too long' : From 677852fe46e49c5fac899a1d3f3bc817ab975154 Mon Sep 17 00:00:00 2001 From: Tobias Linn Date: Tue, 24 Nov 2020 21:22:18 +0100 Subject: [PATCH 3/6] Use same dialog for editing and creating projects # Editing project meta data now uses the same dialog as creating a project # Duplicate validator now uses an additional parameter to exclude a name --- .../create-project-dialog.component.html | 4 +- .../create-project-dialog.component.ts | 104 +++++++++------- .../project-dashboard.component.html | 116 +++++++++--------- .../project-dashboard.component.ts | 25 ++-- 4 files changed, 137 insertions(+), 112 deletions(-) diff --git a/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.html b/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.html index af0b72c..d2f98e4 100644 --- a/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.html +++ b/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.html @@ -75,7 +75,7 @@

Create a new Project

diff --git a/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.ts b/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.ts index f9ac7d9..97c86e5 100644 --- a/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.ts +++ b/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, Inject, OnInit } from '@angular/core'; import { MatDialogRef } from '@angular/material'; import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import CloudProviderItem from './cloud-provider-item'; @@ -8,6 +8,7 @@ import { environment } from '../../../environments/environment'; import Project from '../../model/project'; import { ProjectManager } from '../../data-management/project-manager'; import JsonProjectMeta from '../../model/json-project-meta'; +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; @Component({ selector: 'app-create-project-dialog', @@ -18,41 +19,46 @@ export class CreateProjectDialogComponent implements OnInit { public projectForm: FormGroup; public providerList: CloudProviderItem[]; + readonly isUpdate; constructor(private http: HttpClient, private formBuilder: FormBuilder, - public dialogRef: MatDialogRef) { + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: {projectMeta: JsonProjectMeta}) { + this.isUpdate = !!data.projectMeta; } ngOnInit() { this.providerList = []; this.projectForm = this.formBuilder.group({ - name: ['', [ + name: [this.isUpdate ? this.data.projectMeta.name : '', [ Validators.required, Validators.maxLength(256), - this.duplicateNameValidator + this.duplicateNameValidator(this.isUpdate ? this.data.projectMeta.name : undefined) ]], - description: ['', [ + description: [this.isUpdate ? this.data.projectMeta.description : '', [ Validators.maxLength(2048) ]], - owner: ['', [ + owner: [this.isUpdate ? this.data.projectMeta.owner : '', [ Validators.maxLength(128) ]], }); - this.http.get(environment.serviceServer).subscribe(cloudProviders => - this.providerList = cloudProviders.map(provider => { - const item = new CloudProviderItem(); - item.provider = provider; - item.options = provider.regions.map(r => { - return { - completed: true, - region: r - }; - }); - return item; - }) - ); + if (!this.isUpdate) { + this.http.get(environment.serviceServer).subscribe(cloudProviders => + this.providerList = cloudProviders.map(provider => { + const item = new CloudProviderItem(); + item.provider = provider; + item.options = provider.regions.map(r => { + return { + completed: true, + region: r + }; + }); + return item; + }) + ); + } } updateAllComplete(provider: CloudProviderItem) { @@ -77,44 +83,56 @@ export class CreateProjectDialogComponent implements OnInit { } onCancelClick() { - this.dialogRef.close(null); + this.dialogRef.close(undefined); } - onCreate() { + onSubmit() { this.projectForm.markAllAsTouched(); if (this.projectForm.invalid) { return; } - const rawData = this.projectForm.getRawValue(); - const id = rawData.name + '_' + Date.now().toString(16); const project = new Project(); - project.metaData.id = id; - project.metaData.name = rawData.name; - project.metaData.description = rawData.description; - project.metaData.owner = rawData.owner; - - project.metaData.cloudProviders = this.getCloudProviders(); - // Create empty model - project.model = new ClamsProject(); - // Include Cloud Providers to model - project.model.cloudProviders = project.metaData.cloudProviders.map(jsonCloudProvider => - CloudProviderFactory.fromJSON(jsonCloudProvider)); - - this.dialogRef.close(project); + + project.metaData.name = this.name.value; + project.metaData.description = this.description.value; + project.metaData.owner = this.owner.value; + + if (this.isUpdate) { + project.metaData.id = this.data.projectMeta.id; + project.metaData.cloudProviders = this.data.projectMeta.cloudProviders + } else { + project.metaData.id = this.name.value + '_' + Date.now().toString(16); + project.metaData.cloudProviders = this.getCloudProviders(); + // Create empty project model + project.model = new ClamsProject(); + // Include Cloud Providers to model + project.model.cloudProviders = project.metaData.cloudProviders.map(jsonCloudProvider => + CloudProviderFactory.fromJSON(jsonCloudProvider)); + } + this.dialogRef.close({ + isUpdate: this.isUpdate, + data: project + }); } /** * Check if the current input name already exists in the project manager and return error if it is the case. - * @param newName FormControl of the current name input + * In case of update, ignore the name of this project. + * @param oldName: Name that is excluded from the duplicate check. */ - duplicateNameValidator(newName: FormControl) { - for (const project of ProjectManager.projectMetas) { - const name = project.name.toLowerCase() - if (!name.localeCompare(newName.value.trim())) { - return {duplicate: true}; + duplicateNameValidator(oldName?: string) { + return (control) => { + for (const project of ProjectManager.projectMetas) { + if (oldName && !oldName.localeCompare(control.value.trim())) { + continue + } + const name = project.name.toLowerCase() + if (!name.localeCompare(control.value.trim())) { + return {duplicate: true}; + } } + return null; } - return null; } /** diff --git a/src/app/project-dashboard/project-dashboard.component.html b/src/app/project-dashboard/project-dashboard.component.html index f307234..b7fc218 100644 --- a/src/app/project-dashboard/project-dashboard.component.html +++ b/src/app/project-dashboard/project-dashboard.component.html @@ -1,70 +1,70 @@ - - + + - - + + -
- -
+
+ +
-
- -

Projects

- -
+
- - -
cloud_queue
- - {{project.name | truncate : 40 : '...'}} - - {{project.owner}} -
- -

- {{project.description}} -

-
- - -
- - - -
-
-
+

Projects

+
+ + +
+ cloud_queue
+ + {{project.name | truncate : 40 : '...'}} + + {{project.owner}} +
+ +

+ {{project.description}} +

+
+ + +
+ + +
+
+
+
diff --git a/src/app/project-dashboard/project-dashboard.component.ts b/src/app/project-dashboard/project-dashboard.component.ts index f9763da..ffd271f 100644 --- a/src/app/project-dashboard/project-dashboard.component.ts +++ b/src/app/project-dashboard/project-dashboard.component.ts @@ -38,18 +38,25 @@ export class ProjectDashboardComponent implements OnInit { this.router.navigate(['project', project.id]); } - openCreateProjectDialog() { - console.log('Create Project Event'); - const dialogRef = this.dialog.open(CreateProjectDialogComponent); + openProjectDialog(metaData?: JsonProjectMeta) { + console.log(metaData); + const dialogRef = this.dialog.open(CreateProjectDialogComponent, + {data: {projectMeta: metaData}}); - dialogRef.afterClosed().subscribe(result => { - if (!result) { + dialogRef.afterClosed().subscribe((result: { isUpdate: boolean, data: Project }) => { + if (!result || !result.data) { return; } - const project = result as Project; - console.log(`Dialog result:`, project); - // Save project - ProjectManager.save(project); + console.log(`Dialog result:`, result); + // Update/Save project + if (result.isUpdate) { + ProjectManager.load(metaData.id).then(project => { + project.metaData = result.data.metaData; + ProjectManager.save(project); + }); + } else { + ProjectManager.save(result.data); + } }); } From 11bf7f7db192f9c20a0d55c0a92f7eca8db22c4d Mon Sep 17 00:00:00 2001 From: Tobias Linn Date: Tue, 24 Nov 2020 21:34:15 +0100 Subject: [PATCH 4/6] Code clean up # Removed edit project meta data dialog # Renamed dialog component --- src/app/app.module.ts | 9 +-- .../edit-project-dialog.component.css | 17 ----- .../edit-project-dialog.component.html | 68 ------------------- .../edit-project-dialog.component.spec.ts | 25 ------- .../edit-project-dialog.component.ts | 68 ------------------- .../project-dashboard.component.ts | 21 +----- .../cloud-provider-item.ts | 0 .../project-meta-data-dialog.component.css} | 0 .../project-meta-data-dialog.component.html} | 0 ...roject-meta-data-dialog.component.spec.ts} | 10 +-- .../project-meta-data-dialog.component.ts} | 8 +-- 11 files changed, 14 insertions(+), 212 deletions(-) delete mode 100644 src/app/project-dashboard/edit-project-dialog/edit-project-dialog.component.css delete mode 100644 src/app/project-dashboard/edit-project-dialog/edit-project-dialog.component.html delete mode 100644 src/app/project-dashboard/edit-project-dialog/edit-project-dialog.component.spec.ts delete mode 100644 src/app/project-dashboard/edit-project-dialog/edit-project-dialog.component.ts rename src/app/project-dashboard/{create-project-dialog => project-meta-data-dialog}/cloud-provider-item.ts (100%) rename src/app/project-dashboard/{create-project-dialog/create-project-dialog.component.css => project-meta-data-dialog/project-meta-data-dialog.component.css} (100%) rename src/app/project-dashboard/{create-project-dialog/create-project-dialog.component.html => project-meta-data-dialog/project-meta-data-dialog.component.html} (100%) rename src/app/project-dashboard/{create-project-dialog/create-project-dialog.component.spec.ts => project-meta-data-dialog/project-meta-data-dialog.component.spec.ts} (55%) rename src/app/project-dashboard/{create-project-dialog/create-project-dialog.component.ts => project-meta-data-dialog/project-meta-data-dialog.component.ts} (95%) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 5e45992..fc03396 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -31,8 +31,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { ProjectDashboardComponent } from './project-dashboard/project-dashboard.component'; import { PageNotFoundComponent } from './page-not-found/page-not-found.component'; import { AppRoutingModule } from './app-routing.module'; -import { CreateProjectDialogComponent } from './project-dashboard/create-project-dialog/create-project-dialog.component'; -import { EditProjectDialogComponent } from './project-dashboard/edit-project-dialog/edit-project-dialog.component'; +import { ProjectMetaDataDialogComponent } from './project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component'; import { ProjectBoardComponent } from './project-board/project-board.component'; import { DiagramComponent } from './project-board/diagram/diagram.component'; import { CatalogComponent } from './project-board/catalog/catalog.component'; @@ -65,8 +64,7 @@ import { InputDialogComponent } from './project-board/evaluation/input-dialog/in AppComponent, ProjectDashboardComponent, PageNotFoundComponent, - CreateProjectDialogComponent, - EditProjectDialogComponent, + ProjectMetaDataDialogComponent, ProjectBoardComponent, DiagramComponent, CatalogComponent, @@ -127,8 +125,7 @@ import { InputDialogComponent } from './project-board/evaluation/input-dialog/in providers: [], bootstrap: [AppComponent], entryComponents: [ - CreateProjectDialogComponent, - EditProjectDialogComponent, + ProjectMetaDataDialogComponent, CreateGraphDialogComponent, EditGraphDialogComponent, ReplacementDialogComponent, diff --git a/src/app/project-dashboard/edit-project-dialog/edit-project-dialog.component.css b/src/app/project-dashboard/edit-project-dialog/edit-project-dialog.component.css deleted file mode 100644 index 888c369..0000000 --- a/src/app/project-dashboard/edit-project-dialog/edit-project-dialog.component.css +++ /dev/null @@ -1,17 +0,0 @@ -.provider-section { - margin: 12px 0; - } - - .provider-margin { - margin: 0 12px; - } - - ul { - list-style-type: none; - margin-top: 4px; - } - - .provider-headers-align{ - margin-top: 20px; - margin-bottom: 20px; - } \ No newline at end of file diff --git a/src/app/project-dashboard/edit-project-dialog/edit-project-dialog.component.html b/src/app/project-dashboard/edit-project-dialog/edit-project-dialog.component.html deleted file mode 100644 index c036b0d..0000000 --- a/src/app/project-dashboard/edit-project-dialog/edit-project-dialog.component.html +++ /dev/null @@ -1,68 +0,0 @@ -

Edit Project

-
-
- - - - Please enter a name - - - Name too long - - - - - - - Owners too long - - - - - - - Description too long - - -
-
- - Your Project is using the following cloud providers. - -
- - - - - {{provider.title}} - - - - -
    -
  • - {{region.name}} -
  • -
-
-
-
-
- -
-
- - -
\ No newline at end of file diff --git a/src/app/project-dashboard/edit-project-dialog/edit-project-dialog.component.spec.ts b/src/app/project-dashboard/edit-project-dialog/edit-project-dialog.component.spec.ts deleted file mode 100644 index ecbb8f7..0000000 --- a/src/app/project-dashboard/edit-project-dialog/edit-project-dialog.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { EditProjectDialogComponent } from './edit-project-dialog.component'; - -describe('EditProjectDialogComponent', () => { - let component: EditProjectDialogComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ EditProjectDialogComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(EditProjectDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/project-dashboard/edit-project-dialog/edit-project-dialog.component.ts b/src/app/project-dashboard/edit-project-dialog/edit-project-dialog.component.ts deleted file mode 100644 index 0241f54..0000000 --- a/src/app/project-dashboard/edit-project-dialog/edit-project-dialog.component.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Component, OnInit, Inject } from '@angular/core'; -import { FormGroup, FormBuilder, Validators } from '@angular/forms'; -import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; -import { ProjectManager } from '../../data-management/project-manager'; -import JsonProjectMeta from '../../model/json-project-meta'; - -@Component({ - selector: 'app-edit-project-dialog', - templateUrl: './edit-project-dialog.component.html', - styleUrls: ['./edit-project-dialog.component.css'] -}) -export class EditProjectDialogComponent implements OnInit { - - public projectForm: FormGroup; - - constructor(private formBuilder: FormBuilder, - public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: {projectMeta: JsonProjectMeta} ) { } - - ngOnInit() { - this.projectForm = this.formBuilder.group({ - name: [this.data.projectMeta.name, [ - Validators.required, - Validators.maxLength(32) - ]], - description: [this.data.projectMeta.description, [ - Validators.maxLength(2048) - ]], - owner: [this.data.projectMeta.owner, [ - Validators.maxLength(128) - ]], - }); - } - - onCancelClick() { - this.dialogRef.close(null); - } - - onCreate() { - this.projectForm.markAllAsTouched(); - if (this.projectForm.invalid) { - return; - } - const rawData = this.projectForm.getRawValue(); - const newMeta: JsonProjectMeta = { - id: this.data.projectMeta.id, - name: rawData.name, - description: rawData.description, - owner: rawData.owner, - cloudProviders: this.data.projectMeta.cloudProviders - }; - - this.dialogRef.close(newMeta); - } - - get name() { - return this.projectForm.get('name'); - } - - get description() { - return this.projectForm.get('description'); - } - - get owner() { - return this.projectForm.get('owner'); - } - -} diff --git a/src/app/project-dashboard/project-dashboard.component.ts b/src/app/project-dashboard/project-dashboard.component.ts index ffd271f..f74da69 100644 --- a/src/app/project-dashboard/project-dashboard.component.ts +++ b/src/app/project-dashboard/project-dashboard.component.ts @@ -2,9 +2,8 @@ import { Component, OnInit, HostListener } from '@angular/core'; import { ProjectManager } from '../data-management/project-manager'; import JsonProjectMeta from '../model/json-project-meta'; import { MatDialog } from '@angular/material/dialog'; -import { CreateProjectDialogComponent } from './create-project-dialog/create-project-dialog.component'; +import { ProjectMetaDataDialogComponent } from './project-meta-data-dialog/project-meta-data-dialog.component'; import Project from '../model/project'; -import { EditProjectDialogComponent } from './edit-project-dialog/edit-project-dialog.component'; import { Router } from '@angular/router'; @Component({ @@ -40,7 +39,7 @@ export class ProjectDashboardComponent implements OnInit { openProjectDialog(metaData?: JsonProjectMeta) { console.log(metaData); - const dialogRef = this.dialog.open(CreateProjectDialogComponent, + const dialogRef = this.dialog.open(ProjectMetaDataDialogComponent, {data: {projectMeta: metaData}}); dialogRef.afterClosed().subscribe((result: { isUpdate: boolean, data: Project }) => { @@ -60,22 +59,6 @@ export class ProjectDashboardComponent implements OnInit { }); } - openEditDialog(metaData: JsonProjectMeta) { - console.log('Create Project Event'); - const dialogRef = this.dialog.open(EditProjectDialogComponent, - {data: {projectMeta: metaData}}); - - dialogRef.afterClosed().subscribe(result => { - if (!result) { - return; - } - ProjectManager.load(metaData.id).then(project => { - project.metaData = result; - ProjectManager.save(project); - }); - }); - } - getProjectMetas(): JsonProjectMeta[] { return ProjectManager.projectMetas; } diff --git a/src/app/project-dashboard/create-project-dialog/cloud-provider-item.ts b/src/app/project-dashboard/project-meta-data-dialog/cloud-provider-item.ts similarity index 100% rename from src/app/project-dashboard/create-project-dialog/cloud-provider-item.ts rename to src/app/project-dashboard/project-meta-data-dialog/cloud-provider-item.ts diff --git a/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.css b/src/app/project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component.css similarity index 100% rename from src/app/project-dashboard/create-project-dialog/create-project-dialog.component.css rename to src/app/project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component.css diff --git a/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.html b/src/app/project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component.html similarity index 100% rename from src/app/project-dashboard/create-project-dialog/create-project-dialog.component.html rename to src/app/project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component.html diff --git a/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.spec.ts b/src/app/project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component.spec.ts similarity index 55% rename from src/app/project-dashboard/create-project-dialog/create-project-dialog.component.spec.ts rename to src/app/project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component.spec.ts index b3c4978..d1352b2 100644 --- a/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.spec.ts +++ b/src/app/project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component.spec.ts @@ -1,20 +1,20 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { CreateProjectDialogComponent } from './create-project-dialog.component'; +import { ProjectMetaDataDialogComponent } from './project-meta-data-dialog.component'; describe('CreateProjectDialogComponent', () => { - let component: CreateProjectDialogComponent; - let fixture: ComponentFixture; + let component: ProjectMetaDataDialogComponent; + let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ CreateProjectDialogComponent ] + declarations: [ ProjectMetaDataDialogComponent ] }) .compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(CreateProjectDialogComponent); + fixture = TestBed.createComponent(ProjectMetaDataDialogComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.ts b/src/app/project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component.ts similarity index 95% rename from src/app/project-dashboard/create-project-dialog/create-project-dialog.component.ts rename to src/app/project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component.ts index 97c86e5..15ace54 100644 --- a/src/app/project-dashboard/create-project-dialog/create-project-dialog.component.ts +++ b/src/app/project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component.ts @@ -12,10 +12,10 @@ import { MAT_DIALOG_DATA } from '@angular/material/dialog'; @Component({ selector: 'app-create-project-dialog', - templateUrl: './create-project-dialog.component.html', - styleUrls: ['./create-project-dialog.component.css'] + templateUrl: './project-meta-data-dialog.component.html', + styleUrls: ['./project-meta-data-dialog.component.css'] }) -export class CreateProjectDialogComponent implements OnInit { +export class ProjectMetaDataDialogComponent implements OnInit { public projectForm: FormGroup; public providerList: CloudProviderItem[]; @@ -23,7 +23,7 @@ export class CreateProjectDialogComponent implements OnInit { constructor(private http: HttpClient, private formBuilder: FormBuilder, - public dialogRef: MatDialogRef, + public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: {projectMeta: JsonProjectMeta}) { this.isUpdate = !!data.projectMeta; } From 2066ce62603c0cc2423628d6cacf263439b8f8f5 Mon Sep 17 00:00:00 2001 From: Tobias Linn Date: Tue, 24 Nov 2020 22:19:26 +0100 Subject: [PATCH 5/6] Fixed height on dashboard # Use flex instead of height calculation --- src/app/app.component.html | 4 ++-- src/app/project-dashboard/project-dashboard.component.ts | 8 -------- src/styles.css | 2 +- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/app/app.component.html b/src/app/app.component.html index b11d739..7fa9eac 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -2,7 +2,7 @@ - + - + diff --git a/src/app/project-dashboard/project-dashboard.component.ts b/src/app/project-dashboard/project-dashboard.component.ts index f74da69..6b09967 100644 --- a/src/app/project-dashboard/project-dashboard.component.ts +++ b/src/app/project-dashboard/project-dashboard.component.ts @@ -19,14 +19,6 @@ export class ProjectDashboardComponent implements OnInit { ngOnInit() { ProjectManager.refreshProjectMetas() - this.onResize(); - } - - @HostListener('window:resize', ['$event']) - onResize(event?) { - const screenHeight = window.innerHeight; - let box2h = 64//document.getElementById("command-bar").offsetHeight - document.getElementById("main-container").style.height = (screenHeight - box2h)+'px'; } onDelete(project: JsonProjectMeta, idx: number) { diff --git a/src/styles.css b/src/styles.css index a0a07e3..9c5939d 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1,4 +1,4 @@ /* You can add global styles to this file, and also import other style files */ @import '@angular/material/prebuilt-themes/indigo-pink.css'; -html, body { height: 100%; } +html, body { flex: 1; display: flex; flex-direction: column; } body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } From 188b5c50d817bb77b8128e5ec789121d5648591a Mon Sep 17 00:00:00 2001 From: Tobias Linn Date: Fri, 27 Nov 2020 00:27:55 +0100 Subject: [PATCH 6/6] Added simple tests # Test name error message function # Test duplicate name validator --- ...project-meta-data-dialog.component.spec.ts | 91 ++++++++++++++++++- .../project-meta-data-dialog.component.ts | 25 +++-- 2 files changed, 105 insertions(+), 11 deletions(-) diff --git a/src/app/project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component.spec.ts b/src/app/project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component.spec.ts index d1352b2..9e59be6 100644 --- a/src/app/project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component.spec.ts +++ b/src/app/project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component.spec.ts @@ -1,25 +1,110 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ProjectMetaDataDialogComponent } from './project-meta-data-dialog.component'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { InjectionToken } from '@angular/core'; +import JsonProjectMeta from '../../model/json-project-meta'; +import { ReactiveFormsModule } from '@angular/forms'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatExpansionModule } from '@angular/material/expansion'; +import { MatInputModule } from '@angular/material/input'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { ProjectManager } from '../../data-management/project-manager'; +import { By } from '@angular/platform-browser'; -describe('CreateProjectDialogComponent', () => { +const testStrings: string[] = [ + 'string1', + 'string1 ', + ' string1', + 'string2', + 'string3' +]; + +describe('ProjectMetaDataDialogComponent', () => { let component: ProjectMetaDataDialogComponent; let fixture: ComponentFixture; + const noData = new InjectionToken<{ projectMeta: JsonProjectMeta }>(undefined); beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ ProjectMetaDataDialogComponent ] + declarations: [ProjectMetaDataDialogComponent], + imports: [ + HttpClientTestingModule, + BrowserAnimationsModule, + ReactiveFormsModule, + MatFormFieldModule, + MatExpansionModule, + MatInputModule + ], + providers: [ + {provide: MatDialogRef, useValue: {}}, + {provide: MAT_DIALOG_DATA, useValue: noData} + ] }) - .compileComponents(); + .compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(ProjectMetaDataDialogComponent); component = fixture.componentInstance; fixture.detectChanges(); + + ProjectManager.projectMetas = [ + { + id: undefined, + name: testStrings[0], + description: undefined, + owner: undefined, + cloudProviders: undefined + }, + { + id: undefined, + name: testStrings[3], + description: undefined, + owner: undefined, + cloudProviders: undefined + } + ]; + }); + + afterEach(() => { + ProjectManager.projectMetas = []; + component.projectForm.reset() }); it('should create', () => { expect(component).toBeTruthy(); }); + + it('#duplicateNameValidator() should recognize duplicate', () => { + expect(component.duplicateNameValidator()({value: testStrings[0]}).duplicate).toBeTrue(); + expect(component.duplicateNameValidator()({value: testStrings[1]}).duplicate).toBeTrue(); + expect(component.duplicateNameValidator()({value: testStrings[2]}).duplicate).toBeTrue(); + expect(component.duplicateNameValidator()({value: testStrings[3]}).duplicate).toBeTrue(); + }); + + it('#duplicateNameValidator() should not recognize duplicate', () => { + expect(component.duplicateNameValidator()({value: testStrings[4]})).toBeNull(); + }); + + function addLetters(letters: string) { + component.projectForm.controls.name.setValue(component.name.value + letters); + } + + it('#getNameErrorMsg() should return correct error message', () => { + component.projectForm.controls.name.markAsTouched() + expect(component.getNameErrorMsg()).toMatch('Please enter a name'); + addLetters('s'); + expect(component.getNameErrorMsg()).toMatch(''); + addLetters('tring1'); + expect(component.getNameErrorMsg()).toMatch('Name already exists'); + addLetters('0'); + expect(component.getNameErrorMsg()).toMatch(''); + // Results in 257 letters + addLetters('x'.repeat(249)); + expect(component.getNameErrorMsg()).toMatch('Name too long'); + addLetters('x'); + expect(component.getNameErrorMsg()).toMatch('Name too long'); + }); }); diff --git a/src/app/project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component.ts b/src/app/project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component.ts index 15ace54..8a74a80 100644 --- a/src/app/project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component.ts +++ b/src/app/project-dashboard/project-meta-data-dialog/project-meta-data-dialog.component.ts @@ -1,6 +1,6 @@ import { Component, Inject, OnInit } from '@angular/core'; import { MatDialogRef } from '@angular/material'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import CloudProviderItem from './cloud-provider-item'; import { HttpClient } from '@angular/common/http'; import { ClamsProject, CloudProviderFactory, JsonCloudProvider } from '@openclams/clams-ml'; @@ -11,7 +11,7 @@ import JsonProjectMeta from '../../model/json-project-meta'; import { MAT_DIALOG_DATA } from '@angular/material/dialog'; @Component({ - selector: 'app-create-project-dialog', + selector: 'app-project-meta-data-dialog', templateUrl: './project-meta-data-dialog.component.html', styleUrls: ['./project-meta-data-dialog.component.css'] }) @@ -24,7 +24,7 @@ export class ProjectMetaDataDialogComponent implements OnInit { constructor(private http: HttpClient, private formBuilder: FormBuilder, public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: {projectMeta: JsonProjectMeta}) { + @Inject(MAT_DIALOG_DATA) public data: { projectMeta: JsonProjectMeta }) { this.isUpdate = !!data.projectMeta; } @@ -99,7 +99,7 @@ export class ProjectMetaDataDialogComponent implements OnInit { if (this.isUpdate) { project.metaData.id = this.data.projectMeta.id; - project.metaData.cloudProviders = this.data.projectMeta.cloudProviders + project.metaData.cloudProviders = this.data.projectMeta.cloudProviders; } else { project.metaData.id = this.name.value + '_' + Date.now().toString(16); project.metaData.cloudProviders = this.getCloudProviders(); @@ -118,30 +118,39 @@ export class ProjectMetaDataDialogComponent implements OnInit { /** * Check if the current input name already exists in the project manager and return error if it is the case. * In case of update, ignore the name of this project. + * * @param oldName: Name that is excluded from the duplicate check. + * + * @return Null if the strings do not match + * An object { duplicate: true } if the strings do match */ duplicateNameValidator(oldName?: string) { return (control) => { for (const project of ProjectManager.projectMetas) { if (oldName && !oldName.localeCompare(control.value.trim())) { - continue + continue; } - const name = project.name.toLowerCase() + const name = project.name.toLowerCase(); if (!name.localeCompare(control.value.trim())) { return {duplicate: true}; } } return null; - } + }; } /** * Return the appropriate error message for the name input form field. + * + * @return One of three strings: + * If no input is given: 'Please enter a name' + * If input is too long: 'Name too long' + * If name exists in metas: 'Name already exists' */ getNameErrorMsg() { return this.name.hasError('required') ? 'Please enter a name' : this.name.hasError('maxlength') ? 'Name too long' : - this.name.invalid ? 'Name already exists' : '' + this.name.invalid ? 'Name already exists' : ''; } public getCloudProviders(): JsonCloudProvider[] {