diff --git a/package-lock.json b/package-lock.json index 9af0a87..6d70eb9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11734,9 +11734,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sartography-workflow-lib": { - "version": "0.0.62", - "resolved": "https://registry.npmjs.org/sartography-workflow-lib/-/sartography-workflow-lib-0.0.62.tgz", - "integrity": "sha512-Ml5D75HPvxFzeT+0OYKx0YVdkDSywBGuLUpXx981k0yPnOUHWqhDNumWY7jVfr3AsPxvxPXhZYrMTTshOx/1fw==" + "version": "0.0.64", + "resolved": "https://registry.npmjs.org/sartography-workflow-lib/-/sartography-workflow-lib-0.0.64.tgz", + "integrity": "sha512-5tkoXjbELAhJRmVg6vc63o+B4M8WUWdpvS9oq8imODlEv8Oby4A4mDK/4g1h2daFgIvkC+99iqhiTTrD85gX8w==" }, "sass": { "version": "1.23.3", diff --git a/package.json b/package.json index 77acd7e..a6b9b0d 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "dmn-js-properties-panel": "^0.3.4", "file-saver": "^2.0.2", "rxjs": "~6.5.4", - "sartography-workflow-lib": "^0.0.62", + "sartography-workflow-lib": "^0.0.64", "tslib": "^1.10.0", "uuid": "^7.0.0", "zone.js": "~0.10.2" diff --git a/src/app/_dialogs/delete-workflow-spec-category-dialog/delete-workflow-spec-category-dialog.component.html b/src/app/_dialogs/delete-workflow-spec-category-dialog/delete-workflow-spec-category-dialog.component.html new file mode 100644 index 0000000..de54c9f --- /dev/null +++ b/src/app/_dialogs/delete-workflow-spec-category-dialog/delete-workflow-spec-category-dialog.component.html @@ -0,0 +1,16 @@ +
+ Delete workflow specification {{data.workflowSpec.name}}? + +
+
+
+ + +
+
diff --git a/src/app/_dialogs/delete-workflow-spec-category-dialog/delete-workflow-spec-category-dialog.component.scss b/src/app/_dialogs/delete-workflow-spec-category-dialog/delete-workflow-spec-category-dialog.component.scss new file mode 100644 index 0000000..44d0938 --- /dev/null +++ b/src/app/_dialogs/delete-workflow-spec-category-dialog/delete-workflow-spec-category-dialog.component.scss @@ -0,0 +1,9 @@ +.select-mode { + width: 100%; + height: 100%; + + ::ng-deep button { + padding: 1em 2em; + margin: 1em; + } +} diff --git a/src/app/_dialogs/delete-workflow-spec-category-dialog/delete-workflow-spec-category-dialog.component.spec.ts b/src/app/_dialogs/delete-workflow-spec-category-dialog/delete-workflow-spec-category-dialog.component.spec.ts new file mode 100644 index 0000000..da56b29 --- /dev/null +++ b/src/app/_dialogs/delete-workflow-spec-category-dialog/delete-workflow-spec-category-dialog.component.spec.ts @@ -0,0 +1,60 @@ +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; +import {MAT_DIALOG_DATA, MatDialogModule, MatDialogRef} from '@angular/material/dialog'; +import {MatIconModule} from '@angular/material/icon'; +import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {mockWorkflowSpecCategory0} from 'sartography-workflow-lib'; +import {DeleteWorkflowSpecCategoryDialogData} from '../../_interfaces/dialog-data'; + +import {DeleteWorkflowSpecCategoryDialogComponent} from './delete-workflow-spec-category-dialog.component'; + +describe('DeleteFileDialogComponent', () => { + let component: DeleteWorkflowSpecCategoryDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + BrowserAnimationsModule, + MatDialogModule, + MatIconModule, + NoopAnimationsModule, + ], + declarations: [DeleteWorkflowSpecCategoryDialogComponent], + providers: [ + { + provide: MatDialogRef, + useValue: { + close: (dialogResult: any) => { + } + } + }, + {provide: MAT_DIALOG_DATA, useValue: []}, + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DeleteWorkflowSpecCategoryDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should save data on submit', () => { + const closeSpy = spyOn(component.dialogRef, 'close').and.stub(); + const expectedData: DeleteWorkflowSpecCategoryDialogData = {confirm: true, category: mockWorkflowSpecCategory0}; + component.data.category = mockWorkflowSpecCategory0; + component.onSubmit(); + expect(closeSpy).toHaveBeenCalledWith(expectedData); + }); + + it('should not change data on cancel', () => { + const closeSpy = spyOn(component.dialogRef, 'close').and.stub(); + component.onNoClick(); + expect(closeSpy).toHaveBeenCalledWith(); + }); +}); diff --git a/src/app/_dialogs/delete-workflow-spec-category-dialog/delete-workflow-spec-category-dialog.component.ts b/src/app/_dialogs/delete-workflow-spec-category-dialog/delete-workflow-spec-category-dialog.component.ts new file mode 100644 index 0000000..feda238 --- /dev/null +++ b/src/app/_dialogs/delete-workflow-spec-category-dialog/delete-workflow-spec-category-dialog.component.ts @@ -0,0 +1,30 @@ +import {Component, Inject} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {DeleteWorkflowSpecCategoryDialogData} from '../../_interfaces/dialog-data'; + +@Component({ + selector: 'app-delete-workflow-spec-dialog', + templateUrl: './delete-workflow-spec-category-dialog.component.html', + styleUrls: ['./delete-workflow-spec-category-dialog.component.scss'] +}) +export class DeleteWorkflowSpecCategoryDialogComponent { + + constructor( + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: DeleteWorkflowSpecCategoryDialogData + ) { + } + + onNoClick() { + this.dialogRef.close(); + } + + onSubmit() { + const data: DeleteWorkflowSpecCategoryDialogData = { + confirm: true, + category: this.data.category, + }; + this.dialogRef.close(data); + } + +} diff --git a/src/app/_dialogs/workflow-spec-category-dialog/workflow-spec-category-dialog.component.spec.ts b/src/app/_dialogs/workflow-spec-category-dialog/workflow-spec-category-dialog.component.spec.ts index ae0261a..bf6eec1 100644 --- a/src/app/_dialogs/workflow-spec-category-dialog/workflow-spec-category-dialog.component.spec.ts +++ b/src/app/_dialogs/workflow-spec-category-dialog/workflow-spec-category-dialog.component.spec.ts @@ -7,7 +7,7 @@ import {MatInputModule} from '@angular/material/input'; import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations'; import {FormlyModule} from '@ngx-formly/core'; import {FormlyMaterialModule} from '@ngx-formly/material'; -import {mockWorkflowSpec0} from 'sartography-workflow-lib'; +import {mockWorkflowSpecCategory0} from 'sartography-workflow-lib'; import {WorkflowSpecCategoryDialogData} from '../../_interfaces/dialog-data'; import {WorkflowSpecCategoryDialogComponent} from './workflow-spec-category-dialog.component'; @@ -56,7 +56,7 @@ describe('WorkflowSpecDialogComponent', () => { it('should save data on submit', () => { const closeSpy = spyOn(component.dialogRef, 'close').and.stub(); - const expectedData: WorkflowSpecCategoryDialogData = mockWorkflowSpec0 as WorkflowSpecCategoryDialogData; + const expectedData: WorkflowSpecCategoryDialogData = mockWorkflowSpecCategory0 as WorkflowSpecCategoryDialogData; component.model = expectedData; component.onSubmit(); expect(closeSpy).toHaveBeenCalledWith(expectedData); diff --git a/src/app/_dialogs/workflow-spec-dialog/workflow-spec-dialog.component.ts b/src/app/_dialogs/workflow-spec-dialog/workflow-spec-dialog.component.ts index d741888..d2062ed 100644 --- a/src/app/_dialogs/workflow-spec-dialog/workflow-spec-dialog.component.ts +++ b/src/app/_dialogs/workflow-spec-dialog/workflow-spec-dialog.component.ts @@ -1,7 +1,8 @@ import {Component, Inject} from '@angular/core'; import {FormGroup} from '@angular/forms'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; -import {FormlyFieldConfig, FormlyFormOptions} from '@ngx-formly/core'; +import {FormlyFieldConfig, FormlyFormOptions, FormlyTemplateOptions} from '@ngx-formly/core'; +import {ApiService} from 'sartography-workflow-lib'; import {v4 as uuidv4} from 'uuid'; import {WorkflowSpecDialogData} from '../../_interfaces/dialog-data'; import {toSnakeCase} from '../../_util/string-clean'; @@ -15,60 +16,83 @@ export class WorkflowSpecDialogComponent { form: FormGroup = new FormGroup({}); model: any = {}; options: FormlyFormOptions = {}; - fields: FormlyFieldConfig[] = [ - { - key: 'id', - type: 'input', - defaultValue: this.data.id || uuidv4(), - templateOptions: { - label: 'ID', - placeholder: 'UUID of workflow specification', - description: 'This is an autogenerated unique ID and is not editable.', - required: true, - disabled: true, - }, - }, - { - key: 'name', - type: 'input', - defaultValue: this.data.name, - templateOptions: { - label: 'Name', - placeholder: 'Name of workflow specification', - description: 'Enter a name, in lowercase letters, separated by underscores, that is easy for you to remember.' + - 'It will be converted to all_lowercase_with_underscores when you save.', - required: true, - }, - }, - { - key: 'display_name', - type: 'input', - defaultValue: this.data.display_name, - templateOptions: { - label: 'Display Name', - placeholder: 'Title of the workflow specification', - description: 'This is a human-readable title for the workflow specification,' + - 'which should be easy for others to read and remember.', - required: true, - }, - }, - { - key: 'description', - type: 'textarea', - defaultValue: this.data.description, - templateOptions: { - label: 'Description', - placeholder: 'Description of workflow specification', - description: 'Write a few sentences explaining to users why this workflow exists and what it should be used for.', - required: true, - }, - }, - ]; + fields: FormlyFieldConfig[] = []; + categories: any; constructor( + private api: ApiService, public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: WorkflowSpecDialogData, ) { + this.api.getWorkflowSpecCategoryList().subscribe(cats => { + this.categories = cats.map(c => { + return { + value: c.id, + label: c.display_name, + }; + }); + + this.fields = [ + { + key: 'id', + type: 'input', + defaultValue: this.data.id || uuidv4(), + templateOptions: { + label: 'ID', + placeholder: 'UUID of workflow specification', + description: 'This is an autogenerated unique ID and is not editable.', + required: true, + disabled: true, + }, + }, + { + key: 'name', + type: 'input', + defaultValue: this.data.name, + templateOptions: { + label: 'Name', + placeholder: 'Name of workflow specification', + description: 'Enter a name, in lowercase letters, separated by underscores, that is easy for you to remember.' + + 'It will be converted to all_lowercase_with_underscores when you save.', + required: true, + }, + }, + { + key: 'workflow_spec_category_id', + type: 'select', + defaultValue: this.data.name, + templateOptions: { + label: 'Category', + placeholder: 'Category of workflow specification', + required: true, + options: this.categories + }, + }, + { + key: 'display_name', + type: 'input', + defaultValue: this.data.display_name, + templateOptions: { + label: 'Display Name', + placeholder: 'Title of the workflow specification', + description: 'This is a human-readable title for the workflow specification,' + + 'which should be easy for others to read and remember.', + required: true, + }, + }, + { + key: 'description', + type: 'textarea', + defaultValue: this.data.description, + templateOptions: { + label: 'Description', + placeholder: 'Description of workflow specification', + description: 'Write a few sentences explaining to users why this workflow exists and what it should be used for.', + required: true, + }, + }, + ]; + }); } onNoClick() { diff --git a/src/app/_interfaces/dialog-data.ts b/src/app/_interfaces/dialog-data.ts index f525b32..47da37e 100644 --- a/src/app/_interfaces/dialog-data.ts +++ b/src/app/_interfaces/dialog-data.ts @@ -1,4 +1,4 @@ -import {FileMeta, FileType, WorkflowSpec} from 'sartography-workflow-lib'; +import {FileMeta, FileType, WorkflowSpec, WorkflowSpecCategory} from 'sartography-workflow-lib'; export interface FileMetaDialogData { fileName: string; @@ -18,6 +18,7 @@ export interface WorkflowSpecDialogData { name: string; display_name: string; description: string; + workflow_spec_category_id: number; } export interface WorkflowSpecCategoryDialogData { @@ -35,3 +36,8 @@ export interface DeleteWorkflowSpecDialogData { confirm: boolean; workflowSpec: WorkflowSpec; } + +export interface DeleteWorkflowSpecCategoryDialogData { + confirm: boolean; + category: WorkflowSpecCategory; +} diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 1b815b6..981431b 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -22,6 +22,7 @@ import {FormlyMaterialModule} from '@ngx-formly/material'; import {AppEnvironment, AuthInterceptor, SartographyWorkflowLibModule} from 'sartography-workflow-lib'; import {environment} from '../environments/environment'; import {DeleteFileDialogComponent} from './_dialogs/delete-file-dialog/delete-file-dialog.component'; +import {DeleteWorkflowSpecCategoryDialogComponent} from './_dialogs/delete-workflow-spec-category-dialog/delete-workflow-spec-category-dialog.component'; import {DeleteWorkflowSpecDialogComponent} from './_dialogs/delete-workflow-spec-dialog/delete-workflow-spec-dialog.component'; import {FileMetaDialogComponent} from './_dialogs/file-meta-dialog/file-meta-dialog.component'; import {NewFileDialogComponent} from './_dialogs/new-file-dialog/new-file-dialog.component'; @@ -41,6 +42,7 @@ import {NavbarComponent} from './navbar/navbar.component'; import {SignInComponent} from './sign-in/sign-in.component'; import {SignOutComponent} from './sign-out/sign-out.component'; import {WorkflowSpecListComponent} from './workflow-spec-list/workflow-spec-list.component'; +import { WorkflowSpecCardComponent } from './workflow-spec-card/workflow-spec-card.component'; @Injectable() export class ThisEnvironment implements AppEnvironment { @@ -71,6 +73,7 @@ export class AppFormlyConfig { AppComponent, DeleteFileDialogComponent, DeleteWorkflowSpecDialogComponent, + DeleteWorkflowSpecCategoryDialogComponent, DiagramComponent, FileListComponent, FileMetaDialogComponent, @@ -86,6 +89,7 @@ export class AppFormlyConfig { WorkflowSpecDialogComponent, WorkflowSpecListComponent, HomeComponent, + WorkflowSpecCardComponent, ], imports: [ BrowserAnimationsModule, @@ -115,6 +119,7 @@ export class AppFormlyConfig { entryComponents: [ DeleteFileDialogComponent, DeleteWorkflowSpecDialogComponent, + DeleteWorkflowSpecCategoryDialogComponent, FileMetaDialogComponent, NewFileDialogComponent, OpenFileDialogComponent, diff --git a/src/app/file-list/file-list.component.html b/src/app/file-list/file-list.component.html index fdf1c96..c4b7388 100644 --- a/src/app/file-list/file-list.component.html +++ b/src/app/file-list/file-list.component.html @@ -1,23 +1,29 @@ - - - {{fm.type | getIconCode}} - - + + +

{{fm.name}}

+

{{fm.last_updated | date}}

+ - - -

{{fm.name}}

-

{{fm.last_updated | date}}

- - -
-
+ + + diff --git a/src/app/file-list/file-list.component.scss b/src/app/file-list/file-list.component.scss index 1198c4d..f97a645 100644 --- a/src/app/file-list/file-list.component.scss +++ b/src/app/file-list/file-list.component.scss @@ -1,4 +1,11 @@ -::ng-deep mat-list-item:hover { - background-color: #EEEEFF; - cursor: pointer; +@import "../../config"; + +::ng-deep mat-list-item { + border-left: 4px solid $brand-gray-light; + + &:hover { + border-left: 4px solid $brand-primary; + background-color: $brand-primary-tint-4; + cursor: pointer; + } } diff --git a/src/app/workflow-spec-card/workflow-spec-card.component.html b/src/app/workflow-spec-card/workflow-spec-card.component.html new file mode 100644 index 0000000..14be3cb --- /dev/null +++ b/src/app/workflow-spec-card/workflow-spec-card.component.html @@ -0,0 +1,30 @@ + + + +

{{workflowSpec.display_name}}

+
+ +
+
+
+ +
+
ID
{{workflowSpec.id}}
+
Name
{{workflowSpec.name}}
+
Description
{{workflowSpec.description}}
+
+ +

Workflow Spec Files

+ +
+ + + + +
diff --git a/src/app/workflow-spec-card/workflow-spec-card.component.scss b/src/app/workflow-spec-card/workflow-spec-card.component.scss new file mode 100644 index 0000000..9d74185 --- /dev/null +++ b/src/app/workflow-spec-card/workflow-spec-card.component.scss @@ -0,0 +1,28 @@ +mat-card { + margin-bottom: 1em; + border: 1px solid #CCCCCC; + + mat-card-title { + h3 { + margin: 2rem 0 2rem 0; + } + + .action-buttons { + opacity: 0; + } + + &:hover { + .action-buttons { + opacity: 1; + } + } + } + + mat-card-content { + padding-left: 16px; + + dl { margin: 0 0 3rem 0; } + dt { font-weight: bold; } + } + +} diff --git a/src/app/workflow-spec-card/workflow-spec-card.component.spec.ts b/src/app/workflow-spec-card/workflow-spec-card.component.spec.ts new file mode 100644 index 0000000..a28ca65 --- /dev/null +++ b/src/app/workflow-spec-card/workflow-spec-card.component.spec.ts @@ -0,0 +1,60 @@ +import {HttpClientTestingModule} from '@angular/common/http/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; +import {MatCardModule} from '@angular/material/card'; +import {MAT_DIALOG_DATA, MatDialogModule, MatDialogRef} from '@angular/material/dialog'; +import {MatIconModule} from '@angular/material/icon'; +import {MatListModule} from '@angular/material/list'; +import {MatSnackBarModule} from '@angular/material/snack-bar'; +import {RouterTestingModule} from '@angular/router/testing'; +import {ApiService, MockEnvironment, mockWorkflowSpec0} from 'sartography-workflow-lib'; +import {GetIconCodePipe} from '../_pipes/get-icon-code.pipe'; +import {FileListComponent} from '../file-list/file-list.component'; +import {WorkflowSpecCardComponent} from './workflow-spec-card.component'; + +describe('WorkflowSpecCardComponent', () => { + let component: WorkflowSpecCardComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ + WorkflowSpecCardComponent, + FileListComponent, + GetIconCodePipe, + ], + imports: [ + HttpClientTestingModule, + MatCardModule, + MatDialogModule, + MatIconModule, + MatListModule, + MatSnackBarModule, + RouterTestingModule, + ], + providers: [ + ApiService, + {provide: 'APP_ENVIRONMENT', useClass: MockEnvironment}, + { + provide: MatDialogRef, + useValue: { + close: (dialogResult: any) => { + }, + } + }, + {provide: MAT_DIALOG_DATA, useValue: []}, + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(WorkflowSpecCardComponent); + component = fixture.componentInstance; + component.workflowSpec = mockWorkflowSpec0; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/workflow-spec-card/workflow-spec-card.component.ts b/src/app/workflow-spec-card/workflow-spec-card.component.ts new file mode 100644 index 0000000..eb70e06 --- /dev/null +++ b/src/app/workflow-spec-card/workflow-spec-card.component.ts @@ -0,0 +1,19 @@ +import {Component, Input, OnInit, TemplateRef} from '@angular/core'; +import {WorkflowSpec} from 'sartography-workflow-lib'; + +@Component({ + selector: 'app-workflow-spec-card', + templateUrl: './workflow-spec-card.component.html', + styleUrls: ['./workflow-spec-card.component.scss'] +}) +export class WorkflowSpecCardComponent implements OnInit { + @Input() workflowSpec: WorkflowSpec; + @Input() actionButtons: TemplateRef; + + constructor() { + } + + ngOnInit(): void { + } + +} diff --git a/src/app/workflow-spec-list/workflow-spec-list.component.html b/src/app/workflow-spec-list/workflow-spec-list.component.html index e1af6d9..2ac6ce6 100644 --- a/src/app/workflow-spec-list/workflow-spec-list.component.html +++ b/src/app/workflow-spec-list/workflow-spec-list.component.html @@ -1,50 +1,45 @@ -
+

Workflow Specifications

-
-
-
-

{{cat.display_name}}

- - - -

- {{wfs.display_name}} - -

-
- -

{{wfs.name}}

-
{{wfs.id}}
-
- - -
- -

{{wfs.description}}

- -
- - - - -
+ + +
+

{{cat.display_name}} ({{cat.name}})

+
+ + +
+
+
+ + + +
+ + +
+
+
+
No workflow specs in this category
+
+
diff --git a/src/app/workflow-spec-list/workflow-spec-list.component.scss b/src/app/workflow-spec-list/workflow-spec-list.component.scss index 4b4a88c..c61b1b3 100644 --- a/src/app/workflow-spec-list/workflow-spec-list.component.scss +++ b/src/app/workflow-spec-list/workflow-spec-list.component.scss @@ -1,4 +1,25 @@ -mat-card { - margin-bottom: 1em; - border: 1px solid #CCCCCC; +.container { + padding: 3rem; +} + +.category { + padding: 1rem 1rem 1rem 0; + + h2 { + margin: 1rem 1rem 1rem 0; + } + + .category-actions { + opacity: 0; + + &:hover { + opacity: 1; + } + } + + &:hover { + .category-actions { + opacity: 1; + } + } } diff --git a/src/app/workflow-spec-list/workflow-spec-list.component.spec.ts b/src/app/workflow-spec-list/workflow-spec-list.component.spec.ts index f9156f2..393857c 100644 --- a/src/app/workflow-spec-list/workflow-spec-list.component.spec.ts +++ b/src/app/workflow-spec-list/workflow-spec-list.component.spec.ts @@ -96,6 +96,7 @@ describe('WorkflowSpecListComponent', () => { name: '', display_name: '', description: '', + workflow_spec_category_id: 0, }; const _upsertWorkflowSpecificationSpy = spyOn((component as any), '_upsertWorkflowSpecification') diff --git a/src/app/workflow-spec-list/workflow-spec-list.component.ts b/src/app/workflow-spec-list/workflow-spec-list.component.ts index 55ec975..71d1718 100644 --- a/src/app/workflow-spec-list/workflow-spec-list.component.ts +++ b/src/app/workflow-spec-list/workflow-spec-list.component.ts @@ -2,10 +2,12 @@ import {Component, OnInit} from '@angular/core'; import {MatDialog} from '@angular/material/dialog'; import {MatSnackBar} from '@angular/material/snack-bar'; import {ApiService, WorkflowSpec, WorkflowSpecCategory} from 'sartography-workflow-lib'; +import {DeleteWorkflowSpecCategoryDialogComponent} from '../_dialogs/delete-workflow-spec-category-dialog/delete-workflow-spec-category-dialog.component'; import {DeleteWorkflowSpecDialogComponent} from '../_dialogs/delete-workflow-spec-dialog/delete-workflow-spec-dialog.component'; import {WorkflowSpecCategoryDialogComponent} from '../_dialogs/workflow-spec-category-dialog/workflow-spec-category-dialog.component'; import {WorkflowSpecDialogComponent} from '../_dialogs/workflow-spec-dialog/workflow-spec-dialog.component'; import { + DeleteWorkflowSpecCategoryDialogData, DeleteWorkflowSpecDialogData, WorkflowSpecCategoryDialogData, WorkflowSpecDialogData @@ -28,13 +30,14 @@ export class WorkflowSpecListComponent implements OnInit { selectedSpec: WorkflowSpec; selectedCat: WorkflowSpecCategory; workflowSpecsByCategory: WorklflowSpecCategoryGroup[] = []; + categories: WorkflowSpecCategory[]; constructor( private api: ApiService, private snackBar: MatSnackBar, public dialog: MatDialog ) { - this._loadWorkflowSpecs(); + this._loadWorkflowSpecCategories(); } ngOnInit() { @@ -52,6 +55,7 @@ export class WorkflowSpecListComponent implements OnInit { name: this.selectedSpec ? this.selectedSpec.name || this.selectedSpec.id : '', display_name: this.selectedSpec ? this.selectedSpec.display_name : '', description: this.selectedSpec ? this.selectedSpec.description : '', + workflow_spec_category_id: this.selectedSpec ? this.selectedSpec.workflow_spec_category_id : '', }, }); @@ -83,6 +87,21 @@ export class WorkflowSpecListComponent implements OnInit { }); } + confirmDeleteWorkflowSpecCategory(cat: WorkflowSpecCategory) { + const dialogRef = this.dialog.open(DeleteWorkflowSpecCategoryDialogComponent, { + data: { + confirm: false, + category: cat, + } + }); + + dialogRef.afterClosed().subscribe((data: DeleteWorkflowSpecCategoryDialogData) => { + if (data && data.confirm && data.category) { + this._deleteWorkflowSpecCategory(data.category); + } + }); + } + confirmDeleteWorkflowSpec(wfs: WorkflowSpec) { const dialogRef = this.dialog.open(DeleteWorkflowSpecDialogComponent, { data: { @@ -98,39 +117,34 @@ export class WorkflowSpecListComponent implements OnInit { }); } - private _loadWorkflowSpecs() { - this.api.getWorkflowSpecList().subscribe(wfs => { - this.workflowSpecs = wfs; - this.workflowSpecs.forEach(wf => { - if (wf.workflow_spec_category) { - const cat = this.workflowSpecsByCategory.find(c => c.id === wf.workflow_spec_category_id); - if (cat) { - cat.workflow_specs.push(wf); - } else { - this.workflowSpecsByCategory.push({ - id: wf.workflow_spec_category_id, - name: wf.workflow_spec_category.name, - display_name: wf.workflow_spec_category.display_name, - workflow_specs: [wf], - }); - } - } else { - const cat = this.workflowSpecsByCategory.find(c => c.id === -1); - if (cat) { - cat.workflow_specs.push(wf); - } else { - this.workflowSpecsByCategory.push({ - id: -1, - name: 'none', - display_name: 'No category', - workflow_specs: [wf], - }); - } - } + private _loadWorkflowSpecCategories() { + this.api.getWorkflowSpecCategoryList().subscribe(cats => { + this.categories = cats; + this.workflowSpecsByCategory = [{ + id: null, + name: 'none', + display_name: 'No category', + workflow_specs: [], + }]; + + this.categories.forEach((cat, i) => { + this.workflowSpecsByCategory.push(cat); + this.workflowSpecsByCategory[i + 1].workflow_specs = []; }); + + this._loadWorkflowSpecs(); }); } + private _loadWorkflowSpecs() { + this.api.getWorkflowSpecList().subscribe(wfs => { + this.workflowSpecs = wfs; + this.workflowSpecsByCategory.forEach(cat => { + cat.workflow_specs = this.workflowSpecs.filter(wf => wf.workflow_spec_category_id === cat.id); + }); + }); + } + private _upsertWorkflowSpecification(data: WorkflowSpecDialogData) { if (data.id && data.name && data.display_name && data.description) { @@ -142,6 +156,7 @@ export class WorkflowSpecListComponent implements OnInit { name: data.name, display_name: data.display_name, description: data.description, + workflow_spec_category_id: data.workflow_spec_category_id, }; if (specId) { @@ -173,14 +188,14 @@ export class WorkflowSpecListComponent implements OnInit { } private _updateWorkflowSpec(specId: string, newSpec: WorkflowSpec) { - this.api.updateWorkflowSpecification(specId, newSpec).subscribe(spec => { + this.api.updateWorkflowSpecification(specId, newSpec).subscribe(_ => { this._loadWorkflowSpecs(); this._displayMessage('Saved changes to workflow spec.'); }); } private _addWorkflowSpec(newSpec: WorkflowSpec) { - this.api.addWorkflowSpecification(newSpec).subscribe(spec => { + this.api.addWorkflowSpecification(newSpec).subscribe(_ => { this._loadWorkflowSpecs(); this._displayMessage('Saved new workflow spec.'); }); @@ -194,22 +209,22 @@ export class WorkflowSpecListComponent implements OnInit { } private _updateWorkflowSpecCategory(catId: number, newCat: WorkflowSpecCategory) { - this.api.updateWorkflowSpecCategory(catId, newCat).subscribe(spec => { - this._loadWorkflowSpecs(); + this.api.updateWorkflowSpecCategory(catId, newCat).subscribe(_ => { + this._loadWorkflowSpecCategories(); this._displayMessage('Saved changes to workflow spec category.'); }); } private _addWorkflowSpecCategory(newCat: WorkflowSpecCategory) { - this.api.addWorkflowSpecCategory(newCat).subscribe(spec => { - this._loadWorkflowSpecs(); + this.api.addWorkflowSpecCategory(newCat).subscribe(_ => { + this._loadWorkflowSpecCategories(); this._displayMessage('Saved new workflow spec category.'); }); } private _deleteWorkflowSpecCategory(workflowSpecCategory: WorkflowSpecCategory) { this.api.deleteWorkflowSpecCategory(workflowSpecCategory.id).subscribe(() => { - this._loadWorkflowSpecs(); + this._loadWorkflowSpecCategories(); this._displayMessage(`Deleted workflow spec category ${workflowSpecCategory.name}.`); }); }