diff --git a/package-lock.json b/package-lock.json index 5c10385..869742b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/src/app/_dialogs/confirm-dialog/confirm-dialog.component.html b/src/app/_dialogs/confirm-dialog/confirm-dialog.component.html new file mode 100644 index 0000000..690e062 --- /dev/null +++ b/src/app/_dialogs/confirm-dialog/confirm-dialog.component.html @@ -0,0 +1,12 @@ + + +

{{data.title}}

+ +

{{data.message}}

+ + +
+ + +
+
diff --git a/src/app/_dialogs/confirm-dialog/confirm-dialog.component.scss b/src/app/_dialogs/confirm-dialog/confirm-dialog.component.scss new file mode 100644 index 0000000..e9de670 --- /dev/null +++ b/src/app/_dialogs/confirm-dialog/confirm-dialog.component.scss @@ -0,0 +1,3 @@ +mat-dialog-container { + padding: 0px !important +} diff --git a/src/app/_dialogs/confirm-dialog/confirm-dialog.component.spec.ts b/src/app/_dialogs/confirm-dialog/confirm-dialog.component.spec.ts new file mode 100644 index 0000000..1483f34 --- /dev/null +++ b/src/app/_dialogs/confirm-dialog/confirm-dialog.component.spec.ts @@ -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; + + 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(); + }); +}); diff --git a/src/app/_dialogs/confirm-dialog/confirm-dialog.component.ts b/src/app/_dialogs/confirm-dialog/confirm-dialog.component.ts new file mode 100644 index 0000000..4eb099e --- /dev/null +++ b/src/app/_dialogs/confirm-dialog/confirm-dialog.component.ts @@ -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, + @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); + } +} diff --git a/src/app/_dialogs/delete-file-dialog/delete-file-dialog.component.ts b/src/app/_dialogs/delete-file-dialog/delete-file-dialog.component.ts index 6313b5f..2508364 100644 --- a/src/app/_dialogs/delete-file-dialog/delete-file-dialog.component.ts +++ b/src/app/_dialogs/delete-file-dialog/delete-file-dialog.component.ts @@ -27,4 +27,5 @@ export class DeleteFileDialogComponent { this.dialogRef.close(data); } + } diff --git a/src/app/_interfaces/dialog-data.ts b/src/app/_interfaces/dialog-data.ts index 48ce9db..8eb5ffa 100644 --- a/src/app/_interfaces/dialog-data.ts +++ b/src/app/_interfaces/dialog-data.ts @@ -39,6 +39,13 @@ export interface DeleteFileDialogData { fileMeta: FileMeta; } +export interface ConfirmDialogData { + title: string; + message: string; +} + + + export interface DeleteWorkflowSpecDialogData { confirm: boolean; workflowSpec: WorkflowSpec; diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4e9f00b..f255d93 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -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, diff --git a/src/app/modeler/modeler.component.html b/src/app/modeler/modeler.component.html index 8fcbfd6..ab4c6a0 100644 --- a/src/app/modeler/modeler.component.html +++ b/src/app/modeler/modeler.component.html @@ -1,6 +1,6 @@ - + arrow_back Back @@ -45,14 +45,10 @@ - - @@ -73,37 +69,8 @@ {{getFileName()}} - - - - - - - - - - folder_open   - - - - - - - link   - - - - - - - +
@@ -115,3 +82,4 @@
+ diff --git a/src/app/modeler/modeler.component.spec.ts b/src/app/modeler/modeler.component.spec.ts index dafe1a9..79fe2ac 100644 --- a/src/app/modeler/modeler.component.spec.ts +++ b/src/app/modeler/modeler.component.spec.ts @@ -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(); }); diff --git a/src/app/modeler/modeler.component.ts b/src/app/modeler/modeler.component.ts index d86e18b..1469d11 100644 --- a/src/app/modeler/modeler.component.ts +++ b/src/app/modeler/modeler.component.ts @@ -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 { } } } + }