Merge pull request #110 from sartography/chore/bpmn-refactor-455

Chore/bpmn refactor 455
This commit is contained in:
Dan Funk 2021-10-13 12:10:14 -04:00 committed by GitHub
commit 97736f824f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 89 additions and 51 deletions

View File

@ -26,6 +26,14 @@ Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
One way to check for coverage:
Install lcov (in ubuntu: sudo apt-get install lcov)
run `ng test --no-watch --code-coverage` to generate a coverage directory, with an lcov file in it
run `genhtml coverage/lcov.info -o coverage/html` to generate an html doc that looks at coverage (index.html)
## Further help ## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).

View File

@ -1,5 +1,5 @@
<div mat-dialog-title *ngIf="data && data.category"> <div mat-dialog-title *ngIf="data && data.category">
Delete category <strong>{{data.category.id}}</strong>? Delete category <strong>{{data.category.display_name}}</strong>?
<button mat-icon-button mat-dialog-close=""><mat-icon>close</mat-icon></button> <button mat-icon-button mat-dialog-close=""><mat-icon>close</mat-icon></button>
</div> </div>
<div mat-dialog-content> <div mat-dialog-content>

View File

@ -1,7 +1,11 @@
<div mat-dialog-title> <div *ngIf="!this.data.library" mat-dialog-title>
<h1>Workflow Specification</h1> <h1>Workflow Specification</h1>
</div> </div>
<div *ngIf="this.data.library" mat-dialog-title>
<h1>Library Specification</h1>
</div>
<div mat-dialog-content> <div mat-dialog-content>
<form [formGroup]="form"> <form [formGroup]="form">
<formly-form [model]="model" [fields]="fields" [options]="options" [form]="form"></formly-form> <formly-form [model]="model" [fields]="fields" [options]="options" [form]="form"></formly-form>

View File

@ -1,3 +1,3 @@
::ng-deep formly-field mat-form-field { ::ng-deep formly-field mat-form-field {
margin-bottom: 40px;
} }

View File

@ -68,6 +68,7 @@ export class WorkflowSpecDialogComponent {
required: true, required: true,
options: this.categories options: this.categories
}, },
hideExpression: this.data.library,
}, },
{ {
key: 'display_name', key: 'display_name',
@ -92,25 +93,15 @@ export class WorkflowSpecDialogComponent {
required: true, required: true,
}, },
}, },
{ {
key: 'standalone', key: 'standalone',
type: 'checkbox',
defaultValue: this.data.standalone ? this.data.standalone : false, defaultValue: this.data.standalone ? this.data.standalone : false,
templateOptions: { hideExpression: true,
label: 'Standalone',
description: 'Is this a standalone workflow?',
indeterminate: false,
},
}, },
{ {
key: 'library', key: 'library',
type: 'checkbox',
defaultValue: this.data.library ? this.data.library : false, defaultValue: this.data.library ? this.data.library : false,
templateOptions: { hideExpression: true,
label: 'Library',
description: 'Is this a library workflow?',
indeterminate: false,
},
}, },
]; ];
}); });

View File

@ -18,9 +18,6 @@
<dl gdAreas="field value" gdColumns="10ch auto"> <dl gdAreas="field value" gdColumns="10ch auto">
<dt>Name</dt><dd>{{workflowSpec.id}}</dd> <dt>Name</dt><dd>{{workflowSpec.id}}</dd>
<dt>Description</dt><dd>{{workflowSpec.description}}</dd> <dt>Description</dt><dd>{{workflowSpec.description}}</dd>
<dt>Standalone</dt><dd *ngIf="workflowSpec.standalone; then thenBlock else elseBlock"></dd>
<ng-template #thenBlock><dd>True</dd></ng-template>
<ng-template #elseBlock><dd>False</dd></ng-template>
</dl> </dl>
<h4>Workflow Spec Files</h4> <h4>Workflow Spec Files</h4>
<app-file-list [workflowSpec]="workflowSpec"></app-file-list> <app-file-list [workflowSpec]="workflowSpec"></app-file-list>

View File

@ -1,22 +1,16 @@
<div class="workflow-specs" fxLayout="column" fxLayoutGap="10px"> <div class="workflow-specs" fxLayout="column" fxLayoutGap="10px">
<h1>Workflow Specifications</h1> <div class="buttons" fxLayout="row" fxLayoutGap="20px">
<div class="buttons" fxLayout="row" fxLayoutGap="10px"> <div>
<button id="add_spec" mat-flat-button color="primary" (click)="editWorkflowSpec()" fxLayoutAlign="stretch"> <h1 style="margin-top: 16px">Workflow Specifications</h1>
<mat-icon>library_add</mat-icon> </div>
Add new workflow specification
</button>
<button id="add_category" mat-flat-button color="accent" (click)="editWorkflowSpecCategory()" fxLayoutAlign="stretch">
<mat-icon>post_add</mat-icon>
Add category
</button>
<mat-form-field class="search-field"> <mat-form-field class="search-field">
<label><input matInput type="search" placeholder="Search Workflows" class="form-control" [formControl]="searchField"></label> <label><input matInput type="search" placeholder="Search Workflows" fxLayoutAlign="start" style="margin-top: 0;" class="form-control" [formControl]="searchField"></label>
</mat-form-field> </mat-form-field>
</div> </div>
<mat-drawer-container class="example-container" autosize> <mat-drawer-container class="example-container" autosize>
<mat-drawer #drawer class="example-sidenav" mode="side" opened="true"> <mat-drawer #drawer class="example-sidenav" mode="side" opened="true">
<ng-container *ngIf="masterStatusSpec"> <ng-container *ngIf="masterStatusSpec">
<div class="category"> <div class="category-top">
<h4>Master Specification</h4> <h4>Master Specification</h4>
<mat-list> <mat-list>
<mat-list-item class="workflow-spec" fxLayout="row"> <mat-list-item class="workflow-spec" fxLayout="row">
@ -27,13 +21,20 @@
</ng-container> </ng-container>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-divider></mat-divider>
<ng-container> <ng-container>
<div class="category"> <div class="category" fxLayout="row">
<mat-accordion class="example-headers-align"> <h4 style="margin-top: 5px">Library Specs</h4>
<button id="add_spec" title="Add new Library" mat-flat-button color="primary" (click)="editWorkflowSpec('library')" fxLayoutAlign="auto">
<mat-icon>library_add</mat-icon>
</button>
</div>
<mat-divider></mat-divider>
<mat-accordion class="example-headers-align">
<mat-expansion-panel> <mat-expansion-panel>
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
<h4>Libraries</h4> <h4>All Libraries</h4>
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<mat-list> <mat-list>
@ -45,16 +46,21 @@
</mat-list> </mat-list>
</mat-expansion-panel> </mat-expansion-panel>
</mat-accordion> </mat-accordion>
</div>
</ng-container> </ng-container>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<ng-container> <ng-container>
<div class="category"> <div class="category" fxLayout="row">
<h4>Categories</h4> <h4 style="margin-top: 5px">Study Specs</h4>
<button id="add_category" title="Add new Category" mat-flat-button color="accent" (click)="editWorkflowSpecCategory()" fxLayoutAlign="stretch">
<mat-icon>post_add</mat-icon>
</button>
<button id="add_library" title="Add new Study Spec" mat-flat-button color="primary" (click)="editWorkflowSpec('study')" fxLayoutAlign="start">
<mat-icon>library_add</mat-icon>
</button>
</div> </div>
<mat-divider></mat-divider> <mat-divider></mat-divider>
@ -162,7 +168,7 @@
(click)="validateWorkflowSpec(wfs)"> (click)="validateWorkflowSpec(wfs)">
<mat-icon>verified_user</mat-icon> <mat-icon>verified_user</mat-icon>
</button> </button>
<button mat-mini-fab title="Edit this workflow specification" color="primary" (click)="editWorkflowSpec(wfs)"> <button mat-mini-fab title="Edit this workflow specification" color="primary" (click)="editWorkflowSpec(this.selectedSpec.library ? 'library' : 'study', wfs)">
<mat-icon>edit</mat-icon> <mat-icon>edit</mat-icon>
</button> </button>
<button mat-icon-button title="Delete this workflow specification" color="warn" <button mat-icon-button title="Delete this workflow specification" color="warn"

View File

@ -16,8 +16,31 @@
min-height: 600px; min-height: 600px;
} }
.category-top {
padding: 0 1rem 1rem 0;
h4 {
margin: 1rem 1rem 0 0;
}
.category-actions {
opacity: 0;
&:hover {
opacity: 1;
}
}
&:hover {
.category-actions {
opacity: 1;
}
}
}
.category { .category {
padding: 1rem 1rem 0 0; padding: 2rem 1rem 1rem 0;
h4 { h4 {
margin: 1rem 1rem 0 0; margin: 1rem 1rem 0 0;

View File

@ -167,12 +167,12 @@ describe('WorkflowSpecListComponent', () => {
component.selectedSpec = mockWorkflowSpec1; component.selectedSpec = mockWorkflowSpec1;
component.selectedSpec.parents = []; component.selectedSpec.parents = [];
component.selectedSpec.libraries = []; component.selectedSpec.libraries = [];
component.editWorkflowSpec(); component.editWorkflowSpec('study');
expect(openDialogSpy).toHaveBeenCalled(); expect(openDialogSpy).toHaveBeenCalled();
expect(_upsertWorkflowSpecificationSpy).not.toHaveBeenCalled(); expect(_upsertWorkflowSpecificationSpy).not.toHaveBeenCalled();
mockSpecData = mockWorkflowSpec0 as WorkflowSpecDialogData; mockSpecData = mockWorkflowSpec0 as WorkflowSpecDialogData;
component.editWorkflowSpec(mockWorkflowSpec0); component.editWorkflowSpec('study', mockWorkflowSpec0);
expect(openDialogSpy).toHaveBeenCalled(); expect(openDialogSpy).toHaveBeenCalled();
expect(_upsertWorkflowSpecificationSpy).toHaveBeenCalled(); expect(_upsertWorkflowSpecificationSpy).toHaveBeenCalled();
}); });
@ -199,6 +199,7 @@ describe('WorkflowSpecListComponent', () => {
it('should add a workflow spec', () => { it('should add a workflow spec', () => {
const _loadWorkflowSpecsSpy = spyOn((component as any), '_loadWorkflowSpecs').and.stub(); const _loadWorkflowSpecsSpy = spyOn((component as any), '_loadWorkflowSpecs').and.stub();
const _loadWorkflowLibrariesSpy = spyOn((component as any), '_loadWorkflowLibraries').and.stub();
const _displayMessageSpy = spyOn((component as any), '_displayMessage').and.stub(); const _displayMessageSpy = spyOn((component as any), '_displayMessage').and.stub();
(component as any)._addWorkflowSpec(mockWorkflowSpec0); (component as any)._addWorkflowSpec(mockWorkflowSpec0);
const wfsReq = httpMock.expectOne(`apiRoot/workflow-specification`); const wfsReq = httpMock.expectOne(`apiRoot/workflow-specification`);
@ -206,6 +207,7 @@ describe('WorkflowSpecListComponent', () => {
wfsReq.flush(mockWorkflowSpec0); wfsReq.flush(mockWorkflowSpec0);
expect(_loadWorkflowSpecsSpy).toHaveBeenCalled(); expect(_loadWorkflowSpecsSpy).toHaveBeenCalled();
expect(_loadWorkflowLibrariesSpy).toHaveBeenCalled();
expect(_displayMessageSpy).toHaveBeenCalled(); expect(_displayMessageSpy).toHaveBeenCalled();
}); });
@ -248,12 +250,14 @@ describe('WorkflowSpecListComponent', () => {
it('should delete a workflow spec', () => { it('should delete a workflow spec', () => {
const loadWorkflowSpecsSpy = spyOn((component as any), '_loadWorkflowSpecs').and.stub(); const loadWorkflowSpecsSpy = spyOn((component as any), '_loadWorkflowSpecs').and.stub();
const _loadWorkflowLibrariesSpy = spyOn((component as any), '_loadWorkflowLibraries').and.stub();
(component as any)._deleteWorkflowSpec(mockWorkflowSpec0); (component as any)._deleteWorkflowSpec(mockWorkflowSpec0);
const wfsReq = httpMock.expectOne(`apiRoot/workflow-specification/${mockWorkflowSpec0.id}`); const wfsReq = httpMock.expectOne(`apiRoot/workflow-specification/${mockWorkflowSpec0.id}`);
expect(wfsReq.request.method).toEqual('DELETE'); expect(wfsReq.request.method).toEqual('DELETE');
wfsReq.flush(null); wfsReq.flush(null);
expect(loadWorkflowSpecsSpy).toHaveBeenCalled(); expect(loadWorkflowSpecsSpy).toHaveBeenCalled();
expect(_loadWorkflowLibrariesSpy).toHaveBeenCalled();
}); });
it('should show a metadata dialog when editing a workflow spec category', () => { it('should show a metadata dialog when editing a workflow spec category', () => {

View File

@ -79,7 +79,6 @@ export class WorkflowSpecListComponent implements OnInit {
this.searchField = new FormControl(); this.searchField = new FormControl();
this.searchField.valueChanges.subscribe(value => { this.searchField.valueChanges.subscribe(value => {
this._loadWorkflowSpecs(null, value); this._loadWorkflowSpecs(null, value);
console.log(value);
}); });
} }
@ -112,6 +111,7 @@ export class WorkflowSpecListComponent implements OnInit {
} }
canSaveWorkflowSpec(proposed: WorkflowSpecDialogData){ canSaveWorkflowSpec(proposed: WorkflowSpecDialogData){
// Can possibly remove or bypass this method alltogether
if ((this.selectedSpec.parents.length > 0) && (!proposed.library)){ if ((this.selectedSpec.parents.length > 0) && (!proposed.library)){
this.snackBar.open('This Workflow Specification is still being used as a Library. Please remove references first!', 'Ok', { duration: 5000 }); this.snackBar.open('This Workflow Specification is still being used as a Library. Please remove references first!', 'Ok', { duration: 5000 });
return false; return false;
@ -123,7 +123,7 @@ export class WorkflowSpecListComponent implements OnInit {
return true; return true;
} }
editWorkflowSpec(selectedSpec?: WorkflowSpec) { editWorkflowSpec(state: String, selectedSpec?: WorkflowSpec) {
const hasDisplayOrder = selectedSpec && isNumberDefined(selectedSpec.display_order); const hasDisplayOrder = selectedSpec && isNumberDefined(selectedSpec.display_order);
const dialogData: WorkflowSpecDialogData = { const dialogData: WorkflowSpecDialogData = {
@ -133,7 +133,7 @@ export class WorkflowSpecListComponent implements OnInit {
category_id: selectedSpec ? selectedSpec.category_id : null, category_id: selectedSpec ? selectedSpec.category_id : null,
display_order: hasDisplayOrder ? selectedSpec.display_order : 0, display_order: hasDisplayOrder ? selectedSpec.display_order : 0,
standalone: selectedSpec ? selectedSpec.standalone : null, standalone: selectedSpec ? selectedSpec.standalone : null,
library: selectedSpec ? selectedSpec.library : null, library: selectedSpec ? selectedSpec.library : (state === 'library' ? true : null),
}; };
// Open new filename/workflow spec dialog // Open new filename/workflow spec dialog
@ -144,10 +144,12 @@ export class WorkflowSpecListComponent implements OnInit {
}); });
dialogRef.afterClosed().subscribe((data: WorkflowSpecDialogData) => { dialogRef.afterClosed().subscribe((data: WorkflowSpecDialogData) => {
data.id = this.toLowercaseId(data.id); if (data.id) {
if (data && data.id && data.display_name && data.description) { data.id = this.toLowercaseId(data.id);
if (this.canSaveWorkflowSpec(data)) { if (data && data.id && data.display_name && data.description) {
this._upsertWorkflowSpecification(selectedSpec == null, data); if (this.canSaveWorkflowSpec(data)) {
this._upsertWorkflowSpecification(selectedSpec == null, data);
}
} }
} }
}); });
@ -359,6 +361,7 @@ export class WorkflowSpecListComponent implements OnInit {
private _addWorkflowSpec(newSpec: WorkflowSpec) { private _addWorkflowSpec(newSpec: WorkflowSpec) {
this.api.addWorkflowSpecification(newSpec).subscribe(_ => { this.api.addWorkflowSpecification(newSpec).subscribe(_ => {
this._loadWorkflowLibraries();
this._loadWorkflowSpecs(newSpec.id); this._loadWorkflowSpecs(newSpec.id);
this._displayMessage('Saved new workflow spec.'); this._displayMessage('Saved new workflow spec.');
}); });
@ -367,6 +370,7 @@ export class WorkflowSpecListComponent implements OnInit {
private _deleteWorkflowSpec(workflowSpec: WorkflowSpec) { private _deleteWorkflowSpec(workflowSpec: WorkflowSpec) {
this.api.deleteWorkflowSpecification(workflowSpec.id).subscribe(() => { this.api.deleteWorkflowSpecification(workflowSpec.id).subscribe(() => {
this._loadWorkflowSpecs(); this._loadWorkflowSpecs();
this._loadWorkflowLibraries();
this._displayMessage(`Deleted workflow spec ${workflowSpec.id}.`); this._displayMessage(`Deleted workflow spec ${workflowSpec.id}.`);
}); });
} }
@ -388,7 +392,7 @@ export class WorkflowSpecListComponent implements OnInit {
private _deleteWorkflowSpecCategory(workflowSpecCategory: WorkflowSpecCategory) { private _deleteWorkflowSpecCategory(workflowSpecCategory: WorkflowSpecCategory) {
this.api.deleteWorkflowSpecCategory(workflowSpecCategory.id).subscribe(() => { this.api.deleteWorkflowSpecCategory(workflowSpecCategory.id).subscribe(() => {
this._loadWorkflowSpecCategories(); this._loadWorkflowSpecCategories();
this._displayMessage(`Deleted workflow spec category ${workflowSpecCategory.id}.`); this._displayMessage(`Deleted workflow spec category ${workflowSpecCategory.display_name}.`);
}); });
} }
@ -396,6 +400,7 @@ export class WorkflowSpecListComponent implements OnInit {
this.snackBar.open(message, 'Ok', {duration: 3000}); this.snackBar.open(message, 'Ok', {duration: 3000});
} }
/** /**
* Deprecated - backend now reorders * Deprecated - backend now reorders
* *