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

This commit is contained in:
Dan 2021-02-12 09:17:58 -05:00
commit 77031ffe82
11 changed files with 299 additions and 256 deletions

242
package-lock.json generated
View File

@ -3522,15 +3522,6 @@
"tweetnacl": "^0.14.3"
}
},
"better-assert": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
"integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
"dev": true,
"requires": {
"callsite": "1.0.0"
}
},
"big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
@ -3959,12 +3950,6 @@
"caller-callsite": "^2.0.0"
}
},
"callsite": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
"integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=",
"dev": true
},
"callsites": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
@ -5763,64 +5748,6 @@
"once": "^1.4.0"
}
},
"engine.io": {
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.4.2.tgz",
"integrity": "sha512-b4Q85dFkGw+TqgytGPrGgACRUhsdKc9S9ErRAXpPGy/CXKs4tYoHDkvIRdsseAF7NjfVwjRFIn6KTnbw7LwJZg==",
"dev": true,
"requires": {
"accepts": "~1.3.4",
"base64id": "2.0.0",
"cookie": "0.3.1",
"debug": "~4.1.0",
"engine.io-parser": "~2.2.0",
"ws": "^7.1.2"
},
"dependencies": {
"cookie": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
"integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=",
"dev": true
},
"ws": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz",
"integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==",
"dev": true
}
}
},
"engine.io-client": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.3.tgz",
"integrity": "sha512-0NGY+9hioejTEJCaSJZfWZLk4FPI9dN+1H1C4+wj2iuFba47UgZbJzfWs4aNFajnX/qAaYKbe2lLTfEEWzCmcw==",
"dev": true,
"requires": {
"component-emitter": "~1.3.0",
"component-inherit": "0.0.3",
"debug": "~4.1.0",
"engine.io-parser": "~2.2.0",
"has-cors": "1.1.0",
"indexof": "0.0.1",
"parseqs": "0.0.5",
"parseuri": "0.0.5",
"ws": "~6.1.0",
"xmlhttprequest-ssl": "~1.5.4",
"yeast": "0.1.2"
},
"dependencies": {
"ws": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz",
"integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==",
"dev": true,
"requires": {
"async-limiter": "~1.0.0"
}
}
}
},
"engine.io-parser": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.0.tgz",
@ -9513,12 +9440,6 @@
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"object-component": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
"integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=",
"dev": true
},
"object-copy": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
@ -10118,24 +10039,6 @@
"integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
"optional": true
},
"parseqs": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
"integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
"dev": true,
"requires": {
"better-assert": "~1.0.0"
}
},
"parseuri": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
"integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
"dev": true,
"requires": {
"better-assert": "~1.0.0"
}
},
"parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@ -12674,53 +12577,69 @@
}
},
"socket.io": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.3.0.tgz",
"integrity": "sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==",
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.4.1.tgz",
"integrity": "sha512-Si18v0mMXGAqLqCVpTxBa8MGqriHGQh8ccEOhmsmNS3thNCGBwO8WGrwMibANsWtQQ5NStdZwHqZR3naJVFc3w==",
"dev": true,
"requires": {
"debug": "~4.1.0",
"engine.io": "~3.4.0",
"engine.io": "~3.5.0",
"has-binary2": "~1.0.2",
"socket.io-adapter": "~1.1.0",
"socket.io-client": "2.3.0",
"socket.io-client": "2.4.0",
"socket.io-parser": "~3.4.0"
}
},
"socket.io-adapter": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz",
"integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==",
"dev": true
},
"socket.io-client": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz",
"integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==",
"dev": true,
"requires": {
"backo2": "1.0.2",
"base64-arraybuffer": "0.1.5",
"component-bind": "1.0.0",
"component-emitter": "1.2.1",
"debug": "~4.1.0",
"engine.io-client": "~3.4.0",
"has-binary2": "~1.0.2",
"has-cors": "1.1.0",
"indexof": "0.0.1",
"object-component": "0.0.3",
"parseqs": "0.0.5",
"parseuri": "0.0.5",
"socket.io-parser": "~3.3.0",
"to-array": "0.1.4"
},
"dependencies": {
"component-emitter": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
"cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==",
"dev": true
},
"engine.io": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.5.0.tgz",
"integrity": "sha512-21HlvPUKaitDGE4GXNtQ7PLP0Sz4aWLddMPw2VTyFz1FVZqu/kZsJUO8WNpKuE/OCL7nkfRaOui2ZCJloGznGA==",
"dev": true,
"requires": {
"accepts": "~1.3.4",
"base64id": "2.0.0",
"cookie": "~0.4.1",
"debug": "~4.1.0",
"engine.io-parser": "~2.2.0",
"ws": "~7.4.2"
}
},
"engine.io-client": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.0.tgz",
"integrity": "sha512-12wPRfMrugVw/DNyJk34GQ5vIVArEcVMXWugQGGuw2XxUSztFNmJggZmv8IZlLyEdnpO1QB9LkcjeWewO2vxtA==",
"dev": true,
"requires": {
"component-emitter": "~1.3.0",
"component-inherit": "0.0.3",
"debug": "~3.1.0",
"engine.io-parser": "~2.2.0",
"has-cors": "1.1.0",
"indexof": "0.0.1",
"parseqs": "0.0.6",
"parseuri": "0.0.6",
"ws": "~7.4.2",
"xmlhttprequest-ssl": "~1.5.4",
"yeast": "0.1.2"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
}
}
},
"isarray": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
@ -12733,15 +12652,35 @@
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
},
"socket.io-parser": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz",
"integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==",
"parseqs": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz",
"integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==",
"dev": true
},
"parseuri": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz",
"integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==",
"dev": true
},
"socket.io-client": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.4.0.tgz",
"integrity": "sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ==",
"dev": true,
"requires": {
"component-emitter": "1.2.1",
"backo2": "1.0.2",
"component-bind": "1.0.0",
"component-emitter": "~1.3.0",
"debug": "~3.1.0",
"isarray": "2.0.1"
"engine.io-client": "~3.5.0",
"has-binary2": "~1.0.2",
"indexof": "0.0.1",
"parseqs": "0.0.6",
"parseuri": "0.0.6",
"socket.io-parser": "~3.3.0",
"to-array": "0.1.4"
},
"dependencies": {
"debug": {
@ -12752,11 +12691,34 @@
"requires": {
"ms": "2.0.0"
}
},
"socket.io-parser": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.2.tgz",
"integrity": "sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==",
"dev": true,
"requires": {
"component-emitter": "~1.3.0",
"debug": "~3.1.0",
"isarray": "2.0.1"
}
}
}
},
"ws": {
"version": "7.4.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.2.tgz",
"integrity": "sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA==",
"dev": true
}
}
},
"socket.io-adapter": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz",
"integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==",
"dev": true
},
"socket.io-parser": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.1.tgz",

View File

@ -0,0 +1,12 @@
<mat-card fxLayoutGap>
<p mat-dialog-title>{{data.title}}</p>
<p display-2>{{data.message}}</p>
<div mat-dialog-actions>
<button mat-button (click)="onDismiss()">No</button>
<button mat-raised-button color="primary" (click)="onConfirm()">Yes</button>
</div>
</mat-card>

View File

@ -0,0 +1,3 @@
mat-dialog-container {
padding: 0px !important
}

View File

@ -0,0 +1,40 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { ConfirmDialogComponent } from './confirm-dialog.component';
describe('ConfirmDialogComponent', () => {
let component: ConfirmDialogComponent;
let fixture: ComponentFixture<ConfirmDialogComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ConfirmDialogComponent ],
imports : [MatDialogModule],
providers: [
{
provide: MatDialogRef,
useValue: {
close: (dialogResult: any) => {
}
}
},
{provide: MAT_DIALOG_DATA, useValue: {
confirm: false,
}},
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ConfirmDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,27 @@
import { Component, OnInit, Inject} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
import {ConfirmDialogData} from '../../_interfaces/dialog-data';
@Component({
selector: 'app-confirm-dialog',
templateUrl: './confirm-dialog.component.html',
styleUrls: ['./confirm-dialog.component.scss']
})
export class ConfirmDialogComponent {
constructor(
public dialogRef: MatDialogRef<ConfirmDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: ConfirmDialogData
) {
}
onConfirm(): void {
// Close the dialog, return true
this.dialogRef.close(true);
}
onDismiss(): void {
// Close the dialog, return false
this.dialogRef.close(false);
}
}

View File

@ -27,4 +27,5 @@ export class DeleteFileDialogComponent {
this.dialogRef.close(data);
}
}

View File

@ -39,6 +39,13 @@ export interface DeleteFileDialogData {
fileMeta: FileMeta;
}
export interface ConfirmDialogData {
title: string;
message: string;
}
export interface DeleteWorkflowSpecDialogData {
confirm: boolean;
workflowSpec: WorkflowSpec;

View File

@ -51,6 +51,7 @@ import {ReferenceFilesComponent} from './reference-files/reference-files.compone
import {WorkflowSpecCardComponent} from './workflow-spec-card/workflow-spec-card.component';
import {WorkflowSpecListComponent} from './workflow-spec-list/workflow-spec-list.component';
import {MatSidenavModule} from '@angular/material/sidenav';
import { ConfirmDialogComponent } from './_dialogs/confirm-dialog/confirm-dialog.component';
@Injectable()
export class ThisEnvironment implements AppEnvironment {
@ -100,6 +101,7 @@ export function getBaseHref(platformLocation: PlatformLocation): string {
WorkflowSpecCardComponent,
ProtocolBuilderComponent,
ReferenceFilesComponent,
ConfirmDialogComponent,
],
imports: [
BrowserAnimationsModule,

View File

@ -1,6 +1,6 @@
<mat-toolbar [ngClass]="{'expanded': expandToolbar}">
<mat-toolbar-row *ngIf="workflowSpec">
<a mat-button [routerLink]="['/home', workflowSpec.name]">
<a mat-button (click)="checkSaved()">
<mat-icon>arrow_back</mat-icon>
Back
</a>
@ -45,14 +45,10 @@
</a>
</mat-menu>
<button mat-menu-item (click)="openMethod = 'file'; expandToolbar = true">
<button mat-menu-item (click)="fileInput.click()">
<mat-icon>code</mat-icon>
Open from XML File
</button>
<button mat-menu-item (click)="openMethod = 'url'; expandToolbar = true">
<mat-icon>link</mat-icon>
Open from URL
</button>
</mat-menu>
<button mat-button (click)="saveChanges()" [disabled]="!hasChanged()"><mat-icon>save</mat-icon></button>
@ -73,37 +69,8 @@
{{getFileName()}}
</button>
</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()">
<span matPrefix><mat-icon>folder_open</mat-icon> &nbsp;</span>
<input matInput disabled [value]="getFileName()" type="text">
</mat-form-field>
<input hidden (change)="onFileSelected($event)" #fileInput type="file" id="file" accept=".bpmn,.dmn,.xml,application/xml,text/xml">
</ng-container>
<ng-container *ngIf="openMethod === 'url'">
<mat-form-field>
<span matPrefix><mat-icon>link</mat-icon> &nbsp;</span>
<input name="diagramUrl" [(ngModel)]="diagramUrl" matInput placeholder="Open diagram from URL" type="text">
</mat-form-field>
</ng-container>
<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>
</mat-toolbar>
<div fxLayout="column">
<div class="diagram-parent">
<app-diagram #diagram (importDone)="handleImported($event)" [fileName]="getFileName()"></app-diagram>
@ -115,3 +82,4 @@
</div>
</div>
<input hidden (change)="onFileSelected($event)" #fileInput type="file" id="file" accept=".bpmn,.dmn,.xml,application/xml,text/xml">

View File

@ -182,25 +182,6 @@ describe('ModelerComponent', () => {
expect(component.importWarnings).toEqual(warnings);
});
it('loads a diagram from URL', () => {
component.diagramUrl = 'some-url';
component.openMethod = 'url';
component.onSubmitFileToOpen();
const sReq = httpMock.expectOne(component.diagramUrl);
expect(sReq.request.method).toEqual('GET');
sReq.flush(BPMN_DIAGRAM);
});
it('loads a diagram from URL with warnings', () => {
component.diagramUrl = 'some-url';
component.openMethod = 'url';
component.onSubmitFileToOpen();
const sReq = httpMock.expectOne(component.diagramUrl);
expect(sReq.request.method).toEqual('GET');
sReq.flush(BPMN_DIAGRAM_WITH_WARNINGS);
});
it('loads a diagram from File', () => {
const readFileSpy = spyOn(component, 'readFile').and.stub();
@ -499,12 +480,13 @@ describe('ModelerComponent', () => {
const data: OpenFileDialogData = {
file: mockFileMeta0.file
};
const expectedFile = new File([], mockFileMeta0.name, {type: mockFileMeta0.content_type});
const event = {target: {files: [expectedFile]}};
const onSubmitFileToOpenSpy = spyOn(component, 'onSubmitFileToOpen').and.stub();
const openDialogSpy = spyOn(component.dialog, 'open')
.and.returnValue({afterClosed: () => of(data)});
component.openFileDialog();
expect(openDialogSpy).toHaveBeenCalled();
expect(component.requestFileClick).toBeTrue();
component.onFileSelected(event);
expect(component.diagramFile).toEqual(data.file);
expect(onSubmitFileToOpenSpy).toHaveBeenCalled();
});

View File

@ -1,9 +1,10 @@
import {DatePipe} from '@angular/common';
import {AfterViewInit, Component, ViewChild} from '@angular/core';
import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';
import {MatBottomSheet} from '@angular/material/bottom-sheet';
import {MatDialog} from '@angular/material/dialog';
import {MatSnackBar} from '@angular/material/snack-bar';
import {ActivatedRoute, Params, Router} from '@angular/router';
import {
ApiErrorsComponent,
ApiService,
@ -16,9 +17,9 @@ import {
} from 'sartography-workflow-lib';
import {FileMetaDialogComponent} from '../_dialogs/file-meta-dialog/file-meta-dialog.component';
import {NewFileDialogComponent} from '../_dialogs/new-file-dialog/new-file-dialog.component';
import {OpenFileDialogComponent} from '../_dialogs/open-file-dialog/open-file-dialog.component';
import {ConfirmDialogComponent} from '../_dialogs/confirm-dialog/confirm-dialog.component';
import {BpmnWarning} from '../_interfaces/bpmn-warning';
import {FileMetaDialogData, NewFileDialogData, OpenFileDialogData} from '../_interfaces/dialog-data';
import {FileMetaDialogData, NewFileDialogData} from '../_interfaces/dialog-data';
import {ImportEvent} from '../_interfaces/import-event';
import {DiagramComponent} from '../diagram/diagram.component';
@ -28,25 +29,6 @@ import {DiagramComponent} from '../diagram/diagram.component';
styleUrls: ['./modeler.component.scss']
})
export class ModelerComponent 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[];
expandToolbar = false;
openMethod: string;
diagramFile: File;
workflowSpec: WorkflowSpec;
bpmnFiles: FileMeta[] = [];
diagramFileMeta: FileMeta;
fileName: string;
fileTypes = FileType;
private xml = '';
private draftXml = '';
private svg = '';
@ViewChild(DiagramComponent) private diagramComponent: DiagramComponent;
private diagramType: FileType;
private workflowSpecId: string;
private fileMetaId: number;
constructor(
private api: ApiService,
@ -66,13 +48,51 @@ export class ModelerComponent implements AfterViewInit {
this.loadFilesFromDb();
});
}
title = 'bpmn-js-angular';
diagramUrl = 'https://cdn.staticaly.com/gh/bpmn-io/bpmn-js-examples/dfceecba/starter/diagram.bpmn';
importError?: Error;
importWarnings?: BpmnWarning[];
expandToolbar = false;
openMethod: string;
diagramFile: File;
workflowSpec: WorkflowSpec;
bpmnFiles: FileMeta[] = [];
diagramFileMeta: FileMeta;
fileName: string;
fileTypes = FileType;
private xml = '';
private draftXml = '';
private svg = '';
@ViewChild(DiagramComponent) private diagramComponent: DiagramComponent;
@ViewChild('fileInput', {static: true}) fileInput: ElementRef;
private diagramType: FileType;
private workflowSpecId: string;
private fileMetaId: number;
private isNew = false;
private requestFileClick = false;
static isXmlFile(file: File) {
return file.type.toLowerCase() === 'text/xml' ||
file.type.toLowerCase() === 'application/xml' ||
file.name.slice(-5).toLowerCase() === '.bpmn' ||
file.name.slice(-4).toLowerCase() === '.dmn' ||
file.name.slice(-4).toLowerCase() === '.xml';
}
ngAfterViewInit(): void {
this.diagramComponent.registerOnChange((newXmlValue: string, newSvgValue: string) => {
console.log('ModelerComponent > DiagramComponent > onChange');
this.draftXml = newXmlValue;
if (this.draftXml !== newXmlValue + ' ') {
// When we initialize a new dmn, the component registers a change even if nothing
// changes. So . . . we check to make sure it *really* changed before updating the draftXml.
this.draftXml = newXmlValue;
}
this.svg = newSvgValue;
});
if (this.requestFileClick) {
this.fileInput.nativeElement.click();
this.requestFileClick = false;
}
}
handleImported(event: ImportEvent) {
@ -92,23 +112,27 @@ export class ModelerComponent implements AfterViewInit {
this.importError = error;
this.importWarnings = warnings;
this.draftXml = this.xml + ' ';
// if this is a new file then we force a change to the file
if (this.isNew ) {
this.draftXml = this.xml + ' ';
this.isNew = false;
} else {
this.draftXml = this.xml;
}
}
onSubmitFileToOpen() {
this.expandToolbar = false;
if (this.openMethod === 'url') {
this.diagramComponent.loadUrl(this.diagramUrl);
if (this.diagramFile && ModelerComponent.isXmlFile(this.diagramFile)) {
this.readFile(this.diagramFile);
} else {
if (this.diagramFile && this.isXmlFile(this.diagramFile)) {
this.readFile(this.diagramFile);
} else {
this.handleImported({
type: 'error',
error: new Error('Wrong file type. Please choose a BPMN XML file.')
});
}
this.handleImported({
type: 'error',
error: new Error('Wrong file type. Please choose a BPMN XML file.')
});
}
this.openMethod = undefined;
@ -118,8 +142,28 @@ export class ModelerComponent implements AfterViewInit {
return this.diagramFile ? this.diagramFile.name : this.fileName || 'No file selected';
}
checkSaved() {
if (this.hasChanged()) {
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
maxWidth: '300px',
data: {
title: 'Unsaved Changes!',
message : 'Are you sure you want to abandon changes?',
}
});
dialogRef.afterClosed().subscribe(dialogResult => {
if (dialogResult) {
this.router.navigate(['/home', this.workflowSpec.name]);
}});
} else {
this.router.navigate(['/home', this.workflowSpec.name]);
}
}
onFileSelected($event: Event) {
this.diagramFile = ($event.target as HTMLFormElement).files[0];
this.onSubmitFileToOpen();
this.isNew = true;
}
// Arrow function here preserves this context
@ -159,7 +203,7 @@ export class ModelerComponent implements AfterViewInit {
}
hasChanged(): boolean {
return this.xml !== this.draftXml;
return (this.xml !== this.draftXml) || this.isNew;
}
loadDbFile(bf: FileMeta) {
@ -180,18 +224,14 @@ export class ModelerComponent implements AfterViewInit {
}
openFileDialog() {
const dialogData: OpenFileDialogData = {
file: undefined,
fileTypes: [FileType.DMN, FileType.BPMN],
};
const dialogRef = this.dialog.open(OpenFileDialogComponent, {data: dialogData});
// NB - Aaron said that doing this may be problematic.
// When we are handling the action in the constructor, the component hasn't been
// Rendered yet. I needed to call fileInput.click() after the component has rendered.
dialogRef.afterClosed().subscribe((data: OpenFileDialogData) => {
if (data && data.file) {
this.diagramFile = data.file;
this.onSubmitFileToOpen();
}
});
// In order to make this work, I check for the requestFileClick variable in ngAfterViewInit
// and then click it. I couldn't see any other way to make this do what I wanted to do
// it *appears* to work fine.
this.requestFileClick = true;
}
newFileDialog() {
@ -303,27 +343,25 @@ export class ModelerComponent implements AfterViewInit {
this.api.addFileMeta({workflow_spec_id: this.workflowSpec.id}, this.diagramFileMeta).subscribe(fileMeta => {
this.router.navigate(['/modeler', this.workflowSpec.id, fileMeta.id]);
this.snackBar.open(`Saved new file ${fileMeta.name} to workflow spec ${this.workflowSpec.name}.`, 'Ok', {duration: 5000});
}, () => {
// if this fails, we make sure that the file is treated as still new,
// and we make the user re-enter the file details as they weren't actually saved.
this.isNew = true;
this.diagramFileMeta = undefined;
});
}
}
}
private isXmlFile(file: File) {
return file.type.toLowerCase() === 'text/xml' ||
file.type.toLowerCase() === 'application/xml' ||
file.name.slice(-5).toLowerCase() === '.bpmn' ||
file.name.slice(-4).toLowerCase() === '.dmn' ||
file.name.slice(-4).toLowerCase() === '.xml';
}
private saveFileChanges() {
this.xml = this.draftXml;
this.diagramFileMeta.file = new File([this.xml], this.diagramFileMeta.name, {type: 'text/xml'});
if (this.svg && this.svg !== '') {
const svgFile = new File([this.svg], this.diagramFileMeta.name, {type: 'text/xml'});
// this.api.updateFileData();
}
// Propose removal
// if (this.svg && this.svg !== '') {
// const svgFile = new File([this.svg], this.diagramFileMeta.name, {type: 'text/xml'});
// // this.api.updateFileData();
// }
this.api.updateFileData(this.diagramFileMeta).subscribe(newFileMeta => {
this.diagramFileMeta = newFileMeta;
@ -340,4 +378,5 @@ export class ModelerComponent implements AfterViewInit {
}
}
}
}