Merge branch 'dev' of https://github.com/sartography/cr-connect-bpmn into bug/move_workflow_spec_260

This commit is contained in:
Nile Walker 2021-03-22 13:17:14 -04:00
commit 9c441e68ca
7 changed files with 112 additions and 65 deletions

View File

@ -1,5 +1,5 @@
### STAGE 1: Build ###
FROM node AS builder
FROM quay.io/sartography/node:latest AS builder
RUN mkdir /app
WORKDIR /app
ADD package.json /app/
@ -11,7 +11,7 @@ RUN npm install && \
### STAGE 2: Run ###
FROM nginx:alpine
FROM quay.io/sartography/nginx:alpine
RUN set -x && apk add --update --no-cache bash libintl gettext curl
COPY --from=builder /app/dist/* /etc/nginx/html/

86
package-lock.json generated
View File

@ -802,6 +802,12 @@
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"ini": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"dev": true
},
"inquirer": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz",
@ -2562,6 +2568,12 @@
"semver-intersect": "1.4.0"
},
"dependencies": {
"ini": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"dev": true
},
"rxjs": {
"version": "6.5.4",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz",
@ -4113,9 +4125,9 @@
"integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw=="
},
"clipboard": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz",
"integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==",
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.7.tgz",
"integrity": "sha512-8M8WEZcIvs0hgOma+wAPkrUxpv0PMY1L6VsAJh/2DOKARIMpyWe6ZLcEoe1qktl6/ced5ceYHs+oGedSbgZ3sg==",
"optional": true,
"requires": {
"good-listener": "^1.2.2",
@ -5661,24 +5673,24 @@
"dev": true
},
"elliptic": {
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
"integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
"version": "6.5.4",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
"integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
"dev": true,
"requires": {
"bn.js": "^4.4.0",
"brorand": "^1.0.1",
"bn.js": "^4.11.9",
"brorand": "^1.1.0",
"hash.js": "^1.0.0",
"hmac-drbg": "^1.0.0",
"inherits": "^2.0.1",
"minimalistic-assert": "^1.0.0",
"minimalistic-crypto-utils": "^1.0.0"
"hmac-drbg": "^1.0.1",
"inherits": "^2.0.4",
"minimalistic-assert": "^1.0.1",
"minimalistic-crypto-utils": "^1.0.1"
},
"dependencies": {
"bn.js": {
"version": "4.11.9",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
"dev": true
}
}
@ -7308,8 +7320,8 @@
},
"ini": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
"resolved": "",
"dev": true
},
"inquirer": {
"version": "3.0.6",
@ -8848,9 +8860,10 @@
}
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true
},
"minipass": {
"version": "3.1.3",
@ -9141,9 +9154,9 @@
}
},
"node-forge": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz",
"integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==",
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
"integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==",
"dev": true
},
"node-libs-browser": {
@ -9568,6 +9581,13 @@
"minimist": "1.2.0",
"node-fetch": "1.6.3",
"opn": "4.0.2"
},
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
}
}
},
"opn": {
@ -10911,9 +10931,9 @@
"dev": true
},
"prismjs": {
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.20.0.tgz",
"integrity": "sha512-AEDjSrVNkynnw6A+B1DsFkd6AVdTnp+/WoUixFRULlCLZVRZlVQMVWio/16jv7G1FscUxQxOQhWwApgbnxr6kQ==",
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.23.0.tgz",
"integrity": "sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==",
"requires": {
"clipboard": "^2.0.0"
}
@ -11900,9 +11920,9 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sartography-workflow-lib": {
"version": "0.0.396",
"resolved": "https://registry.npmjs.org/sartography-workflow-lib/-/sartography-workflow-lib-0.0.396.tgz",
"integrity": "sha512-gfdlq7sFpoX2nzigkQtgzY9kapHUeYar5FI80AqsOEkQU0Rh6gKO++hG3NN6zlqmYtQHFtJd+shSXOgbS6xEsQ=="
"version": "0.0.415",
"resolved": "https://registry.npmjs.org/sartography-workflow-lib/-/sartography-workflow-lib-0.0.415.tgz",
"integrity": "sha512-dc/JObsAq0TqGra/NuHG23EpmXrfnQqxbhGWXXkTfySDcA9beRNxJ5nd7xlc8EZzbUiWXIKxVM3xiyBCBQ+88A=="
},
"sass": {
"version": "1.26.3",
@ -12062,12 +12082,12 @@
}
},
"selfsigned": {
"version": "1.10.7",
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz",
"integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==",
"version": "1.10.8",
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz",
"integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==",
"dev": true,
"requires": {
"node-forge": "0.9.0"
"node-forge": "^0.10.0"
}
},
"semver": {

View File

@ -54,7 +54,7 @@
"ngx-markdown": "^9.1.1",
"protractor": "^7.0.0",
"rxjs": "~6.5.4",
"sartography-workflow-lib": "0.0.396",
"sartography-workflow-lib": "0.0.415",
"tslib": "^1.13.0",
"uuid": "^7.0.2",
"zone.js": "^0.10.3"

View File

@ -1,11 +1,11 @@
<div class="container mat-typography" fxLayout="column" fxLayoutGap="10px">
<h1>Workflow Specifications</h1>
<div fxLayout="row" fxLayoutGap="10px">
<button mat-flat-button color="primary" (click)="editWorkflowSpec()">
<button id="add_spec" mat-flat-button color="primary" (click)="editWorkflowSpec()">
<mat-icon>library_add</mat-icon>
Add new workflow specification
</button>
<button mat-flat-button color="accent" (click)="editWorkflowSpecCategory()">
<button id="add_category" mat-flat-button color="accent" (click)="editWorkflowSpecCategory()">
<mat-icon>post_add</mat-icon>
Add category
</button>

View File

@ -1,9 +1,9 @@
import {APP_BASE_HREF} from '@angular/common';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {async, ComponentFixture, fakeAsync, TestBed} from '@angular/core/testing';
import {MAT_BOTTOM_SHEET_DATA, MatBottomSheetModule, MatBottomSheetRef} from '@angular/material/bottom-sheet';
import {MatCardModule} from '@angular/material/card';
import {MAT_DIALOG_DATA, MatDialogModule, MatDialogRef} from '@angular/material/dialog';
import {MAT_DIALOG_DATA, MatDialog, 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';
@ -11,7 +11,7 @@ import {BrowserDynamicTestingModule} from '@angular/platform-browser-dynamic/tes
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {RouterTestingModule} from '@angular/router/testing';
import createClone from 'rfdc';
import {of} from 'rxjs';
import {Observable, of} from 'rxjs';
import {
ApiErrorsComponent,
ApiService,
@ -37,11 +37,26 @@ import {
import {GetIconCodePipe} from '../_pipes/get-icon-code.pipe';
import {FileListComponent} from '../file-list/file-list.component';
import {WorkflowSpecListComponent} from './workflow-spec-list.component';
import {WorkflowSpecDialogComponent} from '../_dialogs/workflow-spec-dialog/workflow-spec-dialog.component';
export class MdDialogMock {
// When the component calls this.dialog.open(...) we'll return an object
// with an afterClosed method that allows to subscribe to the dialog result observable.
open() {
return {
afterClosed: () => of([
{}
])
};
}
}
describe('WorkflowSpecListComponent', () => {
let httpMock: HttpTestingController;
let component: WorkflowSpecListComponent;
let fixture: ComponentFixture<WorkflowSpecListComponent>;
let dialog: MatDialog;
beforeEach(async(() => {
TestBed.configureTestingModule({
@ -68,11 +83,7 @@ describe('WorkflowSpecListComponent', () => {
{provide: 'APP_ENVIRONMENT', useClass: MockEnvironment},
{provide: APP_BASE_HREF, useValue: ''},
{
provide: MatDialogRef,
useValue: {
close: (dialogResult: any) => {
},
}
provide: MatDialogRef, useClass: MdDialogMock,
},
{provide: MAT_DIALOG_DATA, useValue: []},
{
@ -100,6 +111,7 @@ describe('WorkflowSpecListComponent', () => {
fixture = TestBed.createComponent(WorkflowSpecListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
dialog = TestBed.inject(MatDialog);
const catReq = httpMock.expectOne('apiRoot/workflow-specification-category');
expect(catReq.request.method).toEqual('GET');
@ -151,7 +163,7 @@ describe('WorkflowSpecListComponent', () => {
const _updateWorkflowSpecSpy = spyOn((component as any), '_updateWorkflowSpec').and.stub();
component.selectedSpec = undefined;
(component as any)._upsertWorkflowSpecification(mockWorkflowSpec1 as WorkflowSpecDialogData);
(component as any)._upsertWorkflowSpecification(true, mockWorkflowSpec1 as WorkflowSpecDialogData);
expect(_addWorkflowSpecSpy).toHaveBeenCalled();
expect(_updateWorkflowSpecSpy).not.toHaveBeenCalled();
@ -161,7 +173,7 @@ describe('WorkflowSpecListComponent', () => {
component.selectedSpec = mockWorkflowSpec0;
const modifiedData: WorkflowSpecDialogData = createClone({circles: true})(mockWorkflowSpec0);
modifiedData.display_name = 'Modified';
(component as any)._upsertWorkflowSpecification(modifiedData);
(component as any)._upsertWorkflowSpecification(false, modifiedData);
expect(_addWorkflowSpecSpy).not.toHaveBeenCalled();
expect(_updateWorkflowSpecSpy).toHaveBeenCalled();
});
@ -454,6 +466,8 @@ describe('WorkflowSpecListComponent', () => {
expect(_loadWorkflowSpecCategoriesSpy).toHaveBeenCalled();
});
it('should load master workflow spec', () => {
const mockMasterSpec: WorkflowSpec = {
id: 'master_status_spec',
@ -480,4 +494,14 @@ describe('WorkflowSpecListComponent', () => {
expect(component.masterStatusSpec).toEqual(mockMasterSpec);
});
it('should call editWorkflowSpec, open Dialog & call _upsertWorkflowSpecification when Edit button is clicked', fakeAsync(() => {
spyOn(dialog, 'open').and.callThrough();
const _upsertWorkflowSpecification = spyOn((component as any), '_upsertWorkflowSpecification').and.stub();
const button = fixture.debugElement.nativeElement.querySelector('#add_spec');
button.click();
const req = httpMock.expectOne(`apiRoot/workflow-specification-category`);
expect(dialog.open).toHaveBeenCalled();
}
));
});

View File

@ -97,16 +97,20 @@ export class WorkflowSpecListComponent implements OnInit {
this.location.replaceState(environment.homeRoute + '/' + selectedSpec.name);
}
categoryExpanded(cat: WorkflowSpecCategory) {
return this.selectedSpec != null && this.selectedSpec.category_id === cat.id;
}
editWorkflowSpec(selectedSpec?: WorkflowSpec) {
this.selectedSpec = selectedSpec;
const hasDisplayOrder = this.selectedSpec && isNumberDefined(this.selectedSpec.display_order);
const hasDisplayOrder = selectedSpec && isNumberDefined(selectedSpec.display_order);
const dialogData: WorkflowSpecDialogData = {
id: this.selectedSpec ? this.selectedSpec.id : '',
name: this.selectedSpec ? this.selectedSpec.name || this.selectedSpec.id : '',
display_name: this.selectedSpec ? this.selectedSpec.display_name : '',
description: this.selectedSpec ? this.selectedSpec.description : '',
category_id: this.selectedSpec ? this.selectedSpec.category_id : null,
display_order: hasDisplayOrder ? this.selectedSpec.display_order : 0,
id: selectedSpec ? selectedSpec.id : '',
name: selectedSpec ? selectedSpec.name || selectedSpec.id : '',
display_name: selectedSpec ? selectedSpec.display_name : '',
description: selectedSpec ? selectedSpec.description : '',
category_id: selectedSpec ? selectedSpec.category_id : null,
display_order: hasDisplayOrder ? selectedSpec.display_order : 0,
};
// Open new filename/workflow spec dialog
@ -118,7 +122,7 @@ export class WorkflowSpecListComponent implements OnInit {
dialogRef.afterClosed().subscribe((data: WorkflowSpecDialogData) => {
if (data && data.id && data.name && data.display_name && data.description) {
this._upsertWorkflowSpecification(data);
this._upsertWorkflowSpecification(selectedSpec == null, data);
}
});
}
@ -171,6 +175,7 @@ export class WorkflowSpecListComponent implements OnInit {
dialogRef.afterClosed().subscribe((data: DeleteWorkflowSpecDialogData) => {
if (data && data.confirm && data.workflowSpec) {
this._deleteWorkflowSpec(data.workflowSpec);
this.selectedSpec = this.masterStatusSpec;
}
});
}
@ -211,7 +216,6 @@ export class WorkflowSpecListComponent implements OnInit {
this.api.getWorkflowSpecList().subscribe(wfs => {
this.workflowSpecs = wfs;
this.workflowSpecsByCategory.forEach(cat => {
cat.workflow_specs = this.workflowSpecs
.filter(wf => {
@ -244,12 +248,9 @@ export class WorkflowSpecListComponent implements OnInit {
});
}
private _upsertWorkflowSpecification(data: WorkflowSpecDialogData) {
private _upsertWorkflowSpecification(isNew: boolean, data: WorkflowSpecDialogData) {
if (data.id && data.name && data.display_name && data.description) {
// Save old workflow spec id, in case it's changed
const specId = this.selectedSpec ? this.selectedSpec.id : undefined;
const newSpec: WorkflowSpec = {
id: data.id,
name: data.name,
@ -259,10 +260,10 @@ export class WorkflowSpecListComponent implements OnInit {
display_order: data.display_order,
};
if (specId) {
this._updateWorkflowSpec(specId, newSpec);
} else {
if (isNew) {
this._addWorkflowSpec(newSpec);
} else {
this._updateWorkflowSpec(data.id, newSpec);
}
}
}
@ -389,5 +390,7 @@ export class WorkflowSpecListComponent implements OnInit {
});
});
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB