Enables save button when user changes diagram. Saves changes to server.
This commit is contained in:
parent
393351574d
commit
6377f50ce5
|
@ -1,6 +1,6 @@
|
|||
<mat-toolbar [ngClass]="{'expanded': expandToolbar}">
|
||||
<mat-toolbar-row>
|
||||
<button mat-button (click)="diagram.createNewDiagram()" title="Create new BPMN diagram"><mat-icon>insert_drive_file</mat-icon></button>
|
||||
<button mat-button (click)="newDiagram()" title="Create new BPMN diagram"><mat-icon>insert_drive_file</mat-icon></button>
|
||||
|
||||
<button mat-button [matMenuTriggerFor]="importMenu" title="Open diagram">
|
||||
<mat-icon>folder</mat-icon>
|
||||
|
@ -12,7 +12,7 @@
|
|||
Open previously saved...
|
||||
</button>
|
||||
<mat-menu #dbMenu="matMenu">
|
||||
<button mat-menu-item *ngFor="let bf of bpmnFiles" (click)="diagramFile = bf.file; onSubmit($event)">
|
||||
<button mat-menu-item *ngFor="let bf of bpmnFiles" (click)="loadDbFile(bf)">
|
||||
{{bf.name}} - v{{bf.version}} ({{bf.last_updated | date}})
|
||||
</button>
|
||||
</mat-menu>
|
||||
|
@ -27,8 +27,10 @@
|
|||
</button>
|
||||
</mat-menu>
|
||||
|
||||
<button mat-button (click)="saveChanges()" [disabled]="!hasChanged()"><mat-icon>save</mat-icon></button>
|
||||
|
||||
<button mat-button [matMenuTriggerFor]="downloadMenu" title="Download diagram">
|
||||
<mat-icon>save</mat-icon>
|
||||
<mat-icon>save_alt</mat-icon>
|
||||
<mat-icon>arrow_drop_down</mat-icon>
|
||||
</button>
|
||||
<mat-menu #downloadMenu="matMenu">
|
||||
|
@ -37,6 +39,12 @@
|
|||
</mat-menu>
|
||||
</mat-toolbar-row>
|
||||
<mat-toolbar-row *ngIf="expandToolbar">
|
||||
<ng-container *ngIf="!openMethod">
|
||||
<mat-form-field>
|
||||
<input matInput [(ngModel)]="fileName" placeholder="File name" type="text">
|
||||
</mat-form-field>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="openMethod === 'file'">
|
||||
<mat-form-field (click)="fileInput.click()">
|
||||
<input matInput disabled [value]="getFileName()" type="text">
|
||||
|
@ -49,7 +57,7 @@
|
|||
<input name="diagramUrl" [(ngModel)]="diagramUrl" matInput placeholder="Open diagram from URL" type="text">
|
||||
</mat-form-field>
|
||||
</ng-container>
|
||||
<button mat-icon-button (click)="onSubmit($event)"><mat-icon>arrow_forward</mat-icon></button>
|
||||
<button mat-icon-button (click)="onSubmitFileToOpen()"><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>
|
||||
|
|
|
@ -1,45 +1,50 @@
|
|||
import {Component, ViewChild} from '@angular/core';
|
||||
import {AfterViewInit, Component, ViewChild} from '@angular/core';
|
||||
import {MatDialog, MatDialogRef} from '@angular/material/dialog';
|
||||
import {MatSnackBar} from '@angular/material/snack-bar';
|
||||
import {FileMeta, FileType, WorkflowSpec} from 'sartography-workflow-lib';
|
||||
import {BPMN_DIAGRAM} from '../testing/mocks/diagram.mocks';
|
||||
import {BpmnWarning} from './_interfaces/bpmn-warning';
|
||||
import {ImportEvent} from './_interfaces/import-event';
|
||||
import {NewFileDialogData} from './_interfaces/new-file-dialog-data';
|
||||
import {ApiService} from './_services/api.service';
|
||||
import {DiagramComponent} from './diagram/diagram.component';
|
||||
import {NewFileDialogComponent} from './new-file-dialog/new-file-dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss']
|
||||
})
|
||||
export class AppComponent {
|
||||
export class AppComponent implements AfterViewInit {
|
||||
title = 'bpmn-js-angular';
|
||||
diagramUrl = 'https://cdn.staticaly.com/gh/bpmn-io/bpmn-js-examples/dfceecba/starter/diagram.bpmn';
|
||||
importError?: Error;
|
||||
importWarnings?: BpmnWarning[];
|
||||
xmlModel: any;
|
||||
expandToolbar = false;
|
||||
openMethod: string;
|
||||
diagramFile: File;
|
||||
workflowSpecs: WorkflowSpec[] = [];
|
||||
bpmnFiles: FileMeta[] = [];
|
||||
diagramFileMeta: FileMeta;
|
||||
fileName: string;
|
||||
private xml = '';
|
||||
private draftXml = '';
|
||||
@ViewChild(DiagramComponent, {static: false}) private diagramComponent: DiagramComponent;
|
||||
|
||||
constructor(private api: ApiService) {
|
||||
this.xmlModel = BPMN_DIAGRAM;
|
||||
this.api.listWorkflowSpecifications().subscribe(wfs => {
|
||||
this.workflowSpecs = wfs;
|
||||
this.workflowSpecs.forEach(w => {
|
||||
this.api.listBpmnFiles(w.id).subscribe(files => {
|
||||
this.bpmnFiles = [];
|
||||
files.forEach(f => {
|
||||
this.api.getFileData(f.id).subscribe(d => {
|
||||
f.content_type = (f.type === FileType.SVG) ? 'image/svg+xml' : f.content_type = 'text/xml';
|
||||
f.file = new File([d], f.name, {type: f.content_type});
|
||||
this.bpmnFiles.push(f);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
constructor(
|
||||
private api: ApiService,
|
||||
private snackBar: MatSnackBar,
|
||||
public dialog: MatDialog
|
||||
) {
|
||||
this.loadFilesFromDb();
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.diagramComponent.registerOnChange((newXmlValue: string) => {
|
||||
this.draftXml = newXmlValue;
|
||||
});
|
||||
|
||||
this.diagramComponent.registerOnTouched(() => {
|
||||
console.log('diagramComponent onTouch');
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -60,13 +65,10 @@ export class AppComponent {
|
|||
|
||||
this.importError = error;
|
||||
this.importWarnings = warnings;
|
||||
|
||||
// Clear the inputs
|
||||
this.diagramFile = undefined;
|
||||
this.diagramUrl = undefined;
|
||||
this.draftXml = this.xml;
|
||||
}
|
||||
|
||||
onSubmit($event: MouseEvent) {
|
||||
onSubmitFileToOpen() {
|
||||
this.expandToolbar = false;
|
||||
|
||||
if (this.openMethod === 'url') {
|
||||
|
@ -95,16 +97,110 @@ export class AppComponent {
|
|||
|
||||
// Arrow function here preserves this context
|
||||
onLoad = (event: ProgressEvent) => {
|
||||
const xml = (event.target as FileReader).result;
|
||||
this.diagramComponent.openDiagram(xml.toString());
|
||||
this.xml = (event.target as FileReader).result.toString();
|
||||
this.diagramComponent.openDiagram(this.xml);
|
||||
}
|
||||
|
||||
readFile(file: File) {
|
||||
console.log('readFile', file);
|
||||
|
||||
// FileReader must be instantiated this way so unit test can spy on it.
|
||||
const fileReader = new (window as any).FileReader();
|
||||
fileReader.onload = this.onLoad;
|
||||
fileReader.readAsText(file);
|
||||
}
|
||||
|
||||
saveChanges() {
|
||||
if (this.hasChanged()) {
|
||||
|
||||
console.log('saveChanges this.diagramFileMeta', this.diagramFileMeta);
|
||||
if (this.diagramFileMeta && this.diagramFileMeta.workflow_spec_id) {
|
||||
this.xml = this.draftXml;
|
||||
this.diagramFileMeta.file = new File([this.xml], this.diagramFileMeta.name, {type: 'text/xml'});
|
||||
this.api.updateFileMeta(this.diagramFileMeta).subscribe(() => {
|
||||
this.snackBar.open('Saved changes.', 'Ok', {duration: 5000});
|
||||
});
|
||||
} else {
|
||||
|
||||
// Open new filename/workflow spec dialog
|
||||
const dialogRef = this.dialog.open(NewFileDialogComponent, {
|
||||
height: '400px',
|
||||
width: '400px',
|
||||
data: {
|
||||
fileName: '',
|
||||
workflowSpecId: '',
|
||||
},
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe((data: NewFileDialogData) => {
|
||||
console.log('dialog afterClosed result', data);
|
||||
|
||||
if (data.fileName && data.workflowSpecId) {
|
||||
this.xml = this.draftXml;
|
||||
|
||||
// New fileMeta
|
||||
this.diagramFileMeta = {
|
||||
content_type: 'text/xml',
|
||||
name: data.fileName,
|
||||
type: FileType.BPMN,
|
||||
file: new File([this.xml], data.fileName, {type: 'text/xml'}),
|
||||
workflow_spec_id: data.workflowSpecId,
|
||||
};
|
||||
|
||||
const newSpec: WorkflowSpec = {
|
||||
id: data.workflowSpecId,
|
||||
display_name: data.displayName,
|
||||
description: data.description,
|
||||
};
|
||||
|
||||
// New workflow spec
|
||||
this.api.addWorkflowSpecification(newSpec).subscribe(spec => {
|
||||
console.log('spec', spec);
|
||||
this.api.addFileMeta(this.diagramFileMeta).subscribe(fileMeta => {
|
||||
this.loadFilesFromDb();
|
||||
this.snackBar.open('Saved changes to new workflow spec and file.', 'Ok', {duration: 5000});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hasChanged(): boolean {
|
||||
return this.xml !== this.draftXml;
|
||||
}
|
||||
|
||||
loadDbFile(bf: FileMeta) {
|
||||
this.diagramFile = bf.file;
|
||||
this.diagramFileMeta = bf;
|
||||
this.onSubmitFileToOpen();
|
||||
}
|
||||
|
||||
newDiagram() {
|
||||
this.xml = '';
|
||||
this.draftXml = '';
|
||||
this.fileName = '';
|
||||
this.diagramFileMeta = undefined;
|
||||
this.diagramFile = undefined;
|
||||
this.diagramComponent.createNewDiagram();
|
||||
}
|
||||
|
||||
private loadFilesFromDb() {
|
||||
this.api.listWorkflowSpecifications().subscribe(wfs => {
|
||||
this.workflowSpecs = wfs;
|
||||
this.workflowSpecs.forEach(w => {
|
||||
this.api.listBpmnFiles(w.id).subscribe(files => {
|
||||
this.bpmnFiles = [];
|
||||
files.forEach(f => {
|
||||
this.api.getFileData(f.id).subscribe(d => {
|
||||
f.content_type = (f.type === FileType.SVG) ? 'image/svg+xml' : f.content_type = 'text/xml';
|
||||
f.file = new File([d], f.name, {type: f.content_type});
|
||||
this.bpmnFiles.push(f);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,9 +31,7 @@ export class DiagramComponent implements ControlValueAccessor, AfterViewInit {
|
|||
) {
|
||||
}
|
||||
|
||||
get value(): any {
|
||||
return this.xml;
|
||||
}
|
||||
get value(): string { return this.xml; }
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.initializeModeler();
|
||||
|
@ -78,12 +76,12 @@ export class DiagramComponent implements ControlValueAccessor, AfterViewInit {
|
|||
this.openDiagram(value);
|
||||
}
|
||||
this.xml = value;
|
||||
this.onChange(this.value);
|
||||
this.onChange(this.xml);
|
||||
}
|
||||
|
||||
// Allows Angular to register a function to call when the model changes.
|
||||
// Save the function as a property to call later here.
|
||||
registerOnChange(fn: (rating: number) => void): void {
|
||||
registerOnChange(fn: (newXmlValue: string) => void): void {
|
||||
this.onChange = fn;
|
||||
}
|
||||
|
||||
|
@ -103,11 +101,14 @@ export class DiagramComponent implements ControlValueAccessor, AfterViewInit {
|
|||
}
|
||||
|
||||
openDiagram(xml?: string) {
|
||||
return this.zone.run(
|
||||
() => xml ?
|
||||
this.modeler.importXML(xml, (e, w) => this.onImport(e, w)) :
|
||||
this.modeler.createDiagram((e, w) => this.onImport(e, w))
|
||||
);
|
||||
this.xml = xml;
|
||||
return this.zone.run(() => {
|
||||
if (xml) {
|
||||
this.modeler.importXML(xml, (e, w) => this.onImport(e, w));
|
||||
} else {
|
||||
this.modeler.createDiagram((e, w) => this.onImport(e, w));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
saveSVG() {
|
||||
|
|
Loading…
Reference in New Issue