Implement monaco editor
This commit is contained in:
parent
a949fa2c14
commit
1e71ea605f
|
|
@ -0,0 +1,3 @@
|
|||
namespace Elsa.Management.ActivityInputOptions;
|
||||
|
||||
public record CodeEditorOptions(EditorHeight? EditorHeight = default, string? Language = default, bool? SingleLineMode = default);
|
||||
1659
src/designer/elsa-workflows-designer/package-lock.json
generated
1659
src/designer/elsa-workflows-designer/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -36,6 +36,9 @@
|
|||
"el-transition": "^0.0.7",
|
||||
"moment": "^2.29.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"monaco-editor": ""
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fullhuman/postcss-purgecss": "^4.1.3",
|
||||
"@stencil/postcss": "^2.1.0",
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { NodeInputContext } from "./services/node-input-driver";
|
|||
import { MenuItem } from "./components/shared/context-menu/models";
|
||||
import { DropdownButtonItem, DropdownButtonOrigin } from "./components/shared/dropdown-button/models";
|
||||
import { AddActivityArgs as AddActivityArgs1 } from "./components/designer/canvas/canvas";
|
||||
import { MonacoLib, MonacoValueChangedArgs } from "./components/shared/monaco-editor/monaco-editor";
|
||||
import { PagerData } from "./components/shared/pager/pager";
|
||||
import { PanelPosition, PanelStateChangedArgs } from "./components/designer/panel/models";
|
||||
import { Graph } from "@antv/x6";
|
||||
|
|
@ -38,6 +39,9 @@ export namespace Components {
|
|||
interface ElsaCheckListInput {
|
||||
"inputContext": NodeInputContext;
|
||||
}
|
||||
interface ElsaCodeEditorInput {
|
||||
"inputContext": NodeInputContext;
|
||||
}
|
||||
interface ElsaContextMenu {
|
||||
"menuItems": Array<MenuItem>;
|
||||
}
|
||||
|
|
@ -83,6 +87,16 @@ export namespace Components {
|
|||
"show": (animate?: boolean) => Promise<void>;
|
||||
"size": string;
|
||||
}
|
||||
interface ElsaMonacoEditor {
|
||||
"editorHeight": string;
|
||||
"language": string;
|
||||
"monacoLibPath"?: string;
|
||||
"padding": string;
|
||||
"setJavaScriptLibs": (libs: Array<MonacoLib>) => Promise<void>;
|
||||
"setValue": (value: string) => Promise<void>;
|
||||
"singleLineMode": boolean;
|
||||
"value": string;
|
||||
}
|
||||
interface ElsaMultiLineInput {
|
||||
"inputContext": NodeInputContext;
|
||||
}
|
||||
|
|
@ -113,6 +127,7 @@ export namespace Components {
|
|||
"tabs": Array<TabDefinition>;
|
||||
}
|
||||
interface ElsaStudio {
|
||||
"monacoLibPath": string;
|
||||
"serverUrl": string;
|
||||
}
|
||||
interface ElsaToolbox {
|
||||
|
|
@ -149,6 +164,7 @@ export namespace Components {
|
|||
"getWorkflow": () => Promise<Workflow>;
|
||||
"importWorkflow": (workflow: Workflow, workflowInstance?: WorkflowInstance) => Promise<void>;
|
||||
"importWorkflowMetadata": (workflow: Workflow) => Promise<void>;
|
||||
"monacoLibPath": string;
|
||||
"registerActivityDrivers": (register: (registry: ActivityDriverRegistry) => void) => Promise<void>;
|
||||
"triggerDescriptors": Array<TriggerDescriptor>;
|
||||
}
|
||||
|
|
@ -188,6 +204,12 @@ declare global {
|
|||
prototype: HTMLElsaCheckListInputElement;
|
||||
new (): HTMLElsaCheckListInputElement;
|
||||
};
|
||||
interface HTMLElsaCodeEditorInputElement extends Components.ElsaCodeEditorInput, HTMLStencilElement {
|
||||
}
|
||||
var HTMLElsaCodeEditorInputElement: {
|
||||
prototype: HTMLElsaCodeEditorInputElement;
|
||||
new (): HTMLElsaCodeEditorInputElement;
|
||||
};
|
||||
interface HTMLElsaContextMenuElement extends Components.ElsaContextMenu, HTMLStencilElement {
|
||||
}
|
||||
var HTMLElsaContextMenuElement: {
|
||||
|
|
@ -236,6 +258,12 @@ declare global {
|
|||
prototype: HTMLElsaModalDialogElement;
|
||||
new (): HTMLElsaModalDialogElement;
|
||||
};
|
||||
interface HTMLElsaMonacoEditorElement extends Components.ElsaMonacoEditor, HTMLStencilElement {
|
||||
}
|
||||
var HTMLElsaMonacoEditorElement: {
|
||||
prototype: HTMLElsaMonacoEditorElement;
|
||||
new (): HTMLElsaMonacoEditorElement;
|
||||
};
|
||||
interface HTMLElsaMultiLineInputElement extends Components.ElsaMultiLineInput, HTMLStencilElement {
|
||||
}
|
||||
var HTMLElsaMultiLineInputElement: {
|
||||
|
|
@ -360,6 +388,7 @@ declare global {
|
|||
"elsa-activity-properties-editor": HTMLElsaActivityPropertiesEditorElement;
|
||||
"elsa-canvas": HTMLElsaCanvasElement;
|
||||
"elsa-check-list-input": HTMLElsaCheckListInputElement;
|
||||
"elsa-code-editor-input": HTMLElsaCodeEditorInputElement;
|
||||
"elsa-context-menu": HTMLElsaContextMenuElement;
|
||||
"elsa-dropdown-button": HTMLElsaDropdownButtonElement;
|
||||
"elsa-dropdown-input": HTMLElsaDropdownInputElement;
|
||||
|
|
@ -368,6 +397,7 @@ declare global {
|
|||
"elsa-input-tags": HTMLElsaInputTagsElement;
|
||||
"elsa-input-tags-dropdown": HTMLElsaInputTagsDropdownElement;
|
||||
"elsa-modal-dialog": HTMLElsaModalDialogElement;
|
||||
"elsa-monaco-editor": HTMLElsaMonacoEditorElement;
|
||||
"elsa-multi-line-input": HTMLElsaMultiLineInputElement;
|
||||
"elsa-multi-text-input": HTMLElsaMultiTextInputElement;
|
||||
"elsa-pager": HTMLElsaPagerElement;
|
||||
|
|
@ -403,6 +433,9 @@ declare namespace LocalJSX {
|
|||
interface ElsaCheckListInput {
|
||||
"inputContext"?: NodeInputContext;
|
||||
}
|
||||
interface ElsaCodeEditorInput {
|
||||
"inputContext"?: NodeInputContext;
|
||||
}
|
||||
interface ElsaContextMenu {
|
||||
"menuItems"?: Array<MenuItem>;
|
||||
}
|
||||
|
|
@ -454,6 +487,15 @@ declare namespace LocalJSX {
|
|||
"onShown"?: (event: CustomEvent<any>) => void;
|
||||
"size"?: string;
|
||||
}
|
||||
interface ElsaMonacoEditor {
|
||||
"editorHeight"?: string;
|
||||
"language"?: string;
|
||||
"monacoLibPath"?: string;
|
||||
"onValueChanged"?: (event: CustomEvent<MonacoValueChangedArgs>) => void;
|
||||
"padding"?: string;
|
||||
"singleLineMode"?: boolean;
|
||||
"value"?: string;
|
||||
}
|
||||
interface ElsaMultiLineInput {
|
||||
"inputContext"?: NodeInputContext;
|
||||
}
|
||||
|
|
@ -486,6 +528,7 @@ declare namespace LocalJSX {
|
|||
"tabs"?: Array<TabDefinition>;
|
||||
}
|
||||
interface ElsaStudio {
|
||||
"monacoLibPath"?: string;
|
||||
"serverUrl"?: string;
|
||||
}
|
||||
interface ElsaToolbox {
|
||||
|
|
@ -520,6 +563,7 @@ declare namespace LocalJSX {
|
|||
}
|
||||
interface ElsaWorkflowEditor {
|
||||
"activityDescriptors"?: Array<ActivityDescriptor>;
|
||||
"monacoLibPath"?: string;
|
||||
"onWorkflowUpdated"?: (event: CustomEvent<WorkflowUpdatedArgs>) => void;
|
||||
"triggerDescriptors"?: Array<TriggerDescriptor>;
|
||||
}
|
||||
|
|
@ -546,6 +590,7 @@ declare namespace LocalJSX {
|
|||
"elsa-activity-properties-editor": ElsaActivityPropertiesEditor;
|
||||
"elsa-canvas": ElsaCanvas;
|
||||
"elsa-check-list-input": ElsaCheckListInput;
|
||||
"elsa-code-editor-input": ElsaCodeEditorInput;
|
||||
"elsa-context-menu": ElsaContextMenu;
|
||||
"elsa-dropdown-button": ElsaDropdownButton;
|
||||
"elsa-dropdown-input": ElsaDropdownInput;
|
||||
|
|
@ -554,6 +599,7 @@ declare namespace LocalJSX {
|
|||
"elsa-input-tags": ElsaInputTags;
|
||||
"elsa-input-tags-dropdown": ElsaInputTagsDropdown;
|
||||
"elsa-modal-dialog": ElsaModalDialog;
|
||||
"elsa-monaco-editor": ElsaMonacoEditor;
|
||||
"elsa-multi-line-input": ElsaMultiLineInput;
|
||||
"elsa-multi-text-input": ElsaMultiTextInput;
|
||||
"elsa-pager": ElsaPager;
|
||||
|
|
@ -583,6 +629,7 @@ declare module "@stencil/core" {
|
|||
"elsa-activity-properties-editor": LocalJSX.ElsaActivityPropertiesEditor & JSXBase.HTMLAttributes<HTMLElsaActivityPropertiesEditorElement>;
|
||||
"elsa-canvas": LocalJSX.ElsaCanvas & JSXBase.HTMLAttributes<HTMLElsaCanvasElement>;
|
||||
"elsa-check-list-input": LocalJSX.ElsaCheckListInput & JSXBase.HTMLAttributes<HTMLElsaCheckListInputElement>;
|
||||
"elsa-code-editor-input": LocalJSX.ElsaCodeEditorInput & JSXBase.HTMLAttributes<HTMLElsaCodeEditorInputElement>;
|
||||
"elsa-context-menu": LocalJSX.ElsaContextMenu & JSXBase.HTMLAttributes<HTMLElsaContextMenuElement>;
|
||||
"elsa-dropdown-button": LocalJSX.ElsaDropdownButton & JSXBase.HTMLAttributes<HTMLElsaDropdownButtonElement>;
|
||||
"elsa-dropdown-input": LocalJSX.ElsaDropdownInput & JSXBase.HTMLAttributes<HTMLElsaDropdownInputElement>;
|
||||
|
|
@ -591,6 +638,7 @@ declare module "@stencil/core" {
|
|||
"elsa-input-tags": LocalJSX.ElsaInputTags & JSXBase.HTMLAttributes<HTMLElsaInputTagsElement>;
|
||||
"elsa-input-tags-dropdown": LocalJSX.ElsaInputTagsDropdown & JSXBase.HTMLAttributes<HTMLElsaInputTagsDropdownElement>;
|
||||
"elsa-modal-dialog": LocalJSX.ElsaModalDialog & JSXBase.HTMLAttributes<HTMLElsaModalDialogElement>;
|
||||
"elsa-monaco-editor": LocalJSX.ElsaMonacoEditor & JSXBase.HTMLAttributes<HTMLElsaMonacoEditorElement>;
|
||||
"elsa-multi-line-input": LocalJSX.ElsaMultiLineInput & JSXBase.HTMLAttributes<HTMLElsaMultiLineInputElement>;
|
||||
"elsa-multi-text-input": LocalJSX.ElsaMultiTextInput & JSXBase.HTMLAttributes<HTMLElsaMultiTextInputElement>;
|
||||
"elsa-pager": LocalJSX.ElsaPager & JSXBase.HTMLAttributes<HTMLElsaPagerElement>;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
$activity-picker-width: 300px;
|
||||
$trigger-panel-height: 76px;
|
||||
$activity-editor-width: 500px;
|
||||
$activity-editor-width: 580px;
|
||||
|
||||
elsa-canvas {
|
||||
left: $activity-picker-width;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import {ActivityDriverRegistry} from '../../../services';
|
|||
import {TriggerSelectedArgs, TriggersUpdatedArgs} from '../trigger-container/trigger-container';
|
||||
import {DeleteTriggerRequestedArgs, TriggerUpdatedArgs} from "../trigger-properties-editor/trigger-properties-editor";
|
||||
import {WorkflowPropsUpdatedArgs} from "../workflow-properties-editor/workflow-properties-editor";
|
||||
import {MonacoEditorSettings} from "../../../services/monaco-editor-settings";
|
||||
|
||||
export interface WorkflowUpdatedArgs {
|
||||
workflow: Workflow;
|
||||
|
|
@ -55,6 +56,7 @@ export class WorkflowEditor {
|
|||
this.saveChangesDebounced = debounce(this.saveChanges, 1000);
|
||||
}
|
||||
|
||||
@Prop({attribute: 'monaco-lib-path'}) public monacoLibPath: string;
|
||||
@Prop() public activityDescriptors: Array<ActivityDescriptor> = [];
|
||||
@Prop() public triggerDescriptors: Array<TriggerDescriptor> = [];
|
||||
@Event() public workflowUpdated: EventEmitter<WorkflowUpdatedArgs>
|
||||
|
|
@ -66,6 +68,12 @@ export class WorkflowEditor {
|
|||
return !this.workflowInstance;
|
||||
}
|
||||
|
||||
@Watch('monacoLibPath')
|
||||
private handleMonacoLibPath(value: string) {
|
||||
const settings = Container.get(MonacoEditorSettings);
|
||||
settings.monacoLibPath = value;
|
||||
}
|
||||
|
||||
@Listen('resize', {target: 'window'})
|
||||
private async handleResize() {
|
||||
await this.updateLayout();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
import {Component, h, Prop} from '@stencil/core';
|
||||
import {EditorHeight, LiteralExpression, SyntaxNames} from "../../models";
|
||||
import {NodeInputContext} from "../../services/node-input-driver";
|
||||
import {getInputPropertyValue} from "../../utils";
|
||||
import {MonacoValueChangedArgs} from "../shared/monaco-editor/monaco-editor";
|
||||
|
||||
interface CodeEditorOptions {
|
||||
editorHeight?: EditorHeight;
|
||||
language?: string;
|
||||
singleLineMode?: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-code-editor-input',
|
||||
shadow: false
|
||||
})
|
||||
export class CodeEditorInput {
|
||||
@Prop() public inputContext: NodeInputContext;
|
||||
|
||||
public render() {
|
||||
const inputContext = this.inputContext;
|
||||
const inputDescriptor = inputContext.inputDescriptor;
|
||||
const options: CodeEditorOptions = inputDescriptor.options || {};
|
||||
const input = getInputPropertyValue(inputContext);
|
||||
let currentValue = (input?.expression as LiteralExpression)?.value;
|
||||
|
||||
if (currentValue == undefined)
|
||||
currentValue = inputDescriptor.defaultValue;
|
||||
|
||||
return (
|
||||
<elsa-monaco-editor value={currentValue} {...options} onValueChanged={this.onChange}/>
|
||||
);
|
||||
}
|
||||
|
||||
private onChange = (e: CustomEvent<MonacoValueChangedArgs>) => {
|
||||
const value = e.detail.value;
|
||||
this.inputContext.inputChanged(value, SyntaxNames.Literal);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
.monaco-editor-host {
|
||||
display: block;
|
||||
position: relative;
|
||||
min-height: 6em;
|
||||
}
|
||||
|
||||
.monaco-editor-container {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-height: 100% !important;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.monaco-editor {
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.monaco-editor .overflow-guard {
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget div.tree {
|
||||
white-space: unset;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
import {Component, Event, EventEmitter, h, Host, Method, Prop, Watch} from '@stencil/core';
|
||||
import {initializeMonacoWorker, Monaco} from "./utils";
|
||||
import globalState from '../../../data/store';
|
||||
|
||||
export interface MonacoValueChangedArgs {
|
||||
value: string;
|
||||
markers: Array<any>;
|
||||
}
|
||||
|
||||
export interface MonacoLib {
|
||||
content: string;
|
||||
filePath?: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-monaco-editor',
|
||||
styleUrl: 'monaco-editor.scss',
|
||||
shadow: false
|
||||
})
|
||||
export class MonacoEditor {
|
||||
private monaco: Monaco;
|
||||
private container: HTMLElement;
|
||||
private editor: any;
|
||||
|
||||
@Prop() public monacoLibPath?: string;
|
||||
@Prop() public editorHeight: string = '5em';
|
||||
@Prop() public value: string;
|
||||
@Prop() public language: string;
|
||||
@Prop() public singleLineMode: boolean = false;
|
||||
@Prop() public padding: string;
|
||||
@Event() public valueChanged: EventEmitter<MonacoValueChangedArgs>;
|
||||
|
||||
@Watch('language')
|
||||
languageChangeHandler(newValue: string) {
|
||||
if (!this.editor)
|
||||
return;
|
||||
|
||||
const model = this.editor.getModel();
|
||||
this.monaco.editor.setModelLanguage(model, this.language);
|
||||
}
|
||||
|
||||
@Method()
|
||||
async setValue(value: string) {
|
||||
if (!this.editor)
|
||||
return;
|
||||
|
||||
const model = this.editor.getModel();
|
||||
model.setValue(value || '');
|
||||
}
|
||||
|
||||
@Method()
|
||||
async setJavaScriptLibs(libs: Array<MonacoLib>) {
|
||||
const monaco = this.monaco;
|
||||
|
||||
const defaultLib: MonacoLib = {
|
||||
content: "<reference lib=\"es5\" />",
|
||||
filePath: "lib.d.ts"
|
||||
};
|
||||
|
||||
libs = [defaultLib, ...libs];
|
||||
monaco.languages.typescript.javascriptDefaults.setExtraLibs(libs);
|
||||
|
||||
for (const lib of libs) {
|
||||
const oldModel = monaco.editor.getModel(lib.filePath);
|
||||
|
||||
if (oldModel)
|
||||
oldModel.dispose();
|
||||
|
||||
monaco.editor.createModel(lib.content, 'typescript', monaco.Uri.parse(lib.filePath));
|
||||
}
|
||||
}
|
||||
|
||||
async componentWillLoad() {
|
||||
const monacoLibPath = this.monacoLibPath || globalState.monacoLibPath;
|
||||
this.monaco = await initializeMonacoWorker(monacoLibPath);
|
||||
await this.setJavaScriptLibs([]);
|
||||
this.registerLiquid();
|
||||
}
|
||||
|
||||
componentDidLoad() {
|
||||
const monaco = this.monaco;
|
||||
const language = this.language;
|
||||
|
||||
// Validation settings.
|
||||
monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
|
||||
noSemanticValidation: true,
|
||||
noSyntaxValidation: false,
|
||||
});
|
||||
|
||||
// Compiler options.
|
||||
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
|
||||
target: monaco.languages.typescript.ScriptTarget.ES2020,
|
||||
lib: [],
|
||||
allowNonTsExtensions: true
|
||||
});
|
||||
|
||||
monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true);
|
||||
|
||||
const defaultOptions = {
|
||||
value: this.value,
|
||||
language: language,
|
||||
fontFamily: "Roboto Mono, monospace",
|
||||
renderLineHighlight: 'none',
|
||||
minimap: {
|
||||
enabled: false
|
||||
},
|
||||
automaticLayout: true,
|
||||
lineNumbers: "on",
|
||||
theme: "vs",
|
||||
roundedSelection: true,
|
||||
scrollBeyondLastLine: false,
|
||||
readOnly: false,
|
||||
overviewRulerLanes: 0,
|
||||
overviewRulerBorder: false,
|
||||
lineDecorationsWidth: 0,
|
||||
hideCursorInOverviewRuler: true,
|
||||
glyphMargin: false
|
||||
};
|
||||
|
||||
let options = defaultOptions;
|
||||
|
||||
if (this.singleLineMode) {
|
||||
options = {
|
||||
...defaultOptions, ...{
|
||||
wordWrap: 'off',
|
||||
lineNumbers: 'off',
|
||||
lineNumbersMinChars: 0,
|
||||
folding: false,
|
||||
scrollBeyondLastColumn: 0,
|
||||
scrollbar: {horizontal: 'hidden', vertical: 'hidden'},
|
||||
find: {addExtraSpaceOnTop: false, autoFindInSelection: 'never', seedSearchStringFromSelection: false},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.editor = monaco.editor.create(this.container, options);
|
||||
|
||||
this.editor.onDidChangeModelContent(e => {
|
||||
const value = this.editor.getValue();
|
||||
const markers = monaco.editor.getModelMarkers({owner: language});
|
||||
this.valueChanged.emit({value: value, markers: markers});
|
||||
});
|
||||
|
||||
if (this.singleLineMode) {
|
||||
this.editor.onKeyDown(e => {
|
||||
if (e.keyCode == monaco.KeyCode.Enter) {
|
||||
// We only prevent enter when the suggest model is not active
|
||||
if (this.editor.getContribution('editor.contrib.suggestController').model.state == 0) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.editor.onDidPaste(e => {
|
||||
if (e.range.endLineNumber > 1) {
|
||||
let newContent = "";
|
||||
const model = this.editor.getModel();
|
||||
let lineCount = model.getLineCount();
|
||||
for (let i = 0; i < lineCount; i++) {
|
||||
newContent += model.getLineContent(i + 1);
|
||||
}
|
||||
model.setValue(newContent);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
const editor = this.editor;
|
||||
|
||||
if (!!editor)
|
||||
editor.dispose();
|
||||
}
|
||||
|
||||
registerLiquid() {
|
||||
const monaco = this.monaco;
|
||||
monaco.languages.register({id: 'liquid'});
|
||||
|
||||
monaco.languages.registerCompletionItemProvider('liquid', {
|
||||
provideCompletionItems: () => {
|
||||
const autocompleteProviderItems = [];
|
||||
const keywords = ['assign', 'capture', 'endcapture', 'increment', 'decrement',
|
||||
'if', 'else', 'elsif', 'endif', 'for', 'endfor', 'break',
|
||||
'continue', 'limit', 'offset', 'range', 'reversed', 'cols',
|
||||
'case', 'endcase', 'when', 'block', 'endblock', 'true', 'false',
|
||||
'in', 'unless', 'endunless', 'cycle', 'tablerow', 'endtablerow',
|
||||
'contains', 'startswith', 'endswith', 'comment', 'endcomment',
|
||||
'raw', 'endraw', 'editable', 'endentitylist', 'endentityview', 'endinclude',
|
||||
'endmarker', 'entitylist', 'entityview', 'forloop', 'image', 'include',
|
||||
'marker', 'outputcache', 'plugin', 'style', 'text', 'widget',
|
||||
'abs', 'append', 'at_least', 'at_most', 'capitalize', 'ceil', 'compact',
|
||||
'concat', 'date', 'default', 'divided_by', 'downcase', 'escape',
|
||||
'escape_once', 'first', 'floor', 'join', 'last', 'lstrip', 'map',
|
||||
'minus', 'modulo', 'newline_to_br', 'plus', 'prepend', 'remove',
|
||||
'remove_first', 'replace', 'replace_first', 'reverse', 'round',
|
||||
'rstrip', 'size', 'slice', 'sort', 'sort_natural', 'split', 'strip',
|
||||
'strip_html', 'strip_newlines', 'times', 'truncate', 'truncatewords',
|
||||
'uniq', 'upcase', 'url_decode', 'url_encode'];
|
||||
|
||||
for (let i = 0; i < keywords.length; i++) {
|
||||
autocompleteProviderItems.push({'label': keywords[i], kind: monaco.languages.CompletionItemKind.Keyword});
|
||||
}
|
||||
|
||||
return {suggestions: autocompleteProviderItems};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const padding = this.padding || 'elsa-pt-1.5 elsa-pl-1';
|
||||
return (
|
||||
<Host
|
||||
class="monaco-editor-host border focus:ring-blue-500 focus:border-blue-500 block w-full min-w-0 rounded-md sm:text-sm border-gray-300 p-4"
|
||||
style={{'min-height': this.editorHeight}}>
|
||||
<div ref={el => this.container = el} class={`monaco-editor-container ${padding}`}/>
|
||||
</Host>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
const win = window as any;
|
||||
const require = win.require;
|
||||
|
||||
export interface Monaco {
|
||||
editor: any;
|
||||
languages: any;
|
||||
KeyCode: any;
|
||||
Uri: any;
|
||||
}
|
||||
|
||||
export function initializeMonacoWorker(libPath?: string): Promise<Monaco> {
|
||||
|
||||
if (win.monaco)
|
||||
return win.monaco;
|
||||
|
||||
if (!libPath)
|
||||
return win.monaco;
|
||||
|
||||
const origin = document.location.origin;
|
||||
const baseUrl = libPath.startsWith('http') ? libPath : `${origin}/${libPath}`;
|
||||
|
||||
require.config({paths: {'vs': `${baseUrl}/vs`}});
|
||||
win.MonacoEnvironment = {getWorkerUrl: () => proxy};
|
||||
|
||||
let proxy = URL.createObjectURL(new Blob([`
|
||||
self.MonacoEnvironment = {
|
||||
baseUrl: '${baseUrl}'
|
||||
};
|
||||
importScripts('${baseUrl}/vs/base/worker/workerMain.js');
|
||||
`], {type: 'text/javascript'}));
|
||||
|
||||
return new Promise(resolve => {
|
||||
require(["vs/editor/editor.main"], () => {
|
||||
resolve(win.monaco);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export const DefaultLibUri: string = 'defaultLib:lib.es6.d.ts';
|
||||
|
|
@ -5,6 +5,7 @@ import {ElsaApiClientProvider, ElsaClient, SaveWorkflowRequest, ServerSettings}
|
|||
import {ActivityDescriptor, TriggerDescriptor, VersionOptions, Workflow, WorkflowInstanceSummary, WorkflowSummary} from '../../../models';
|
||||
import {WorkflowUpdatedArgs} from '../../designer/workflow-editor/workflow-editor';
|
||||
import {PublishClickedArgs} from "../../toolbar/workflow-publish-button/workflow-publish-button";
|
||||
import {MonacoEditorSettings} from "../../../services/monaco-editor-settings";
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-studio'
|
||||
|
|
@ -17,7 +18,7 @@ export class Studio {
|
|||
|
||||
@Element() private el: HTMLElsaStudioElement;
|
||||
@Prop({attribute: 'server'}) public serverUrl: string;
|
||||
|
||||
@Prop({attribute: 'monaco-lib-path'}) public monacoLibPath: string;
|
||||
|
||||
@Watch('serverUrl')
|
||||
private handleServerUrl(value: string) {
|
||||
|
|
@ -25,6 +26,15 @@ export class Studio {
|
|||
settings.baseAddress = value;
|
||||
}
|
||||
|
||||
@Watch('monacoLibPath')
|
||||
private handleMonacoLibPath(value: string) {
|
||||
const settings = Container.get(MonacoEditorSettings);
|
||||
settings.monacoLibPath = value;
|
||||
|
||||
if (!!this.workflowEditorElement)
|
||||
this.workflowEditorElement.monacoLibPath = this.monacoLibPath;
|
||||
}
|
||||
|
||||
@Listen('workflowUpdated')
|
||||
private async handleWorkflowUpdated(e: CustomEvent<WorkflowUpdatedArgs>) {
|
||||
const workflow = e.detail.workflow;
|
||||
|
|
@ -84,6 +94,7 @@ export class Studio {
|
|||
if (!!this.workflowEditorElement) {
|
||||
this.workflowEditorElement.activityDescriptors = this.activityDescriptors;
|
||||
this.workflowEditorElement.triggerDescriptors = this.triggerDescriptors;
|
||||
this.workflowEditorElement.monacoLibPath = this.monacoLibPath;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,12 +6,13 @@
|
|||
<title>Elsa Workflows Designer</title>
|
||||
<link rel="stylesheet" href="https://rsms.me/inter/inter.css">
|
||||
<link rel="stylesheet" href="/build/elsa-workflows-designer.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.31.1/min/vs/loader.min.js"></script>
|
||||
<script type="module" src="/build/elsa-workflows-designer.esm.js"></script>
|
||||
<script nomodule src="/build/elsa-workflows-designer.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!--Use the Server Shell component to handle automatic interaction with the Elsa Server API-->
|
||||
<elsa-studio server="https://localhost:5001">
|
||||
<elsa-studio server="https://localhost:5001" monaco-lib-path="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.31.1/min">
|
||||
<elsa-workflow-toolbar></elsa-workflow-toolbar>
|
||||
<div class="absolute inset-0" style="top: 63px;">
|
||||
<elsa-workflow-editor></elsa-workflow-editor>
|
||||
|
|
|
|||
|
|
@ -92,3 +92,8 @@ export interface RuntimeSelectListProviderSettings {
|
|||
runtimeSelectListProviderType: string;
|
||||
context?: any;
|
||||
}
|
||||
|
||||
export enum EditorHeight {
|
||||
Default = 'Default',
|
||||
Large = 'Large'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
export * from './activity-driver';
|
||||
export * from './activity-driver-registry';
|
||||
export * from './activity-icon-registry';
|
||||
export * from './custom-event-bus';
|
||||
export * from './elsa-api-client-provider';
|
||||
export * from './event-bus';
|
||||
export * from './input-control-registry';
|
||||
export * from './input-driver-registry';
|
||||
export * from './server-settings';
|
||||
export * from './trigger-driver';
|
||||
export * from './trigger-driver-registry';
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ export class InputControlRegistry {
|
|||
this.add('check-list', c => <elsa-check-list-input inputContext={c}/>);
|
||||
this.add('radio-list', c => <elsa-radio-list-input inputContext={c}/>);
|
||||
this.add('multi-text', c => <elsa-multi-text-input inputContext={c}/>);
|
||||
this.add('code-editor', c => <elsa-code-editor-input inputContext={c}/>);
|
||||
}
|
||||
|
||||
public add(uiHint: UIHint, control: RenderActivityPropInputControl) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
import {Service} from "typedi";
|
||||
import store from "../data/store";
|
||||
|
||||
@Service()
|
||||
export class MonacoEditorSettings {
|
||||
get monacoLibPath(): string {
|
||||
return store.monacoLibPath;
|
||||
}
|
||||
|
||||
set monacoLibPath(value: string) {
|
||||
store.monacoLibPath = value;
|
||||
}
|
||||
}
|
||||
|
|
@ -38,10 +38,13 @@ public class WriteLines : Activity, IActivityPropertyOptionsProvider
|
|||
|
||||
[Input(Options = new[] { "Normal", "Bold", "Italic" }, UIHint = InputUIHints.RadioList)]
|
||||
public Input<string> Format { get; set; } = default!;
|
||||
|
||||
|
||||
[Input(OptionsProvider = typeof(WriteLines), UIHint = InputUIHints.MultiLine)]
|
||||
public Input<string> Body { get; set; } = default!;
|
||||
|
||||
|
||||
[Input(UIHint = InputUIHints.CodeEditor, OptionsProvider = typeof(WriteLines))]
|
||||
public Input<string> Script { get; set; } = default!;
|
||||
|
||||
[Input(UIHint = InputUIHints.MultiText)]
|
||||
public Input<ICollection<string>> Tags { get; set; } = default!;
|
||||
|
||||
|
|
@ -55,9 +58,11 @@ public class WriteLines : Activity, IActivityPropertyOptionsProvider
|
|||
|
||||
public object? GetOptions(PropertyInfo property)
|
||||
{
|
||||
if (property.Name == nameof(Body))
|
||||
return new MultiLineOptions(EditorHeight.Large);
|
||||
|
||||
return null;
|
||||
return property.Name switch
|
||||
{
|
||||
nameof(Body) => new { EditorHeight = EditorHeight.Large },
|
||||
nameof(Script) => new { EditorHeight = EditorHeight.Large, Language = "JavaScript" },
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue