Skip to content

Commit

Permalink
feat(modeler): add commands to copy or save diagram as svg (#622)
Browse files Browse the repository at this point in the history
* feat: add commands to copy or save diagram as svg
  • Loading branch information
peterhnm authored Jun 28, 2024
1 parent 8a353f2 commit 1c777ec
Show file tree
Hide file tree
Showing 13 changed files with 147 additions and 3 deletions.
9 changes: 9 additions & 0 deletions apps/miranum-modeler-bpmn-webview/src/app/modeler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,15 @@ export async function exportDiagram(): Promise<string> {
throw Error("Failed to save changes made to the diagram!");
}

/**
* Get the SVG content of the current diagram.
*/
export async function getDiagramAsSVG(): Promise<string> {
const m = getModeler();
const result = await m.saveSVG();
return result.svg;
}

/**
* Set the element templates to the modeler.
* @param templates
Expand Down
7 changes: 7 additions & 0 deletions apps/miranum-modeler-bpmn-webview/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
FormKeysQuery,
GetBpmnFileCommand,
GetBpmnModelerSettingCommand,
GetDiagramAsSVGCommand,
GetElementTemplatesCommand,
GetFormKeysCommand,
LogErrorCommand,
Expand All @@ -31,6 +32,7 @@ import {
alignElementsToOrigin,
createModeler,
exportDiagram,
getDiagramAsSVG,
getVsCodeApi,
loadDiagram,
newDiagram,
Expand Down Expand Up @@ -242,6 +244,11 @@ async function onReceiveMessage(message: MessageEvent<Query | Command>) {
}
break;
}
case queryOrCommand.type === "GetDiagramAsSVGCommand": {
const command = message.data as GetDiagramAsSVGCommand;
command.svg = await getDiagramAsSVG();
vscode.postMessage(command);
}
}
} catch (error: unknown) {
const errorMessage = error instanceof Error ? error.message : `${error}`;
Expand Down
10 changes: 9 additions & 1 deletion apps/miranum-modeler/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.5.13] - 2024-06-28

### Added

* Add commands to copy or save diagram as SVG (#622)

## [0.5.12] - 2024-06-20

### Fixed
Expand Down Expand Up @@ -96,7 +102,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

* Unresolved breakpoints when debugging (#227)

[unreleased]: https://github.com/Miragon/miranum-ide/compare/release/v0.5.12-vscode...HEAD
[unreleased]: https://github.com/Miragon/miranum-ide/compare/release/v0.5.13-vscode...HEAD

[0.5.13]: https://github.com/Miragon/miranum-ide/compare/release/v0.5.12...release/v0.5.13-vscode

[0.5.12]: https://github.com/Miragon/miranum-ide/compare/release/v0.5.11...release/v0.5.12-vscode

Expand Down
16 changes: 16 additions & 0 deletions apps/miranum-modeler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@
"command": "miranum-modeler.openLoggingConsole",
"title": "Miranum Modeler: Display Logging Information",
"icon": "$(callstack-view-session)"
},
{
"command": "miranum-modeler.copyDiagramAsSvg",
"title": "Miranum Modeler: Copy Diagram as SVG"
},
{
"command": "miranum-modeler.saveDiagramAsSvgCommand",
"title": "Miranum Modeler: Save Diagram as SVG"
}
],
"keybindings": [
Expand All @@ -101,6 +109,14 @@
{
"command": "miranum-modeler.openLoggingConsole",
"when": "miranum-modeler.openCustomEditors > 0"
},
{
"command": "miranum-modeler.copyDiagramAsSvg",
"when": "miranum-modeler.openCustomEditors > 0"
},
{
"command": "miranum-modeler.saveDiagramAsSvgCommand",
"when": "miranum-modeler.openCustomEditors > 0"
}
],
"editor/title": [
Expand Down
55 changes: 54 additions & 1 deletion apps/miranum-modeler/src/adapter/in/commands.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { commands } from "vscode";
import { commands, env, Uri, workspace } from "vscode";
import { inject, singleton } from "tsyringe";

import { getContext } from "@miranum-ide/vscode/miranum-vscode";
import {
GetDiagramAsSvgInPort,
GetDocumentInPort,
OpenLoggingConsoleInPort,
ToggleTextEditorInPort,
} from "../../application/ports/in";
import { subscribeToMessageEvent } from "../out";
import { GetDiagramAsSVGCommand } from "@miranum-ide/vscode/miranum-vscode-webview";

@singleton()
export class VsCodeToggleTextEditorCommand {
Expand Down Expand Up @@ -52,3 +56,52 @@ export class VsCodeOpenLoggingConsoleCommand {
this.openLoggingConsoleInPort.open();
}
}

@singleton()
export class VsCodeDiagramAsSvgCommand {
constructor(
@inject("CopyDiagramAsSvgCommand") writeToClipboard: string,
@inject("SaveDiagramAsSvgCommand") writeToFile: string,
@inject("GetDiagramAsSvgInPort")
private readonly getDiagramAsSvgInPort: GetDiagramAsSvgInPort,
@inject("GetDocumentInPort")
private readonly getDocumentInPort: GetDocumentInPort,
) {
const context = getContext();

context.subscriptions.push(
commands.registerCommand(writeToClipboard, this.writeToClipboard, this),
commands.registerCommand(writeToFile, this.writeToFile, this),
);
}

writeToClipboard(): void {
this.getDiagramAsSvgInPort.getSvg();

subscribeToMessageEvent((message) => {
if (message.type === "GetDiagramAsSVGCommand") {
const command = message as GetDiagramAsSVGCommand;
if (command.svg && command.svg.length > 0) {
env.clipboard.writeText(command.svg);
}
}
});
}

writeToFile(): void {
this.getDiagramAsSvgInPort.getSvg();

subscribeToMessageEvent((message) => {
if (message.type === "GetDiagramAsSVGCommand") {
const command = message as GetDiagramAsSVGCommand;
if (command.svg && command.svg.length > 0) {
const filePath = this.getDocumentInPort
.getPath()
.replace("bpmn", "svg");

workspace.fs.writeFile(Uri.file(filePath), Buffer.from(command.svg));
}
}
});
}
}
6 changes: 6 additions & 0 deletions apps/miranum-modeler/src/adapter/out/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
DmnFileQuery,
ElementTemplatesQuery,
FormKeysQuery,
GetDiagramAsSVGCommand,
Query,
} from "@miranum-ide/vscode/miranum-vscode-webview";

Expand Down Expand Up @@ -185,6 +186,11 @@ export class VsCodeBpmnWebviewAdapter implements BpmnUiOutPort {
});
return postMessage(editorId, webviewSettingsQuery);
}

async getDiagramAsSVG(editorId: string): Promise<boolean> {
const getBpmnAsSVGCommand = new GetDiagramAsSVGCommand();
return postMessage(editorId, getBpmnAsSVGCommand);
}
}

export class VsCodeDmnWebviewAdapter implements DmnUiOutPort {
Expand Down
4 changes: 4 additions & 0 deletions apps/miranum-modeler/src/application/ports/in.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ export interface GetDocumentInPort {
getPath(): string;
}

export interface GetDiagramAsSvgInPort {
getSvg(): Promise<boolean>;
}

/**
* Display a message to the user in the UI.
*/
Expand Down
6 changes: 6 additions & 0 deletions apps/miranum-modeler/src/application/ports/out.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ export interface BpmnUiOutPort extends EditorComponent {
* @throws {Error} if the editorId does not match the active editor
*/
setSettings(editorId: string, setting: BpmnModelerSetting): Promise<boolean>;

/**
* Get the BPMN diagram as SVG.
* @param editorId
*/
getDiagramAsSVG(editorId: string): Promise<boolean>;
}

export interface DmnUiOutPort extends EditorComponent {
Expand Down
14 changes: 14 additions & 0 deletions apps/miranum-modeler/src/application/useCases/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import { inject, singleton } from "tsyringe";

import {
DisplayMessageInPort,
GetDiagramAsSvgInPort,
GetDocumentInPort,
LogMessageInPort,
OpenLoggingConsoleInPort,
ToggleTextEditorInPort,
} from "../ports/in";
import {
BpmnUiOutPort,
DisplayMessageOutPort,
DocumentOutPort,
LogMessageOutPort,
Expand Down Expand Up @@ -85,3 +87,15 @@ export class OpenLoggingConsoleUseCase implements OpenLoggingConsoleInPort {
this.openLoggingConsoleOutPort.open();
}
}

@singleton()
export class GetDiagramAsSvgUseCase implements GetDiagramAsSvgInPort {
constructor(
@inject("BpmnUiOutPort")
private readonly bpmnUiOutPort: BpmnUiOutPort,
) {}

getSvg(): Promise<boolean> {
return this.bpmnUiOutPort.getDiagramAsSVG(this.bpmnUiOutPort.getId());
}
}
11 changes: 11 additions & 0 deletions apps/miranum-modeler/src/main.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
DisplayBpmnModelerUseCase,
DisplayDmnModelerUseCase,
DisplayMessageUseCase,
GetDiagramAsSvgUseCase,
GetDocumentUseCase,
GetMiranumConfigUseCase,
GetWorkspaceItemUseCase,
Expand All @@ -26,6 +27,7 @@ import {
VsCodeTextEditorAdapter,
VsCodeWorkspaceAdapter,
} from "./adapter/out";
import { GetDiagramAsSvgInPort } from "./application/ports/in";

/**
* The configuration of the adapter and use cases has to follow the following pattern:
Expand Down Expand Up @@ -106,6 +108,12 @@ function configBpmnModeler(): void {
container.register("BpmnModelerViewType", { useValue: "miranum-modeler.bpmn" });
container.register("C7ExecutionPlatformVersion", { useValue: "7.20.0" });
container.register("C8ExecutionPlatformVersion", { useValue: "8.4.0" });
container.register("CopyDiagramAsSvgCommand", {
useValue: "miranum-modeler.copyDiagramAsSvg",
});
container.register("SaveDiagramAsSvgCommand", {
useValue: "miranum-modeler.saveDiagramAsSvgCommand",
});

// Out Adapter
container.register("BpmnUiOutPort", VsCodeBpmnWebviewAdapter, {
Expand All @@ -131,6 +139,9 @@ function configBpmnModeler(): void {
container.register("SetBpmnModelerSettingsInPort", SetBpmnModelerSettingsUseCase, {
lifecycle: Lifecycle.Singleton,
});
container.register("GetDiagramAsSvgInPort", GetDiagramAsSvgUseCase, {
lifecycle: Lifecycle.Singleton,
});
}

function configDmnModeler(): void {
Expand Down
2 changes: 2 additions & 0 deletions apps/miranum-modeler/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { setContext } from "@miranum-ide/vscode/miranum-vscode";
import { config } from "./main.config";
import {
VsCodeBpmnEditorAdapter,
VsCodeDiagramAsSvgCommand,
VsCodeDmnEditorAdapter,
VsCodeOpenLoggingConsoleCommand,
VsCodeToggleTextEditorCommand,
Expand All @@ -23,6 +24,7 @@ export function activate(context: ExtensionContext) {
// otherwise tsyringe won't create the instance
container.resolve(VsCodeToggleTextEditorCommand);
container.resolve(VsCodeOpenLoggingConsoleCommand);
container.resolve(VsCodeDiagramAsSvgCommand);

// 4. Start the application
container.resolve(VsCodeBpmnEditorAdapter);
Expand Down
8 changes: 8 additions & 0 deletions libs/vscode/miranum-vscode-webview/src/lib/miranum-modeler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ export class GetBpmnFileCommand extends Command {
}
}

export class GetDiagramAsSVGCommand extends Command {
svg?: string;

constructor() {
super("GetDiagramAsSVGCommand");
}
}

export class GetDmnFileCommand extends Command {
constructor() {
super("GetDmnFileCommand");
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "miranum-ide",
"version": "0.5.12",
"version": "0.5.13",
"license": "Apache-2.0",
"scripts": {
"build": "npx nx run-many --target build --all --prod && node tools/scripts/set-version.js && npm run doc",
Expand Down

0 comments on commit 1c777ec

Please sign in to comment.