Fixes various bugs with opening and saving files. Saves files to the selected workflow spec. Displays selected workflow spec in toolbar.
This commit is contained in:
parent
7142069b0f
commit
a01a6594a2
|
@ -1,7 +1,6 @@
|
|||
import {FileType} from 'sartography-workflow-lib';
|
||||
|
||||
export interface FileMetaDialogData {
|
||||
fileName: string;
|
||||
workflowSpecId: string;
|
||||
name: string;
|
||||
displayName: string;
|
||||
description: string;
|
||||
fileType: FileType;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import {FileType} from 'sartography-workflow-lib';
|
||||
|
||||
export const trimString = (str: string): string => {
|
||||
return !str ? '' : String(str).replace(/^\W+|\W+$/gi, '');
|
||||
};
|
||||
|
@ -9,12 +11,12 @@ export const toSnakeCase = (str: string): string => {
|
|||
.toLowerCase();
|
||||
};
|
||||
|
||||
export const cleanUpFilename = (str: string, extension: string): string => {
|
||||
export const cleanUpFilename = (str: string, extension: FileType|string): string => {
|
||||
const arr = trimString(str).split('.');
|
||||
|
||||
// Add file extension, if necessary
|
||||
if (arr.length < 2) {
|
||||
arr.push('bpmn');
|
||||
arr.push(extension);
|
||||
} else {
|
||||
(arr[arr.length - 1]) = extension;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import {DebugNode} from '@angular/core';
|
|||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {MatIconModule} from '@angular/material/icon';
|
||||
import * as FileSaver from 'file-saver';
|
||||
import {ApiService, FileType, MockEnvironment} from 'sartography-workflow-lib';
|
||||
import {ApiService, BPMN_DIAGRAM_DEFAULT, FileType, MockEnvironment} from 'sartography-workflow-lib';
|
||||
import {
|
||||
BPMN_DIAGRAM,
|
||||
BPMN_DIAGRAM_WITH_WARNINGS,
|
||||
|
@ -134,10 +134,11 @@ describe('DiagramComponent', () => {
|
|||
|
||||
it('should create a new diagram', () => {
|
||||
const initializeModelerSpy = spyOn(component, 'initializeModeler').and.stub();
|
||||
const createDiagramSpy = spyOn(component.modeler, 'createDiagram').and.stub();
|
||||
const importXMLSpy = spyOn(component.modeler, 'importXML').and.stub();
|
||||
spyOn(component, 'getRandomString').and.returnValue('REPLACE_ME');
|
||||
component.openDiagram();
|
||||
expect(initializeModelerSpy).toHaveBeenCalledWith(undefined);
|
||||
expect(createDiagramSpy).toHaveBeenCalled();
|
||||
expect(importXMLSpy).toHaveBeenCalledWith(BPMN_DIAGRAM_DEFAULT, jasmine.any(Function));
|
||||
});
|
||||
|
||||
it('should open an existing BPMN diagram from XML', () => {
|
||||
|
@ -177,10 +178,11 @@ describe('DiagramComponent', () => {
|
|||
it('should edit diagram', () => {
|
||||
const initializeModelerSpy = spyOn(component, 'initializeModeler').and.stub();
|
||||
const onChangeSpy = spyOn(component, 'onChange').and.stub();
|
||||
const createDiagramSpy = spyOn(component.modeler, 'createDiagram').and.stub();
|
||||
const importXMLSpy = spyOn(component.modeler, 'importXML').and.stub();
|
||||
spyOn(component, 'getRandomString').and.returnValue('REPLACE_ME');
|
||||
component.openDiagram();
|
||||
expect(initializeModelerSpy).toHaveBeenCalledWith(undefined);
|
||||
expect(createDiagramSpy).toHaveBeenCalled();
|
||||
expect(importXMLSpy).toHaveBeenCalledWith(BPMN_DIAGRAM_DEFAULT, jasmine.any(Function));
|
||||
|
||||
component.writeValue(BPMN_DIAGRAM);
|
||||
expect(initializeModelerSpy).toHaveBeenCalledWith(undefined);
|
||||
|
|
|
@ -4,14 +4,13 @@ import {ControlValueAccessor} from '@angular/forms';
|
|||
import BpmnModeler from 'bpmn-js/lib/Modeler';
|
||||
import DmnModeler from 'dmn-js/lib/Modeler';
|
||||
import * as fileSaver from 'file-saver';
|
||||
import {ApiService, FileType} from 'sartography-workflow-lib';
|
||||
import {DMN_DIAGRAM_EMPTY} from '../../testing/mocks/diagram.mocks';
|
||||
import {ApiService, BPMN_DIAGRAM_DEFAULT, DMN_DIAGRAM_DEFAULT, FileType} from 'sartography-workflow-lib';
|
||||
import {v4 as uuidv4} from 'uuid';
|
||||
import {BpmnWarning} from '../_interfaces/bpmn-warning';
|
||||
import {ImportEvent} from '../_interfaces/import-event';
|
||||
import {getDiagramTypeFromXml} from '../_util/diagram-type';
|
||||
import {bpmnModelerConfig} from './bpmn-modeler-config';
|
||||
import {dmnModelerConfig} from './dmn-modeler-config';
|
||||
import {v4 as uuidv4} from 'uuid';
|
||||
|
||||
@Component({
|
||||
selector: 'app-diagram',
|
||||
|
@ -89,18 +88,14 @@ export class DiagramComponent implements ControlValueAccessor, AfterViewInit {
|
|||
this.diagramType = diagramType || getDiagramTypeFromXml(xml);
|
||||
this.xml = xml;
|
||||
this.initializeModeler(diagramType);
|
||||
|
||||
return this.zone.run(() => {
|
||||
if (xml) {
|
||||
this.modeler.importXML(xml, (e, w) => this.onImport(e, w));
|
||||
} else {
|
||||
if (this.modeler.createDiagram) {
|
||||
this.modeler.createDiagram((e, w) => this.onImport(e, w));
|
||||
} else {
|
||||
const r = 'REPLACE_ME';
|
||||
const newXml = DMN_DIAGRAM_EMPTY.replace(/REPLACE_ME/gi, () => uuidv4().slice(0, 7));
|
||||
this.modeler.importXML(newXml, (e, w) => this.onImport(e, w));
|
||||
}
|
||||
if (!xml) {
|
||||
const defaultXml = diagramType === FileType.DMN ? DMN_DIAGRAM_DEFAULT : BPMN_DIAGRAM_DEFAULT;
|
||||
xml = defaultXml.replace(/REPLACE_ME/gi, () => this.getRandomString(7));
|
||||
}
|
||||
|
||||
this.modeler.importXML(xml, (e, w) => this.onImport(e, w));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -174,6 +169,11 @@ export class DiagramComponent implements ControlValueAccessor, AfterViewInit {
|
|||
this.modeler.on('import.done', ({error}) => {
|
||||
if (!error) {
|
||||
this.modeler.get('canvas').zoom('fit-viewport');
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
left: 0,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -197,6 +197,11 @@ export class DiagramComponent implements ControlValueAccessor, AfterViewInit {
|
|||
this.modeler.on('import.done', ({error}) => {
|
||||
if (!error) {
|
||||
this.modeler.getActiveViewer().get('canvas').zoom('fit-viewport');
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
left: 0,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -207,4 +212,8 @@ export class DiagramComponent implements ControlValueAccessor, AfterViewInit {
|
|||
e.innerHTML = '';
|
||||
});
|
||||
}
|
||||
|
||||
private getRandomString(len: number): string {
|
||||
return uuidv4().slice(0, len);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import {HttpClientTestingModule, HttpTestingController} from '@angular/common/ht
|
|||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {MatIconModule} from '@angular/material/icon';
|
||||
import {MatListModule} from '@angular/material/list';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
import {
|
||||
ApiService,
|
||||
FileType,
|
||||
|
@ -10,6 +11,7 @@ import {
|
|||
mockFileMetas,
|
||||
mockWorkflowSpec0
|
||||
} from 'sartography-workflow-lib';
|
||||
import {GetIconCodePipe} from '../_pipes/get-icon-code.pipe';
|
||||
import {FileListComponent} from './file-list.component';
|
||||
|
||||
describe('FileListComponent', () => {
|
||||
|
@ -23,8 +25,10 @@ describe('FileListComponent', () => {
|
|||
HttpClientTestingModule,
|
||||
MatIconModule,
|
||||
MatListModule,
|
||||
RouterTestingModule,
|
||||
],
|
||||
declarations: [
|
||||
GetIconCodePipe,
|
||||
FileListComponent
|
||||
],
|
||||
providers: [
|
||||
|
|
|
@ -1,22 +1,13 @@
|
|||
<div mat-dialog-content>
|
||||
<mat-form-field>
|
||||
<input disabled required [(ngModel)]="data.workflowSpecId" matInput placeholder="Workflow specification id">
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input required [(ngModel)]="data.name" matInput placeholder="Workflow specification name">
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input required [(ngModel)]="data.fileName" matInput placeholder="File name">
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input required [(ngModel)]="data.displayName" matInput placeholder="Display name">
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<textarea required [(ngModel)]="data.description" matInput matTextareaAutosize placeholder="Description"></textarea>
|
||||
<input disabled required [(ngModel)]="data.fileType" matInput placeholder="File type">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div mat-dialog-actions>
|
||||
<button (click)="onSubmit()" color="primary" mat-flat-button>Save</button>
|
||||
<button [disabled]="!data.fileName" (click)="onSubmit()" color="primary" mat-flat-button>Save</button>
|
||||
<button (click)="onNoClick()" mat-flat-button>Cancel</button>
|
||||
</div>
|
||||
|
|
|
@ -4,6 +4,7 @@ import {MAT_DIALOG_DATA, MatDialogModule, MatDialogRef} from '@angular/material/
|
|||
import {MatFormFieldModule} from '@angular/material/form-field';
|
||||
import {MatInputModule} from '@angular/material/input';
|
||||
import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {FileType} from 'sartography-workflow-lib';
|
||||
import {FileMetaDialogData} from '../_interfaces/file-meta-dialog-data';
|
||||
|
||||
import {FileMetaDialogComponent} from './file-meta-dialog.component';
|
||||
|
@ -52,10 +53,7 @@ describe('EditFileMetaDialogComponent', () => {
|
|||
const closeSpy = spyOn(component.dialogRef, 'close').and.stub();
|
||||
const dataBefore: FileMetaDialogData = {
|
||||
fileName: 'green_eggs.bpmn',
|
||||
workflowSpecId: 'green_eggs',
|
||||
name: 'green_eggs',
|
||||
displayName: 'Green Eggs',
|
||||
description: 'Eat them! Eat them! Here they are.',
|
||||
fileType: FileType.BPMN,
|
||||
};
|
||||
|
||||
component.data = dataBefore;
|
||||
|
@ -67,10 +65,7 @@ describe('EditFileMetaDialogComponent', () => {
|
|||
const closeSpy = spyOn(component.dialogRef, 'close').and.stub();
|
||||
const dataBefore: FileMetaDialogData = {
|
||||
fileName: 'and_ham.bpmn',
|
||||
workflowSpecId: 'and_ham',
|
||||
name: 'and_hame',
|
||||
displayName: 'And Ham',
|
||||
description: 'Would you, could you, in a box?',
|
||||
fileType: FileType.BPMN,
|
||||
};
|
||||
|
||||
component.data = dataBefore;
|
||||
|
@ -82,10 +77,7 @@ describe('EditFileMetaDialogComponent', () => {
|
|||
const closeSpy = spyOn(component.dialogRef, 'close').and.stub();
|
||||
const dataBefore: FileMetaDialogData = {
|
||||
fileName: ' 🍳 green_eggs.v1-2020-01-01.XML.bmnp 🍖 ',
|
||||
workflowSpecId: 'green_eggs',
|
||||
name: 'green_eggs',
|
||||
displayName: 'Green Eggs',
|
||||
description: 'Eat them! Eat them! Here they are.',
|
||||
fileType: FileType.BPMN,
|
||||
};
|
||||
|
||||
component.data = dataBefore;
|
||||
|
@ -94,21 +86,4 @@ describe('EditFileMetaDialogComponent', () => {
|
|||
expectedData.fileName = 'green_eggs.v1-2020-01-01.XML.bpmn';
|
||||
expect(closeSpy).toHaveBeenCalledWith(expectedData);
|
||||
});
|
||||
|
||||
it('should clean up workflow spec id', () => {
|
||||
const closeSpy = spyOn(component.dialogRef, 'close').and.stub();
|
||||
const dataBefore: FileMetaDialogData = {
|
||||
fileName: 'green_eggs.bpmn',
|
||||
workflowSpecId: ' 🍳 Green Eggs & Ham: A Dish Best Served Cold? 🍖 ',
|
||||
name: 'green_eggs',
|
||||
displayName: 'Green Eggs',
|
||||
description: 'I would not, could not, with a fox!',
|
||||
};
|
||||
|
||||
component.data = dataBefore;
|
||||
component.onSubmit();
|
||||
const expectedData: FileMetaDialogData = JSON.parse(JSON.stringify(dataBefore));
|
||||
expectedData.workflowSpecId = 'green_eggs_ham_a_dish_best_served_cold';
|
||||
expect(closeSpy).toHaveBeenCalledWith(dataBefore);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -21,8 +21,7 @@ export class FileMetaDialogComponent {
|
|||
}
|
||||
|
||||
onSubmit() {
|
||||
this.data.workflowSpecId = toSnakeCase(this.data.workflowSpecId);
|
||||
this.data.fileName = cleanUpFilename(this.data.fileName, 'bpmn');
|
||||
this.data.fileName = cleanUpFilename(this.data.fileName, this.data.fileType);
|
||||
this.dialogRef.close(this.data);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
<mat-toolbar [ngClass]="{'expanded': expandToolbar}">
|
||||
<mat-toolbar-row *ngIf="workflowSpec">
|
||||
<button mat-button [routerLink]="['/']">
|
||||
<mat-icon>arrow_back</mat-icon>
|
||||
Back
|
||||
</button>
|
||||
{{workflowSpec.display_name}}
|
||||
({{workflowSpec.name}})
|
||||
</mat-toolbar-row>
|
||||
<mat-toolbar-row>
|
||||
<button mat-button [matMenuTriggerFor]="newMenu" title="Open diagram">
|
||||
<mat-icon>insert_drive_file</mat-icon>
|
||||
|
@ -58,9 +66,9 @@
|
|||
<button mat-menu-item (click)="diagram.saveXML()"><mat-icon>code</mat-icon> Download XML File</button>
|
||||
</mat-menu>
|
||||
|
||||
<button mat-button *ngIf="diagramFileMeta && diagramFileMeta.workflow_spec_id" (click)="editFileMeta()">
|
||||
<button mat-button *ngIf="diagramFile" (click)="editFileMeta()">
|
||||
<mat-icon>edit</mat-icon>
|
||||
{{getFileMetaDisplayString(diagramFileMeta)}}
|
||||
{{getFileName()}}
|
||||
</button>
|
||||
</mat-toolbar-row>
|
||||
<mat-toolbar-row *ngIf="expandToolbar">
|
||||
|
@ -82,7 +90,13 @@
|
|||
<input name="diagramUrl" [(ngModel)]="diagramUrl" matInput placeholder="Open diagram from URL" type="text">
|
||||
</mat-form-field>
|
||||
</ng-container>
|
||||
<button mat-flat-button (click)="onSubmitFileToOpen()" color="primary" id="open_file_button">Open file <mat-icon>arrow_forward</mat-icon></button>
|
||||
<button
|
||||
mat-flat-button
|
||||
(click)="onSubmitFileToOpen()"
|
||||
[disabled]="!diagramFile"
|
||||
color="primary"
|
||||
id="open_file_button"
|
||||
>Open file <mat-icon>arrow_forward</mat-icon></button>
|
||||
<span fxFlex></span>
|
||||
<button mat-icon-button (click)="expandToolbar = false"><mat-icon>close</mat-icon></button>
|
||||
</mat-toolbar-row>
|
||||
|
|
|
@ -22,11 +22,11 @@ mat-form-field {
|
|||
|
||||
mat-toolbar {
|
||||
transition: all 200ms ease-in-out;
|
||||
height: 64px;
|
||||
height: 128px;
|
||||
}
|
||||
|
||||
mat-toolbar.expanded {
|
||||
height: 128px;
|
||||
height: 192px;
|
||||
}
|
||||
|
||||
::ng-deep .tooltip-text {
|
||||
|
|
|
@ -13,7 +13,8 @@ import {MatToolbarModule} from '@angular/material/toolbar';
|
|||
import {MatTooltipModule} from '@angular/material/tooltip';
|
||||
import {BrowserDynamicTestingModule} from '@angular/platform-browser-dynamic/testing';
|
||||
import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {of} from 'rxjs';
|
||||
import {ActivatedRoute, convertToParamMap} from '@angular/router';
|
||||
import {Observable, of} from 'rxjs';
|
||||
import {
|
||||
ApiService,
|
||||
FileMeta,
|
||||
|
@ -27,6 +28,7 @@ import {
|
|||
import {BPMN_DIAGRAM, BPMN_DIAGRAM_WITH_WARNINGS} from '../../testing/mocks/diagram.mocks';
|
||||
import {BpmnWarning} from '../_interfaces/bpmn-warning';
|
||||
import {FileMetaDialogData} from '../_interfaces/file-meta-dialog-data';
|
||||
import {GetIconCodePipe} from '../_pipes/get-icon-code.pipe';
|
||||
import {DiagramComponent} from '../diagram/diagram.component';
|
||||
import {FileMetaDialogComponent} from '../file-meta-dialog/file-meta-dialog.component';
|
||||
import {ModelerComponent} from './modeler.component';
|
||||
|
@ -40,6 +42,7 @@ describe('ModelerComponent', () => {
|
|||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
GetIconCodePipe,
|
||||
ModelerComponent,
|
||||
DiagramComponent,
|
||||
FileMetaDialogComponent,
|
||||
|
@ -70,6 +73,12 @@ describe('ModelerComponent', () => {
|
|||
}
|
||||
},
|
||||
{provide: MAT_DIALOG_DATA, useValue: []},
|
||||
{provide: ActivatedRoute, useValue: {
|
||||
paramMap: of(convertToParamMap({
|
||||
workflowSpecId: mockWorkflowSpec0.id,
|
||||
fileMetaId: `${mockFileMeta0.id}`
|
||||
}))
|
||||
}}
|
||||
]
|
||||
}).overrideModule(BrowserDynamicTestingModule, {set: {entryComponents: [FileMetaDialogComponent]}})
|
||||
.compileComponents();
|
||||
|
@ -198,7 +207,7 @@ describe('ModelerComponent', () => {
|
|||
});
|
||||
|
||||
it('should get the diagram file name', () => {
|
||||
expect(component.getFileName()).toEqual('No file selected');
|
||||
expect(component.getFileName()).toEqual(mockFileMeta0.name);
|
||||
|
||||
const filename = 'expected_file_name.jpg';
|
||||
component.diagramFile = new File([], filename, {type: 'image/jpeg'});
|
||||
|
@ -261,10 +270,7 @@ describe('ModelerComponent', () => {
|
|||
it('should open file metadata dialog', () => {
|
||||
const data: FileMetaDialogData = {
|
||||
fileName: 'after',
|
||||
workflowSpecId: 'after',
|
||||
name: 'after',
|
||||
description: 'after',
|
||||
displayName: 'after',
|
||||
fileType: FileType.BPMN,
|
||||
};
|
||||
|
||||
const upsertSpy = spyOn(component, '_upsertSpecAndFileMeta').and.stub();
|
||||
|
@ -275,14 +281,11 @@ describe('ModelerComponent', () => {
|
|||
expect(upsertSpy).toHaveBeenCalledWith(data);
|
||||
});
|
||||
|
||||
it('should update spec and file metadata for existing file', () => {
|
||||
it('should update file metadata for existing file', () => {
|
||||
const newXml = '<xml>New Value</xml>';
|
||||
const data: FileMetaDialogData = {
|
||||
fileName: mockFileMeta0.name,
|
||||
workflowSpecId: mockWorkflowSpec0.id,
|
||||
name: mockWorkflowSpec0.name,
|
||||
description: mockWorkflowSpec0.description,
|
||||
displayName: mockWorkflowSpec0.display_name,
|
||||
fileType: FileType.BPMN,
|
||||
};
|
||||
const updateWorkflowSpecificationSpy = spyOn(component.api, 'updateWorkflowSpecification')
|
||||
.and.returnValue(of(mockWorkflowSpec0));
|
||||
|
@ -310,14 +313,11 @@ describe('ModelerComponent', () => {
|
|||
expect(snackBarSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should create new spec and file metadata for new file', () => {
|
||||
it('should create new file metadata for new file', () => {
|
||||
const newXml = '<xml>New Value</xml>';
|
||||
const data: FileMetaDialogData = {
|
||||
fileName: mockFileMeta0.name,
|
||||
workflowSpecId: mockWorkflowSpec0.id,
|
||||
name: mockWorkflowSpec0.id,
|
||||
description: mockWorkflowSpec0.description,
|
||||
displayName: mockWorkflowSpec0.display_name,
|
||||
fileType: FileType.BPMN,
|
||||
};
|
||||
|
||||
const noDateOrVersion: FileMeta = {
|
||||
|
|
|
@ -33,6 +33,9 @@ export class ModelerComponent implements AfterViewInit {
|
|||
private xml = '';
|
||||
private draftXml = '';
|
||||
@ViewChild(DiagramComponent, {static: false}) private diagramComponent: DiagramComponent;
|
||||
private diagramType: FileType;
|
||||
private workflowSpecId: string;
|
||||
private fileMetaId: number;
|
||||
|
||||
constructor(
|
||||
private api: ApiService,
|
||||
|
@ -40,7 +43,24 @@ export class ModelerComponent implements AfterViewInit {
|
|||
public dialog: MatDialog,
|
||||
private route: ActivatedRoute,
|
||||
) {
|
||||
this.loadFilesFromDb();
|
||||
|
||||
this.route.queryParams.subscribe(q => {
|
||||
if (q && q.action) {
|
||||
if (q.action === 'openFile') {
|
||||
this.expandToolbar = true;
|
||||
this.openMethod = 'file';
|
||||
} else if (q.action === 'newFile') {
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
this.route.paramMap.subscribe(paramMap => {
|
||||
console.log('paramMap', paramMap);
|
||||
this.workflowSpecId = paramMap.get('workflowSpecId');
|
||||
this.fileMetaId = parseInt(paramMap.get('fileMetaId'), 10);
|
||||
this.loadFilesFromDb();
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
|
@ -89,7 +109,7 @@ export class ModelerComponent implements AfterViewInit {
|
|||
}
|
||||
|
||||
getFileName() {
|
||||
return this.diagramFile ? this.diagramFile.name : 'No file selected';
|
||||
return this.diagramFile ? this.diagramFile.name : this.fileName || 'No file selected';
|
||||
}
|
||||
|
||||
onFileSelected($event: Event) {
|
||||
|
@ -99,9 +119,9 @@ export class ModelerComponent implements AfterViewInit {
|
|||
// Arrow function here preserves this context
|
||||
onLoad = (event: ProgressEvent) => {
|
||||
this.xml = (event.target as FileReader).result.toString();
|
||||
const diagramType = this.diagramFileMeta ? this.diagramFileMeta.type : getDiagramTypeFromXml(this.xml);
|
||||
const diagramType = getDiagramTypeFromXml(this.xml);
|
||||
this.diagramComponent.openDiagram(this.xml, diagramType);
|
||||
};
|
||||
}
|
||||
|
||||
readFile(file: File) {
|
||||
// FileReader must be instantiated this way so unit test can spy on it.
|
||||
|
@ -139,6 +159,7 @@ export class ModelerComponent implements AfterViewInit {
|
|||
this.fileName = '';
|
||||
this.diagramFileMeta = undefined;
|
||||
this.diagramFile = undefined;
|
||||
this.diagramType = diagramType;
|
||||
this.diagramComponent.openDiagram(undefined, diagramType);
|
||||
}
|
||||
|
||||
|
@ -148,16 +169,14 @@ export class ModelerComponent implements AfterViewInit {
|
|||
height: '400px',
|
||||
width: '400px',
|
||||
data: {
|
||||
fileName: this.diagramFileMeta ? this.diagramFileMeta.name : '',
|
||||
workflowSpecId: this.diagramFileMeta ? this.diagramFileMeta.workflow_spec_id : '',
|
||||
description: this.workflowSpec ? this.workflowSpec.description : '',
|
||||
displayName: this.workflowSpec ? this.workflowSpec.display_name : '',
|
||||
fileName: this.diagramFile ? this.diagramFile.name : this.fileName || '',
|
||||
fileType: getDiagramTypeFromXml(this.xml),
|
||||
},
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe((data: FileMetaDialogData) => {
|
||||
if (data && data.fileName && data.workflowSpecId) {
|
||||
this._upsertSpecAndFileMeta(data);
|
||||
if (data && data.fileName) {
|
||||
this._upsertFileMeta(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -167,12 +186,9 @@ export class ModelerComponent implements AfterViewInit {
|
|||
}
|
||||
|
||||
getFileMetaDisplayString(fileMeta: FileMeta) {
|
||||
const spec = this.getWorkflowSpec(fileMeta.workflow_spec_id);
|
||||
|
||||
if (spec) {
|
||||
const specName = spec.id + ' - ' + spec.name + ' - ' + spec.display_name;
|
||||
if (fileMeta) {
|
||||
const lastUpdated = new DatePipe('en-us').transform(fileMeta.last_updated);
|
||||
return `${specName} (${fileMeta.name}) - v${fileMeta.version} (${lastUpdated})`;
|
||||
return `${fileMeta.name} - v${fileMeta.version} (${lastUpdated})`;
|
||||
} else {
|
||||
return 'Loading...';
|
||||
}
|
||||
|
@ -198,89 +214,62 @@ export class ModelerComponent implements AfterViewInit {
|
|||
}
|
||||
|
||||
private loadFilesFromDb() {
|
||||
|
||||
this.route.paramMap.subscribe(paramMap => {
|
||||
const workflowSpecId = paramMap.get('workflowSpecId');
|
||||
const fileMetaId = parseInt(paramMap.get('fileMetaId'), 10);
|
||||
|
||||
console.log('workflowSpecId', workflowSpecId);
|
||||
console.log('fileMetaId', fileMetaId);
|
||||
|
||||
this.api.getWorkflowSpecList().subscribe(wfs => {
|
||||
this.api.getWorkflowSpecList().subscribe(wfs => {
|
||||
this.workflowSpecs = wfs;
|
||||
this.workflowSpecs.forEach(w => {
|
||||
if (w.id === workflowSpecId) {
|
||||
if (w.id === this.workflowSpecId) {
|
||||
this.workflowSpec = w;
|
||||
}
|
||||
this.api.listBpmnFiles(w.id).subscribe(files => {
|
||||
this.bpmnFiles = [];
|
||||
files.forEach(f => {
|
||||
this.api.getFileData(f.id).subscribe(d => {
|
||||
if ((f.type === FileType.BPMN) || (f.type === FileType.DMN)) {
|
||||
f.content_type = 'text/xml';
|
||||
f.file = new File([d], f.name, {type: f.content_type});
|
||||
this.bpmnFiles.push(f);
|
||||
this.api.listBpmnFiles(w.id).subscribe(files => {
|
||||
this.bpmnFiles = [];
|
||||
files.forEach(f => {
|
||||
this.api.getFileData(f.id).subscribe(d => {
|
||||
if ((f.type === FileType.BPMN) || (f.type === FileType.DMN)) {
|
||||
f.content_type = 'text/xml';
|
||||
f.file = new File([d], f.name, {type: f.content_type});
|
||||
this.bpmnFiles.push(f);
|
||||
|
||||
if (f.id === fileMetaId) {
|
||||
this.diagramFileMeta = f;
|
||||
this.diagramFile = f.file;
|
||||
this.onSubmitFileToOpen();
|
||||
if (f.id === this.fileMetaId) {
|
||||
this.diagramFileMeta = f;
|
||||
this.diagramFile = f.file;
|
||||
this.onSubmitFileToOpen();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private _upsertSpecAndFileMeta(data: FileMetaDialogData) {
|
||||
if (data.fileName && data.workflowSpecId) {
|
||||
private _upsertFileMeta(data: FileMetaDialogData) {
|
||||
if (data.fileName) {
|
||||
this.xml = this.draftXml;
|
||||
|
||||
// Save old workflow spec id, if user wants to change it
|
||||
const specId = this.workflowSpec ? this.workflowSpec.id : undefined;
|
||||
|
||||
this.workflowSpec = {
|
||||
id: data.workflowSpecId,
|
||||
name: data.name,
|
||||
display_name: data.displayName,
|
||||
description: data.description,
|
||||
};
|
||||
|
||||
const fileMetaId = this.diagramFileMeta ? this.diagramFileMeta.id : undefined;
|
||||
const fileType = this.diagramFileMeta ? this.diagramFileMeta.type : FileType.BPMN;
|
||||
this.diagramFileMeta = {
|
||||
id: fileMetaId,
|
||||
content_type: 'text/xml',
|
||||
name: data.fileName,
|
||||
type: FileType.BPMN,
|
||||
type: fileType,
|
||||
file: new File([this.xml], data.fileName, {type: 'text/xml'}),
|
||||
workflow_spec_id: data.workflowSpecId,
|
||||
workflow_spec_id: this.workflowSpec.id,
|
||||
};
|
||||
|
||||
const newSpec: WorkflowSpec = {
|
||||
id: data.workflowSpecId,
|
||||
name: data.name,
|
||||
display_name: data.displayName,
|
||||
description: data.description,
|
||||
};
|
||||
|
||||
if (specId) {
|
||||
// Update existing workflow spec and file
|
||||
this.api.updateWorkflowSpecification(specId, newSpec).subscribe(spec => {
|
||||
this.api.updateFileMeta(specId, this.diagramFileMeta).subscribe(fileMeta => {
|
||||
this.loadFilesFromDb();
|
||||
this.snackBar.open('Saved changes to workflow spec and file.', 'Ok', {duration: 5000});
|
||||
});
|
||||
if (specId && fileMetaId) {
|
||||
// Update existing file meta
|
||||
this.api.updateFileMeta(specId, this.diagramFileMeta).subscribe(fileMeta => {
|
||||
this.loadFilesFromDb();
|
||||
this.snackBar.open('Saved changes to workflow spec and file.', 'Ok', {duration: 5000});
|
||||
});
|
||||
} else {
|
||||
// Add new workflow spec and file
|
||||
this.api.addWorkflowSpecification(newSpec).subscribe(spec => {
|
||||
this.api.addFileMeta(newSpec.id, this.diagramFileMeta).subscribe(fileMeta => {
|
||||
this.loadFilesFromDb();
|
||||
this.snackBar.open('Saved new workflow spec and file.', 'Ok', {duration: 5000});
|
||||
});
|
||||
// Add new file meta
|
||||
this.api.addFileMeta(specId, this.diagramFileMeta).subscribe(fileMeta => {
|
||||
this.loadFilesFromDb();
|
||||
this.snackBar.open('Saved new workflow spec and file.', 'Ok', {duration: 5000});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue