Incremental work on modal dialog service
This commit is contained in:
parent
e49f4642bc
commit
691565ed98
|
|
@ -29,8 +29,6 @@ import { WorkflowDefinitionPropsUpdatedArgs, WorkflowDefinitionUpdatedArgs } fro
|
|||
import { PublishClickedArgs as PublishClickedArgs1 } from "./modules/workflow-definitions/components/publish-button";
|
||||
export namespace Components {
|
||||
interface ElsaActivityDefinitionBrowser {
|
||||
"hide": () => Promise<void>;
|
||||
"show": () => Promise<void>;
|
||||
}
|
||||
interface ElsaActivityDefinitionEditor {
|
||||
"activityDefinition"?: ActivityDefinition;
|
||||
|
|
@ -170,15 +168,16 @@ export namespace Components {
|
|||
"selectedLabels": Array<string>;
|
||||
}
|
||||
interface ElsaLabelsManager {
|
||||
"hide": () => Promise<void>;
|
||||
"show": () => Promise<void>;
|
||||
}
|
||||
interface ElsaModalDialog {
|
||||
"actions": Array<ActionDefinition>;
|
||||
"content": () => any;
|
||||
"hide": (animate?: boolean) => Promise<void>;
|
||||
"show": (animate?: boolean) => Promise<void>;
|
||||
"size": string;
|
||||
}
|
||||
interface ElsaModalDialogContainer {
|
||||
}
|
||||
interface ElsaMonacoEditor {
|
||||
"editorHeight": string;
|
||||
"language": string;
|
||||
|
|
@ -232,17 +231,13 @@ export namespace Components {
|
|||
"tooltipContent": any;
|
||||
"tooltipPosition"?: string;
|
||||
}
|
||||
interface ElsaVariableEditorDialog {
|
||||
"hide": () => Promise<void>;
|
||||
"show": () => Promise<void>;
|
||||
interface ElsaVariableEditorDialogContent {
|
||||
"variable": Variable;
|
||||
}
|
||||
interface ElsaVariablesEditor {
|
||||
"variables"?: Array<Variable>;
|
||||
}
|
||||
interface ElsaWorkflowDefinitionBrowser {
|
||||
"hide": () => Promise<void>;
|
||||
"show": () => Promise<void>;
|
||||
}
|
||||
interface ElsaWorkflowDefinitionEditor {
|
||||
"getCanvas": () => Promise<HTMLElsaCanvasElement>;
|
||||
|
|
@ -269,8 +264,6 @@ export namespace Components {
|
|||
"workflowDefinition"?: WorkflowDefinition;
|
||||
}
|
||||
interface ElsaWorkflowInstanceBrowser {
|
||||
"hide": () => Promise<void>;
|
||||
"show": () => Promise<void>;
|
||||
}
|
||||
interface ElsaWorkflowInstanceProperties {
|
||||
"hide": () => Promise<void>;
|
||||
|
|
@ -467,6 +460,12 @@ declare global {
|
|||
prototype: HTMLElsaModalDialogElement;
|
||||
new (): HTMLElsaModalDialogElement;
|
||||
};
|
||||
interface HTMLElsaModalDialogContainerElement extends Components.ElsaModalDialogContainer, HTMLStencilElement {
|
||||
}
|
||||
var HTMLElsaModalDialogContainerElement: {
|
||||
prototype: HTMLElsaModalDialogContainerElement;
|
||||
new (): HTMLElsaModalDialogContainerElement;
|
||||
};
|
||||
interface HTMLElsaMonacoEditorElement extends Components.ElsaMonacoEditor, HTMLStencilElement {
|
||||
}
|
||||
var HTMLElsaMonacoEditorElement: {
|
||||
|
|
@ -545,11 +544,11 @@ declare global {
|
|||
prototype: HTMLElsaTooltipElement;
|
||||
new (): HTMLElsaTooltipElement;
|
||||
};
|
||||
interface HTMLElsaVariableEditorDialogElement extends Components.ElsaVariableEditorDialog, HTMLStencilElement {
|
||||
interface HTMLElsaVariableEditorDialogContentElement extends Components.ElsaVariableEditorDialogContent, HTMLStencilElement {
|
||||
}
|
||||
var HTMLElsaVariableEditorDialogElement: {
|
||||
prototype: HTMLElsaVariableEditorDialogElement;
|
||||
new (): HTMLElsaVariableEditorDialogElement;
|
||||
var HTMLElsaVariableEditorDialogContentElement: {
|
||||
prototype: HTMLElsaVariableEditorDialogContentElement;
|
||||
new (): HTMLElsaVariableEditorDialogContentElement;
|
||||
};
|
||||
interface HTMLElsaVariablesEditorElement extends Components.ElsaVariablesEditor, HTMLStencilElement {
|
||||
}
|
||||
|
|
@ -669,6 +668,7 @@ declare global {
|
|||
"elsa-label-picker": HTMLElsaLabelPickerElement;
|
||||
"elsa-labels-manager": HTMLElsaLabelsManagerElement;
|
||||
"elsa-modal-dialog": HTMLElsaModalDialogElement;
|
||||
"elsa-modal-dialog-container": HTMLElsaModalDialogContainerElement;
|
||||
"elsa-monaco-editor": HTMLElsaMonacoEditorElement;
|
||||
"elsa-multi-line-input": HTMLElsaMultiLineInputElement;
|
||||
"elsa-multi-text-input": HTMLElsaMultiTextInputElement;
|
||||
|
|
@ -682,7 +682,7 @@ declare global {
|
|||
"elsa-studio": HTMLElsaStudioElement;
|
||||
"elsa-switch-editor": HTMLElsaSwitchEditorElement;
|
||||
"elsa-tooltip": HTMLElsaTooltipElement;
|
||||
"elsa-variable-editor-dialog": HTMLElsaVariableEditorDialogElement;
|
||||
"elsa-variable-editor-dialog-content": HTMLElsaVariableEditorDialogContentElement;
|
||||
"elsa-variables-editor": HTMLElsaVariablesEditorElement;
|
||||
"elsa-workflow-definition-browser": HTMLElsaWorkflowDefinitionBrowserElement;
|
||||
"elsa-workflow-definition-editor": HTMLElsaWorkflowDefinitionEditorElement;
|
||||
|
|
@ -838,11 +838,14 @@ declare namespace LocalJSX {
|
|||
}
|
||||
interface ElsaModalDialog {
|
||||
"actions"?: Array<ActionDefinition>;
|
||||
"content"?: () => any;
|
||||
"onActionInvoked"?: (event: CustomEvent<ActionInvokedArgs>) => void;
|
||||
"onHidden"?: (event: CustomEvent<any>) => void;
|
||||
"onShown"?: (event: CustomEvent<any>) => void;
|
||||
"size"?: string;
|
||||
}
|
||||
interface ElsaModalDialogContainer {
|
||||
}
|
||||
interface ElsaMonacoEditor {
|
||||
"editorHeight"?: string;
|
||||
"language"?: string;
|
||||
|
|
@ -898,7 +901,7 @@ declare namespace LocalJSX {
|
|||
"tooltipContent"?: any;
|
||||
"tooltipPosition"?: string;
|
||||
}
|
||||
interface ElsaVariableEditorDialog {
|
||||
interface ElsaVariableEditorDialogContent {
|
||||
"onVariableChanged"?: (event: CustomEvent<Variable>) => void;
|
||||
"variable"?: Variable;
|
||||
}
|
||||
|
|
@ -989,6 +992,7 @@ declare namespace LocalJSX {
|
|||
"elsa-label-picker": ElsaLabelPicker;
|
||||
"elsa-labels-manager": ElsaLabelsManager;
|
||||
"elsa-modal-dialog": ElsaModalDialog;
|
||||
"elsa-modal-dialog-container": ElsaModalDialogContainer;
|
||||
"elsa-monaco-editor": ElsaMonacoEditor;
|
||||
"elsa-multi-line-input": ElsaMultiLineInput;
|
||||
"elsa-multi-text-input": ElsaMultiTextInput;
|
||||
|
|
@ -1002,7 +1006,7 @@ declare namespace LocalJSX {
|
|||
"elsa-studio": ElsaStudio;
|
||||
"elsa-switch-editor": ElsaSwitchEditor;
|
||||
"elsa-tooltip": ElsaTooltip;
|
||||
"elsa-variable-editor-dialog": ElsaVariableEditorDialog;
|
||||
"elsa-variable-editor-dialog-content": ElsaVariableEditorDialogContent;
|
||||
"elsa-variables-editor": ElsaVariablesEditor;
|
||||
"elsa-workflow-definition-browser": ElsaWorkflowDefinitionBrowser;
|
||||
"elsa-workflow-definition-editor": ElsaWorkflowDefinitionEditor;
|
||||
|
|
@ -1051,6 +1055,7 @@ declare module "@stencil/core" {
|
|||
"elsa-label-picker": LocalJSX.ElsaLabelPicker & JSXBase.HTMLAttributes<HTMLElsaLabelPickerElement>;
|
||||
"elsa-labels-manager": LocalJSX.ElsaLabelsManager & JSXBase.HTMLAttributes<HTMLElsaLabelsManagerElement>;
|
||||
"elsa-modal-dialog": LocalJSX.ElsaModalDialog & JSXBase.HTMLAttributes<HTMLElsaModalDialogElement>;
|
||||
"elsa-modal-dialog-container": LocalJSX.ElsaModalDialogContainer & JSXBase.HTMLAttributes<HTMLElsaModalDialogContainerElement>;
|
||||
"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>;
|
||||
|
|
@ -1064,7 +1069,7 @@ declare module "@stencil/core" {
|
|||
"elsa-studio": LocalJSX.ElsaStudio & JSXBase.HTMLAttributes<HTMLElsaStudioElement>;
|
||||
"elsa-switch-editor": LocalJSX.ElsaSwitchEditor & JSXBase.HTMLAttributes<HTMLElsaSwitchEditorElement>;
|
||||
"elsa-tooltip": LocalJSX.ElsaTooltip & JSXBase.HTMLAttributes<HTMLElsaTooltipElement>;
|
||||
"elsa-variable-editor-dialog": LocalJSX.ElsaVariableEditorDialog & JSXBase.HTMLAttributes<HTMLElsaVariableEditorDialogElement>;
|
||||
"elsa-variable-editor-dialog-content": LocalJSX.ElsaVariableEditorDialogContent & JSXBase.HTMLAttributes<HTMLElsaVariableEditorDialogContentElement>;
|
||||
"elsa-variables-editor": LocalJSX.ElsaVariablesEditor & JSXBase.HTMLAttributes<HTMLElsaVariablesEditorElement>;
|
||||
"elsa-workflow-definition-browser": LocalJSX.ElsaWorkflowDefinitionBrowser & JSXBase.HTMLAttributes<HTMLElsaWorkflowDefinitionBrowserElement>;
|
||||
"elsa-workflow-definition-editor": LocalJSX.ElsaWorkflowDefinitionEditor & JSXBase.HTMLAttributes<HTMLElsaWorkflowDefinitionEditorElement>;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
import {Component, h, Prop, Event, EventEmitter, Method} from "@stencil/core";
|
||||
import {DefaultActions, StorageDriverDescriptor, Variable} from "../../../models";
|
||||
import {FormEntry} from "../../shared/forms/form-entry";
|
||||
import {isNullOrWhitespace} from "../../../utils";
|
||||
import descriptorsStore from '../../../data/descriptors-store';
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-variable-editor-dialog-content',
|
||||
shadow: false
|
||||
})
|
||||
export class VariableEditorDialogContent {
|
||||
@Prop() variable: Variable;
|
||||
@Event() variableChanged: EventEmitter<Variable>;
|
||||
|
||||
render() {
|
||||
const variable: Variable = this.variable ?? {name: '', type: 'Object'};
|
||||
const variableType = variable.type;
|
||||
const availableTypes: Array<string> = ['Object', 'String', 'Boolean', 'Int32', 'Int64', 'Single', 'Double']; // TODO: Fetch these from backend.
|
||||
const storageDrivers: Array<StorageDriverDescriptor> = [{id: null, displayName: '-'}, ...descriptorsStore.storageDrivers];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form class="h-full flex flex-col bg-white" onSubmit={e => this.onSubmit(e)} method="post">
|
||||
<div class="pt-4">
|
||||
<h2 class="text-lg font-medium ml-4 mb-2">Edit Variable</h2>
|
||||
<div class="align-middle inline-block min-w-full border-b border-gray-200">
|
||||
|
||||
<FormEntry fieldId="variableName" label="Name" hint="The technical name of the variable.">
|
||||
<input type="text" name="variableName" id="variableName" value={variable.name}/>
|
||||
</FormEntry>
|
||||
|
||||
<FormEntry fieldId="variableType" label="Type" hint="The type of the variable.">
|
||||
<select id="variableType" name="variableType">
|
||||
{availableTypes.map(type => <option value={type} selected={type == variableType}>{type}</option>)}
|
||||
</select>
|
||||
</FormEntry>
|
||||
|
||||
<FormEntry fieldId="variableValue" label="Value" hint="The value of the variable.">
|
||||
<input type="text" name="variableValue" id="variableValue" value={variable.value}/>
|
||||
</FormEntry>
|
||||
|
||||
<FormEntry fieldId="variableStorageDriverId" label="Storage" hint="The storage to use when persisting the variable.">
|
||||
<select id="variableStorageDriverId" name="variableStorageDriverId">
|
||||
{storageDrivers.map(driver => {
|
||||
const value = driver.id;
|
||||
const text = driver.displayName;
|
||||
const selected = value == variable.storageDriverId;
|
||||
return <option value={value} selected={selected}>{text}</option>;
|
||||
})}
|
||||
</select>
|
||||
</FormEntry>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private onSubmit = async (e: Event) => {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(e.target as HTMLFormElement);
|
||||
const name = formData.get('variableName') as string;
|
||||
const value = formData.get('variableValue') as string;
|
||||
const type = formData.get('variableType') as string;
|
||||
const driverId = formData.get('variableStorageDriverId') as string;
|
||||
const variable = this.variable;
|
||||
|
||||
variable.name = name;
|
||||
variable.type = type;
|
||||
variable.value = value;
|
||||
variable.storageDriverId = isNullOrWhitespace(driverId) ? null : driverId;
|
||||
|
||||
this.variableChanged.emit(variable);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
import {Component, h, Prop, Event, EventEmitter, Method} from "@stencil/core";
|
||||
import {DefaultActions, StorageDriverDescriptor, Variable} from "../../../models";
|
||||
import {FormEntry} from "../../shared/forms/form-entry";
|
||||
import {isNullOrWhitespace} from "../../../utils";
|
||||
import descriptorsStore from '../../../data/descriptors-store';
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-variable-editor-dialog',
|
||||
shadow: false
|
||||
})
|
||||
export class VariableEditorDialog {
|
||||
private modalDialog: HTMLElsaModalDialogElement;
|
||||
|
||||
@Prop() variable: Variable;
|
||||
@Event() variableChanged: EventEmitter<Variable>;
|
||||
|
||||
@Method()
|
||||
public async show() {
|
||||
await this.modalDialog.show();
|
||||
}
|
||||
|
||||
@Method()
|
||||
public async hide() {
|
||||
await this.modalDialog.hide();
|
||||
}
|
||||
|
||||
render() {
|
||||
const variable: Variable = this.variable ?? {name: '', type: 'Object'};
|
||||
const variableType = variable.type;
|
||||
const cancelAction = DefaultActions.Cancel();
|
||||
const saveAction = DefaultActions.Save();
|
||||
const actions = [cancelAction, saveAction];
|
||||
const availableTypes: Array<string> = ['Object', 'String', 'Boolean', 'Int32', 'Int64', 'Single', 'Double']; // TODO: Fetch these from backend.
|
||||
const storageDrivers: Array<StorageDriverDescriptor> = [{ id: null, displayName: '-' }, ...descriptorsStore.storageDrivers];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form class="h-full flex flex-col bg-white" onSubmit={e => this.onSubmit(e)} method="post">
|
||||
<elsa-modal-dialog ref={el => (this.modalDialog = el)} actions={actions}>
|
||||
<div class="pt-4">
|
||||
<h2 class="text-lg font-medium ml-4 mb-2">Edit Variable</h2>
|
||||
<div class="align-middle inline-block min-w-full border-b border-gray-200">
|
||||
|
||||
|
||||
<FormEntry fieldId="variableName" label="Name" hint="The technical name of the variable.">
|
||||
<input type="text" name="variableName" id="variableName" value={variable.name}/>
|
||||
</FormEntry>
|
||||
|
||||
<FormEntry fieldId="variableType" label="Type" hint="The type of the variable.">
|
||||
<select id="variableType" name="variableType">
|
||||
{availableTypes.map(type => <option value={type} selected={type == variableType}>{type}</option>)}
|
||||
</select>
|
||||
</FormEntry>
|
||||
|
||||
<FormEntry fieldId="variableValue" label="Value" hint="The value of the variable.">
|
||||
<input type="text" name="variableValue" id="variableValue" value={variable.value}/>
|
||||
</FormEntry>
|
||||
|
||||
<FormEntry fieldId="variableStorageDriverId" label="Storage" hint="The storage to use when persisting the variable.">
|
||||
<select id="variableStorageDriverId" name="variableStorageDriverId">
|
||||
{storageDrivers.map(driver => {
|
||||
const value = driver.id;
|
||||
const text = driver.displayName;
|
||||
const selected = value == variable.storageDriverId;
|
||||
return <option value={value} selected={selected}>{text}</option>;
|
||||
})}
|
||||
</select>
|
||||
</FormEntry>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</elsa-modal-dialog>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private onSubmit = async (e: Event) => {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(e.target as HTMLFormElement);
|
||||
const name = formData.get('variableName') as string;
|
||||
const value = formData.get('variableValue') as string;
|
||||
const type = formData.get('variableType') as string;
|
||||
const driverId = formData.get('variableStorageDriverId') as string;
|
||||
const variable = this.variable;
|
||||
|
||||
variable.name = name;
|
||||
variable.type = type;
|
||||
variable.value = value;
|
||||
variable.storageDriverId = isNullOrWhitespace(driverId) ? null : driverId;
|
||||
|
||||
this.variableChanged.emit(variable);
|
||||
await this.hide();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,15 +1,22 @@
|
|||
import {Component, h, Prop, State, Event, EventEmitter, Watch} from "@stencil/core";
|
||||
import {DeleteIcon, EditIcon} from "../../icons/tooling";
|
||||
import {StorageDriverDescriptor, Variable} from "../../../models";
|
||||
import {isNullOrWhitespace} from "../../../utils";
|
||||
import descriptorsStore from "../../../data/descriptors-store";
|
||||
import {ModalDialogInstance, ModalDialogService} from "../../shared/modal-dialog";
|
||||
import {Container} from "typedi";
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-variables-editor',
|
||||
shadow: false
|
||||
})
|
||||
export class VariablesEditor {
|
||||
private variableEditorDialog: HTMLElsaVariableEditorDialogElement;
|
||||
private readonly modalDialogService: ModalDialogService;
|
||||
private modalDialogInstance: ModalDialogInstance;
|
||||
|
||||
constructor() {
|
||||
this.modalDialogService = Container.get(ModalDialogService);
|
||||
}
|
||||
|
||||
@Prop() variables?: Array<Variable>;
|
||||
@Event() variablesChanged: EventEmitter<Array<Variable>>;
|
||||
@State() variablesState: Array<Variable> = [];
|
||||
|
|
@ -68,7 +75,6 @@ export class VariablesEditor {
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<elsa-variable-editor-dialog ref={el => this.variableEditorDialog = el} onVariableChanged={e => this.onVariableChanged(e)}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -94,14 +100,13 @@ export class VariablesEditor {
|
|||
|
||||
private onAddVariableClick = async () => {
|
||||
const newVariableName = this.generateNewVariableName();
|
||||
this.variableEditorDialog.variable = {name: newVariableName, type: 'Object', value: null};
|
||||
await this.variableEditorDialog.show();
|
||||
const variable = {name: newVariableName, type: 'Object', value: null};
|
||||
this.modalDialogInstance = this.modalDialogService.show(() => <elsa-variable-editor-dialog-content variable={variable} onVariableChanged={this.onVariableChanged} />)
|
||||
};
|
||||
|
||||
private onEditClick = async (e: Event, variable: Variable) => {
|
||||
e.preventDefault();
|
||||
this.variableEditorDialog.variable = variable;
|
||||
await this.variableEditorDialog.show();
|
||||
this.modalDialogInstance = this.modalDialogService.show(() => <elsa-variable-editor-dialog-content variable={variable} onVariableChanged={this.onVariableChanged}/>);
|
||||
};
|
||||
|
||||
private onDeleteClick = (e: Event, variable: Variable) => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
export * from './modal-dialog';
|
||||
export * from './modal-dialog-container';
|
||||
export * from './models';
|
||||
export * from './services';
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
import {Component, Host, h} from '@stencil/core';
|
||||
import state from './state';
|
||||
import {ModalDialogInstance} from "./models";
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-modal-dialog-container',
|
||||
shadow: false,
|
||||
})
|
||||
export class ModalDialogContainer {
|
||||
|
||||
private onInstanceHidden = (instance: ModalDialogInstance) => {
|
||||
let instances: Array<ModalDialogInstance> = state.instances;
|
||||
instances = instances.filter(x => x != instance);
|
||||
state.instances = instances;
|
||||
}
|
||||
|
||||
render() {
|
||||
const instances: Array<ModalDialogInstance> = state.instances;
|
||||
|
||||
return (
|
||||
<Host>
|
||||
{instances.map(instance => <elsa-modal-dialog content={instance.content} onHidden={() => this.onInstanceHidden(instance)}/>)}
|
||||
</Host>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -6,19 +6,17 @@ import {ActionDefinition, ActionInvokedArgs, ActionType} from '../../../models';
|
|||
tag: 'elsa-modal-dialog',
|
||||
shadow: false,
|
||||
})
|
||||
export class ElsaModalDialog {
|
||||
@Prop() public actions: Array<ActionDefinition> = [];
|
||||
@Prop() public size: string = 'sm:w-full sm:max-w-6xl';
|
||||
@Event() public shown: EventEmitter;
|
||||
@Event() public hidden: EventEmitter;
|
||||
@Event() public actionInvoked: EventEmitter<ActionInvokedArgs>;
|
||||
@State() private isVisible: boolean;
|
||||
export class ModalDialog {
|
||||
private overlay: HTMLElement
|
||||
private modal: HTMLElement
|
||||
|
||||
render() {
|
||||
return this.renderModal();
|
||||
}
|
||||
@Prop() actions: Array<ActionDefinition> = [];
|
||||
@Prop() size: string = 'sm:w-full sm:max-w-6xl';
|
||||
@Prop() content: () => any = () => <div/>;
|
||||
@Event() shown: EventEmitter;
|
||||
@Event() hidden: EventEmitter;
|
||||
@Event() actionInvoked: EventEmitter<ActionInvokedArgs>;
|
||||
@State() private isVisible: boolean = true;
|
||||
|
||||
@Method()
|
||||
async show(animate: boolean = true) {
|
||||
|
|
@ -65,7 +63,14 @@ export class ElsaModalDialog {
|
|||
}
|
||||
}
|
||||
|
||||
renderModal() {
|
||||
componentDidRender() {
|
||||
if(this.isVisible) {
|
||||
enter(this.overlay);
|
||||
enter(this.modal).then(this.shown.emit);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const actions = this.actions;
|
||||
|
||||
return (
|
||||
|
|
@ -92,7 +97,7 @@ export class ElsaModalDialog {
|
|||
class={`hidden inline-block sm:align-top bg-white rounded-lg text-left overflow-visible shadow-xl transform transition-all sm:my-8 sm:align-top ${this.size}`}
|
||||
role="dialog" aria-modal="true" aria-labelledby="modal-headline">
|
||||
<div class="modal-content">
|
||||
<slot/>
|
||||
{this.content()}
|
||||
</div>
|
||||
|
||||
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
import {ActionDefinition} from "../../../models";
|
||||
|
||||
export interface ModalDialogInstance {
|
||||
content: () => any;
|
||||
actions: Array<ActionDefinition>;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
import 'reflect-metadata';
|
||||
import {Service} from "typedi";
|
||||
import state from "./state";
|
||||
import {ModalDialogInstance} from "./models";
|
||||
|
||||
@Service()
|
||||
export class ModalDialogService {
|
||||
|
||||
show(content: () => any): ModalDialogInstance {
|
||||
const newInstance: ModalDialogInstance = {
|
||||
content: content,
|
||||
actions: []
|
||||
};
|
||||
|
||||
let instances: Array<ModalDialogInstance> = state.instances;
|
||||
instances = [...instances, newInstance];
|
||||
state.instances = instances;
|
||||
return newInstance;
|
||||
}
|
||||
|
||||
hide(instance: ModalDialogInstance) {
|
||||
let instances: Array<ModalDialogInstance> = state.instances;
|
||||
instances = instances.filter(x => x != instance);
|
||||
state.instances = instances;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import { createStore } from '@stencil/store';
|
||||
|
||||
const { state, onChange } = createStore({
|
||||
instances: []
|
||||
});
|
||||
|
||||
export default state;
|
||||
|
|
@ -11,11 +11,8 @@ import toolbarButtonMenuItemStore from "../../../data/toolbar-button-menu-item-s
|
|||
})
|
||||
export class WorkflowToolbarMenu {
|
||||
private readonly eventBus: EventBus;
|
||||
//private readonly model: ToolbarMenu;
|
||||
private menu: HTMLElement;
|
||||
private element: HTMLElement;
|
||||
private workflowDefinitionBrowser: HTMLElsaWorkflowDefinitionBrowserElement;
|
||||
private workflowInstanceBrowser: HTMLElsaWorkflowInstanceBrowserElement;
|
||||
|
||||
constructor() {
|
||||
this.eventBus = Container.get(EventBus);
|
||||
|
|
@ -60,7 +57,6 @@ export class WorkflowToolbarMenu {
|
|||
<a href="#" role="menuitem" tabindex="-1">Settings</a>
|
||||
</div>
|
||||
</div>
|
||||
<elsa-workflow-instance-browser ref={el => this.workflowInstanceBrowser = el}/>
|
||||
</Host>
|
||||
);
|
||||
}
|
||||
|
|
@ -73,10 +69,6 @@ export class WorkflowToolbarMenu {
|
|||
this.closeMenu();
|
||||
}
|
||||
|
||||
private onWorkflowInstancesClick = async () => {
|
||||
await this.workflowInstanceBrowser.show();
|
||||
};
|
||||
|
||||
private onMenuItemClick = async (e: MouseEvent, menuItem: ToolbarMenuItem) => {
|
||||
e.preventDefault();
|
||||
await menuItem.onClick();
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export class WorkflowToolbar {
|
|||
<nav class="bg-gray-800">
|
||||
<div class="mx-auto px-2 sm:px-6 lg:px-6">
|
||||
<div class="relative flex items-center justify-end h-16">
|
||||
<div class="absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0 z-20">
|
||||
<div class="absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0 z-30">
|
||||
{/* Notifications*/}
|
||||
<button
|
||||
onClick={e => this.onNotificationClick(e)}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
<elsa-studio server="https://localhost:5001/elsa/api" monaco-lib-path="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.31.1/min"></elsa-studio>
|
||||
</div>
|
||||
<elsa-custom-activities-manager></elsa-custom-activities-manager>
|
||||
<elsa-labels-manager></elsa-labels-manager>
|
||||
<!--<elsa-labels-manager></elsa-labels-manager>-->
|
||||
<elsa-notifications-manager></elsa-notifications-manager>
|
||||
<script type="module">
|
||||
// Integration demos.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Component, Event, EventEmitter, h, Host, Method, State } from '@stencil/core';
|
||||
import { Container } from 'typedi';
|
||||
import { Filter, FilterProps } from './filter';
|
||||
import {Component, Event, EventEmitter, h, Host, Method, State} from '@stencil/core';
|
||||
import {Container} from 'typedi';
|
||||
import {Filter, FilterProps} from './filter';
|
||||
import {ActivityDefinitionsApi} from "../services/api";
|
||||
import {ActivityDefinitionsOrderBy, ActivityDefinitionSummary} from "../models";
|
||||
import {DefaultActions, PagedList, VersionOptions} from "../../../models";
|
||||
|
|
@ -19,13 +19,12 @@ export class ActivityDefinitionBrowser {
|
|||
static readonly START_PAGE = 0;
|
||||
|
||||
private activityDefinitionsApi: ActivityDefinitionsApi;
|
||||
private modalDialog: HTMLElsaModalDialogElement;
|
||||
private selectAllCheckbox: HTMLInputElement;
|
||||
|
||||
@Event() public activityDefinitionSelected: EventEmitter<ActivityDefinitionSummary>;
|
||||
@Event() public newActivityDefinitionSelected: EventEmitter;
|
||||
@State() private activityDefinitions: PagedList<ActivityDefinitionSummary> = { items: [], totalCount: 0 };
|
||||
@State() private publishedActivityDefinitions: PagedList<ActivityDefinitionSummary> = { items: [], totalCount: 0 };
|
||||
@State() private activityDefinitions: PagedList<ActivityDefinitionSummary> = {items: [], totalCount: 0};
|
||||
@State() private publishedActivityDefinitions: PagedList<ActivityDefinitionSummary> = {items: [], totalCount: 0};
|
||||
@State() private selectedActivityDefinitionIds: Array<string> = [];
|
||||
@State() private currentPage: number = 0;
|
||||
@State() private currentPageSize: number = ActivityDefinitionBrowser.DEFAULT_PAGE_SIZE;
|
||||
|
|
@ -33,24 +32,14 @@ export class ActivityDefinitionBrowser {
|
|||
@State() private labels?: string[];
|
||||
@State() private selectAllChecked: boolean;
|
||||
|
||||
@Method()
|
||||
public async show() {
|
||||
await this.modalDialog.show();
|
||||
await this.loadActivityDefinitions();
|
||||
}
|
||||
|
||||
@Method()
|
||||
public async hide() {
|
||||
await this.modalDialog.hide();
|
||||
}
|
||||
|
||||
public async componentWillLoad() {
|
||||
|
||||
this.activityDefinitionsApi = Container.get(ActivityDefinitionsApi);
|
||||
await this.loadActivityDefinitions();
|
||||
}
|
||||
|
||||
private onNewDefinitionClick = async () => {
|
||||
this.newActivityDefinitionSelected.emit();
|
||||
await this.hide();
|
||||
};
|
||||
|
||||
private async onPublishClick(e: MouseEvent, ActivityDefinition: ActivityDefinitionSummary) {
|
||||
|
|
@ -74,34 +63,33 @@ export class ActivityDefinitionBrowser {
|
|||
}
|
||||
|
||||
private onDeleteManyClick = async () => {
|
||||
await this.activityDefinitionsApi.deleteMany({ definitionIds: this.selectedActivityDefinitionIds });
|
||||
await this.activityDefinitionsApi.deleteMany({definitionIds: this.selectedActivityDefinitionIds});
|
||||
await this.loadActivityDefinitions();
|
||||
};
|
||||
|
||||
private onPublishManyClick = async () => {
|
||||
await this.activityDefinitionsApi.publishMany({ definitionIds: this.selectedActivityDefinitionIds });
|
||||
await this.activityDefinitionsApi.publishMany({definitionIds: this.selectedActivityDefinitionIds});
|
||||
await this.loadActivityDefinitions();
|
||||
};
|
||||
|
||||
private onUnpublishManyClick = async () => {
|
||||
await this.activityDefinitionsApi.unpublishMany({ definitionIds: this.selectedActivityDefinitionIds });
|
||||
await this.activityDefinitionsApi.unpublishMany({definitionIds: this.selectedActivityDefinitionIds});
|
||||
await this.loadActivityDefinitions();
|
||||
};
|
||||
|
||||
private onActivityDefinitionClick = async (e: MouseEvent, ActivityDefinition: ActivityDefinitionSummary) => {
|
||||
e.preventDefault();
|
||||
this.activityDefinitionSelected.emit(ActivityDefinition);
|
||||
await this.hide();
|
||||
};
|
||||
|
||||
private async loadActivityDefinitions() {
|
||||
const publishedVersionOptions: VersionOptions = { isPublished: true };
|
||||
const publishedVersionOptions: VersionOptions = {isPublished: true};
|
||||
const api = this.activityDefinitionsApi;
|
||||
|
||||
const latestActivityDefinitions = await api.list({
|
||||
page: this.currentPage,
|
||||
pageSize: this.currentPageSize,
|
||||
versionOptions: { isLatest: true },
|
||||
versionOptions: {isLatest: true},
|
||||
orderBy: this.orderBy,
|
||||
label: this.labels,
|
||||
});
|
||||
|
|
@ -143,91 +131,87 @@ export class ActivityDefinitionBrowser {
|
|||
|
||||
return (
|
||||
<Host class="block">
|
||||
<elsa-modal-dialog ref={el => (this.modalDialog = el)} actions={actions}>
|
||||
<div class="pt-4">
|
||||
<h2 class="text-lg font-medium ml-4 mb-2">Activity Definitions</h2>
|
||||
<Filter {...filterProps} />
|
||||
<div class="align-middle inline-block min-w-full border-b border-gray-200">
|
||||
<table class="default-table">
|
||||
<thead>
|
||||
<div class="pt-4">
|
||||
<h2 class="text-lg font-medium ml-4 mb-2">Activity Definitions</h2>
|
||||
<Filter {...filterProps} />
|
||||
<div class="align-middle inline-block min-w-full border-b border-gray-200">
|
||||
<table class="default-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<input
|
||||
type="checkbox"
|
||||
value="true"
|
||||
checked={this.getSelectAllState()}
|
||||
onChange={e => this.onSelectAllCheckChange(e)}
|
||||
ref={el => (this.selectAllCheckbox = el)}
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
<span class="lg:pl-2">Name</span>
|
||||
</th>
|
||||
<th class="optional align-right">Latest Version</th>
|
||||
<th class="optional align-right">Published Version</th>
|
||||
<th/>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{ActivityDefinitions.items.map(definition => {
|
||||
const latestVersionNumber = definition.version;
|
||||
const {isPublished} = definition;
|
||||
const publishedVersion: ActivityDefinitionSummary = isPublished
|
||||
? definition
|
||||
: publishedActivityDefinitions.find(x => x.definitionId == definition.definitionId);
|
||||
const publishedVersionNumber = !!publishedVersion ? publishedVersion.version : '-';
|
||||
|
||||
const isSelected = this.selectedActivityDefinitionIds.findIndex(x => x === definition.definitionId) >= 0;
|
||||
let displayName = definition.displayName || definition.typeName;
|
||||
|
||||
if (!displayName || displayName.trim().length == 0) displayName = 'Untitled';
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<th>
|
||||
<td>
|
||||
<input
|
||||
type="checkbox"
|
||||
value="true"
|
||||
checked={this.getSelectAllState()}
|
||||
onChange={e => this.onSelectAllCheckChange(e)}
|
||||
ref={el => (this.selectAllCheckbox = el)}
|
||||
value={definition.definitionId}
|
||||
checked={isSelected}
|
||||
onChange={e => this.onActivityDefinitionCheckChange(e, definition)}
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
<span class="lg:pl-2">Name</span>
|
||||
</th>
|
||||
<th class="optional align-right">Latest Version</th>
|
||||
<th class="optional align-right">Published Version</th>
|
||||
<th />
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex items-center space-x-3 lg:pl-2">
|
||||
<a onClick={e => this.onActivityDefinitionClick(e, definition)} href="#" class="truncate hover:text-gray-600">
|
||||
<span>{displayName}</span>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="optional align-right">{latestVersionNumber}</td>
|
||||
<td class="optional align-right">{publishedVersionNumber}</td>
|
||||
<td class="pr-6">
|
||||
<elsa-context-menu
|
||||
menuItems={[
|
||||
{text: 'Edit', clickHandler: e => this.onActivityDefinitionClick(e, definition), icon: <EditIcon/>},
|
||||
isPublished
|
||||
? {text: 'Unpublish', clickHandler: e => this.onUnPublishClick(e, definition), icon: <UnPublishIcon/>}
|
||||
: {
|
||||
text: 'Publish',
|
||||
clickHandler: e => this.onPublishClick(e, definition),
|
||||
icon: <PublishIcon/>,
|
||||
},
|
||||
{text: 'Delete', clickHandler: e => this.onDeleteClick(e, definition), icon: <DeleteIcon/>},
|
||||
]}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{ActivityDefinitions.items.map(definition => {
|
||||
const latestVersionNumber = definition.version;
|
||||
const { isPublished } = definition;
|
||||
const publishedVersion: ActivityDefinitionSummary = isPublished
|
||||
? definition
|
||||
: publishedActivityDefinitions.find(x => x.definitionId == definition.definitionId);
|
||||
const publishedVersionNumber = !!publishedVersion ? publishedVersion.version : '-';
|
||||
|
||||
const isSelected = this.selectedActivityDefinitionIds.findIndex(x => x === definition.definitionId) >= 0;
|
||||
let displayName = definition.displayName || definition.typeName;
|
||||
|
||||
if (!displayName || displayName.trim().length == 0) displayName = 'Untitled';
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<input
|
||||
type="checkbox"
|
||||
value={definition.definitionId}
|
||||
checked={isSelected}
|
||||
onChange={e => this.onActivityDefinitionCheckChange(e, definition)}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex items-center space-x-3 lg:pl-2">
|
||||
<a onClick={e => this.onActivityDefinitionClick(e, definition)} href="#" class="truncate hover:text-gray-600">
|
||||
<span>{displayName}</span>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="optional align-right">{latestVersionNumber}</td>
|
||||
<td class="optional align-right">{publishedVersionNumber}</td>
|
||||
<td class="pr-6">
|
||||
<elsa-context-menu
|
||||
menuItems={[
|
||||
{ text: 'Edit', clickHandler: e => this.onActivityDefinitionClick(e, definition), icon: <EditIcon /> },
|
||||
isPublished
|
||||
? { text: 'Unpublish', clickHandler: e => this.onUnPublishClick(e, definition), icon: <UnPublishIcon /> }
|
||||
: {
|
||||
text: 'Publish',
|
||||
clickHandler: e => this.onPublishClick(e, definition),
|
||||
icon: <PublishIcon />,
|
||||
},
|
||||
{ text: 'Delete', clickHandler: e => this.onDeleteClick(e, definition), icon: <DeleteIcon /> },
|
||||
]}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
<elsa-pager page={this.currentPage} pageSize={this.currentPageSize} totalCount={totalCount} onPaginated={this.onPaginated} />
|
||||
</div>
|
||||
|
||||
{/*<confirm-dialog ref={el => this.confirmDialog = el} culture={this.culture}/>*/}
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
<elsa-pager page={this.currentPage} pageSize={this.currentPageSize} totalCount={totalCount} onPaginated={this.onPaginated}/>
|
||||
</div>
|
||||
</elsa-modal-dialog>
|
||||
</div>
|
||||
</Host>
|
||||
);
|
||||
}
|
||||
|
|
@ -259,7 +243,7 @@ export class ActivityDefinitionBrowser {
|
|||
};
|
||||
|
||||
private getSelectAllState = () => {
|
||||
const { items } = this.activityDefinitions;
|
||||
const {items} = this.activityDefinitions;
|
||||
const selectedWorkflowInstanceIds = this.selectedActivityDefinitionIds;
|
||||
return items.findIndex(item => !selectedWorkflowInstanceIds.includes(item.definitionId)) < 0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import {PublishClickedArgs} from "./components/publish-button";
|
|||
import {ActivityDefinitionManager} from "./services/manager";
|
||||
import {ActivityDefinition, ActivityDefinitionSummary, ActivityDefinitionUpdatedArgs} from "./models";
|
||||
import {ActivityDefinitionsApi} from "./services/api";
|
||||
import {ModalDialogInstance, ModalDialogService} from "../../components/shared/modal-dialog";
|
||||
|
||||
const FlowchartTypeName = 'Elsa.Flowchart';
|
||||
|
||||
|
|
@ -26,16 +27,16 @@ export class ActivityDefinitionsPlugin implements Plugin {
|
|||
private readonly activityDefinitionManager: ActivityDefinitionManager;
|
||||
private readonly activityDescriptorManager: ActivityDescriptorManager;
|
||||
private readonly api: ActivityDefinitionsApi;
|
||||
private readonly modalDialogService: ModalDialogService;
|
||||
private activityDefinitionEditorElement: HTMLElsaActivityDefinitionEditorElement;
|
||||
private activityDefinitionBrowserElement: HTMLElsaActivityDefinitionBrowserElement;
|
||||
|
||||
|
||||
private activityDefinitionBrowserInstance: ModalDialogInstance;
|
||||
|
||||
constructor() {
|
||||
this.eventBus = Container.get(EventBus);
|
||||
this.activityDefinitionManager = Container.get(ActivityDefinitionManager);
|
||||
this.api = Container.get(ActivityDefinitionsApi);
|
||||
this.activityDescriptorManager = Container.get(ActivityDescriptorManager);
|
||||
this.modalDialogService = Container.get(ModalDialogService);
|
||||
|
||||
const newActivityDefinitionItem: MenuItem = {
|
||||
text: 'Activity Definition',
|
||||
|
|
@ -50,10 +51,6 @@ export class ActivityDefinitionsPlugin implements Plugin {
|
|||
|
||||
newButtonItemStore.items = [...newButtonItemStore.items, newActivityDefinitionItem];
|
||||
toolbarButtonMenuItemStore.items = [...toolbarButtonMenuItemStore.items, activityDefinitionBrowserItem];
|
||||
|
||||
studioComponentStore.modalComponents = [
|
||||
...studioComponentStore.modalComponents,
|
||||
() => <elsa-activity-definition-browser ref={el => this.activityDefinitionBrowserElement = el} onActivityDefinitionSelected={this.onActivityDefinitionSelected} onNewActivityDefinitionSelected={this.onNewActivityDefinitionClick}/>];
|
||||
}
|
||||
|
||||
async initialize(): Promise<void> {
|
||||
|
|
@ -105,11 +102,10 @@ export class ActivityDefinitionsPlugin implements Plugin {
|
|||
ref={el => this.activityDefinitionEditorElement = el}/>;
|
||||
};
|
||||
|
||||
private refreshActivityDescriptors = () => {
|
||||
|
||||
}
|
||||
|
||||
private onNewActivityDefinitionClick = async () => await this.newActivityDefinition();
|
||||
private onNewActivityDefinitionClick = async () => {
|
||||
await this.newActivityDefinition();
|
||||
this.modalDialogService.hide(this.activityDefinitionBrowserInstance);
|
||||
};
|
||||
|
||||
private onActivityDefinitionUpdated = async (e: CustomEvent<ActivityDefinitionUpdatedArgs>) => {
|
||||
const activityDefinition = e.detail.activityDefinition;
|
||||
|
|
@ -117,13 +113,15 @@ export class ActivityDefinitionsPlugin implements Plugin {
|
|||
}
|
||||
|
||||
private onBrowseActivityDefinitions = async () => {
|
||||
await this.activityDefinitionBrowserElement.show();
|
||||
this.activityDefinitionBrowserInstance = this.modalDialogService.show(() =>
|
||||
<elsa-activity-definition-browser onActivityDefinitionSelected={this.onActivityDefinitionSelected} onNewActivityDefinitionSelected={this.onNewActivityDefinitionClick}/>)
|
||||
}
|
||||
|
||||
private onActivityDefinitionSelected = async (e: CustomEvent<ActivityDefinitionSummary>) => {
|
||||
const definitionId = e.detail.definitionId;
|
||||
const workflowDefinition = await this.api.get({definitionId});
|
||||
this.showActivityDefinitionEditor(workflowDefinition);
|
||||
this.modalDialogService.hide(this.activityDefinitionBrowserInstance);
|
||||
}
|
||||
|
||||
private onPublishClicked = async (e: CustomEvent<PublishClickedArgs>) => {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ export class LabelsManager {
|
|||
private readonly workflowDefinitionLabelsApi: WorkflowDefinitionLabelsApi;
|
||||
private readonly saveLabelsDebounced: () => void;
|
||||
private workflowEditor: HTMLElsaWorkflowDefinitionEditorElement;
|
||||
private modalDialog: HTMLElsaModalDialogElement;
|
||||
private elsaClient: ElsaClient;
|
||||
private definitionVersionId: string;
|
||||
private assignedLabelIds: Array<string> = [];
|
||||
|
|
@ -34,7 +33,7 @@ export class LabelsManager {
|
|||
this.labelsApi = Container.get(LabelsApi);
|
||||
this.workflowDefinitionLabelsApi = Container.get(WorkflowDefinitionLabelsApi);
|
||||
this.eventBus.on(WorkflowEditorEventTypes.WorkflowEditor.Ready, this.onWorkflowEditorReady)
|
||||
this.eventBus.on(ToolbarEventTypes.Displaying, this.onToolbarDisplaying);
|
||||
//this.eventBus.on(ToolbarEventTypes.Displaying, this.onToolbarDisplaying);
|
||||
this.eventBus.on(WorkflowPropertiesEditorEventTypes.Displaying, this.onWorkflowPropertiesEditorDisplaying);
|
||||
this.eventBus.on(WorkflowEditorEventTypes.WorkflowDefinition.Imported, this.onWorkflowDefinitionImported);
|
||||
this.saveLabelsDebounced = debounce(this.saveWorkflowLabels, 1000);
|
||||
|
|
@ -42,16 +41,6 @@ export class LabelsManager {
|
|||
|
||||
@State() private createMode: boolean = false;
|
||||
|
||||
@Method()
|
||||
async show() {
|
||||
await this.modalDialog.show();
|
||||
}
|
||||
|
||||
@Method()
|
||||
async hide() {
|
||||
await this.modalDialog.hide();
|
||||
}
|
||||
|
||||
async componentWillLoad() {
|
||||
this.elsaClient = await Container.get(ElsaApiClientProvider).getElsaClient();
|
||||
labelStore.labels = await this.labelsApi.list();
|
||||
|
|
@ -76,13 +65,13 @@ export class LabelsManager {
|
|||
this.workflowEditor = e.workflowEditor;
|
||||
}
|
||||
|
||||
private onToolbarDisplaying = (e: ToolbarDisplayingArgs) => {
|
||||
e.menu.menuItems.push({
|
||||
text: 'Labels',
|
||||
onClick: this.onLabelsMenuItemClicked,
|
||||
order: 3
|
||||
});
|
||||
}
|
||||
// private onToolbarDisplaying = (e: ToolbarDisplayingArgs) => {
|
||||
// e.menu.menuItems.push({
|
||||
// text: 'Labels',
|
||||
// onClick: this.onLabelsMenuItemClicked,
|
||||
// order: 3
|
||||
// });
|
||||
// }
|
||||
|
||||
private onWorkflowPropertiesEditorDisplaying = (e: WorkflowPropertiesEditorDisplayingArgs) => {
|
||||
const propertiesTabModel = e.model.tabModels.find(x => x.name == 'properties') as PropertiesTabModel;
|
||||
|
|
@ -113,8 +102,6 @@ export class LabelsManager {
|
|||
this.definitionVersionId = workflowDefinition.id;
|
||||
}
|
||||
|
||||
private onLabelsMenuItemClicked = async () => await this.show();
|
||||
|
||||
private onSelectedLabelsChanged = async (e: CustomEvent<Array<string>>) => {
|
||||
this.assignedLabelIds = e.detail;
|
||||
await this.saveLabelsDebounced();
|
||||
|
|
@ -129,41 +116,39 @@ export class LabelsManager {
|
|||
return (
|
||||
<Host class="block">
|
||||
|
||||
<elsa-modal-dialog ref={el => this.modalDialog = el} actions={actions}>
|
||||
<div class="pt-4">
|
||||
<h2 class="text-lg font-medium ml-4 mb-2">Labels</h2>
|
||||
<div class="pt-4">
|
||||
<h2 class="text-lg font-medium ml-4 mb-2">Labels</h2>
|
||||
|
||||
<div class="pl-4 pr-6">
|
||||
<div class="flex justify-end">
|
||||
<div class="flex-shrink">
|
||||
<button type="button" class="btn" onClick={() => this.createMode = !this.createMode}>New label</button>
|
||||
</div>
|
||||
<div class="pl-4 pr-6">
|
||||
<div class="flex justify-end">
|
||||
<div class="flex-shrink">
|
||||
<button type="button" class="btn" onClick={() => this.createMode = !this.createMode}>New label</button>
|
||||
</div>
|
||||
|
||||
{createMode ? <elsa-label-creator onCreateLabelClicked={e => this.onCreateLabelClicked(e)}/> : undefined}
|
||||
|
||||
<div class="mt-5">
|
||||
<div class="flex">
|
||||
<div>
|
||||
<p class="max-w-2xl text-sm text-gray-500">{labels.length == 1 ? '1 label' : `${labels.length} labels`}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 border-t border-gray-200">
|
||||
<div class="divide-y divide-gray-200">
|
||||
{labels.map(label => <div class="border-top last:border-bottom border-solid border-gray-200">
|
||||
<elsa-label-editor key={label.id}
|
||||
label={label}
|
||||
onLabelUpdated={e => this.onLabelUpdated(e)}
|
||||
onLabelDeleted={e => this.onLabelDeleted(e)}
|
||||
/>
|
||||
</div>)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{createMode ? <elsa-label-creator onCreateLabelClicked={e => this.onCreateLabelClicked(e)}/> : undefined}
|
||||
|
||||
<div class="mt-5">
|
||||
<div class="flex">
|
||||
<div>
|
||||
<p class="max-w-2xl text-sm text-gray-500">{labels.length == 1 ? '1 label' : `${labels.length} labels`}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 border-t border-gray-200">
|
||||
<div class="divide-y divide-gray-200">
|
||||
{labels.map(label => <div class="border-top last:border-bottom border-solid border-gray-200">
|
||||
<elsa-label-editor key={label.id}
|
||||
label={label}
|
||||
onLabelUpdated={e => this.onLabelUpdated(e)}
|
||||
onLabelDeleted={e => this.onLabelDeleted(e)}
|
||||
/>
|
||||
</div>)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</elsa-modal-dialog>
|
||||
</div>
|
||||
</Host>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { Component, Event, EventEmitter, h, Host, Method, Prop, State, Watch } from '@stencil/core';
|
||||
import { DefaultActions, OrderBy, PagedList, VersionOptions} from '../../../models';
|
||||
import { Container } from 'typedi';
|
||||
import { ElsaApiClientProvider, ElsaClient } from '../../../services';
|
||||
import { DeleteIcon, EditIcon, PublishIcon, UnPublishIcon } from '../../../components/icons/tooling';
|
||||
import { Filter, FilterProps } from './filter';
|
||||
import { PagerData } from '../../../components/shared/pager/pager';
|
||||
import { updateSelectedWorkflowDefinitions } from '../services/utils';
|
||||
import {Component, Event, EventEmitter, h, Host, Method, Prop, State, Watch} from '@stencil/core';
|
||||
import {DefaultActions, OrderBy, PagedList, VersionOptions} from '../../../models';
|
||||
import {Container} from 'typedi';
|
||||
import {ElsaApiClientProvider, ElsaClient} from '../../../services';
|
||||
import {DeleteIcon, EditIcon, PublishIcon, UnPublishIcon} from '../../../components/icons/tooling';
|
||||
import {Filter, FilterProps} from './filter';
|
||||
import {PagerData} from '../../../components/shared/pager/pager';
|
||||
import {updateSelectedWorkflowDefinitions} from '../services/utils';
|
||||
import {WorkflowDefinitionSummary} from "../models/entities";
|
||||
import {WorkflowDefinitionsApi, WorkflowDefinitionsOrderBy} from "../services/api";
|
||||
|
||||
|
|
@ -20,7 +20,6 @@ export class WorkflowDefinitionBrowser {
|
|||
static readonly START_PAGE = 0;
|
||||
|
||||
private readonly api: WorkflowDefinitionsApi;
|
||||
private modalDialog: HTMLElsaModalDialogElement;
|
||||
private selectAllCheckbox: HTMLInputElement;
|
||||
|
||||
constructor() {
|
||||
|
|
@ -29,8 +28,8 @@ export class WorkflowDefinitionBrowser {
|
|||
|
||||
@Event() workflowDefinitionSelected: EventEmitter<WorkflowDefinitionSummary>;
|
||||
@Event() public newWorkflowDefinitionSelected: EventEmitter;
|
||||
@State() private workflowDefinitions: PagedList<WorkflowDefinitionSummary> = { items: [], totalCount: 0 };
|
||||
@State() private publishedWorkflowDefinitions: PagedList<WorkflowDefinitionSummary> = { items: [], totalCount: 0 };
|
||||
@State() private workflowDefinitions: PagedList<WorkflowDefinitionSummary> = {items: [], totalCount: 0};
|
||||
@State() private publishedWorkflowDefinitions: PagedList<WorkflowDefinitionSummary> = {items: [], totalCount: 0};
|
||||
@State() private selectedWorkflowDefinitionIds: Array<string> = [];
|
||||
@State() private currentPage: number = 0;
|
||||
@State() private currentPageSize: number = WorkflowDefinitionBrowser.DEFAULT_PAGE_SIZE;
|
||||
|
|
@ -38,20 +37,12 @@ export class WorkflowDefinitionBrowser {
|
|||
@State() private labels?: string[];
|
||||
@State() private selectAllChecked: boolean;
|
||||
|
||||
@Method()
|
||||
async show() {
|
||||
await this.modalDialog.show();
|
||||
async componentWillLoad() {
|
||||
await this.loadWorkflowDefinitions();
|
||||
}
|
||||
|
||||
@Method()
|
||||
async hide() {
|
||||
await this.modalDialog.hide();
|
||||
}
|
||||
|
||||
private onNewDefinitionClick = async () => {
|
||||
this.newWorkflowDefinitionSelected.emit();
|
||||
await this.hide();
|
||||
};
|
||||
|
||||
private async onPublishClick(e: MouseEvent, workflowDefinition: WorkflowDefinitionSummary) {
|
||||
|
|
@ -75,29 +66,28 @@ export class WorkflowDefinitionBrowser {
|
|||
}
|
||||
|
||||
private onDeleteManyClick = async () => {
|
||||
await this.api.deleteMany({ definitionIds: this.selectedWorkflowDefinitionIds });
|
||||
await this.api.deleteMany({definitionIds: this.selectedWorkflowDefinitionIds});
|
||||
await this.loadWorkflowDefinitions();
|
||||
};
|
||||
|
||||
private onPublishManyClick = async () => {
|
||||
await this.api.publishMany({ definitionIds: this.selectedWorkflowDefinitionIds });
|
||||
await this.api.publishMany({definitionIds: this.selectedWorkflowDefinitionIds});
|
||||
await this.loadWorkflowDefinitions();
|
||||
};
|
||||
|
||||
private onUnpublishManyClick = async () => {
|
||||
await this.api.unpublishMany({ definitionIds: this.selectedWorkflowDefinitionIds });
|
||||
await this.api.unpublishMany({definitionIds: this.selectedWorkflowDefinitionIds});
|
||||
await this.loadWorkflowDefinitions();
|
||||
};
|
||||
|
||||
private onWorkflowDefinitionClick = async (e: MouseEvent, workflowDefinition: WorkflowDefinitionSummary) => {
|
||||
e.preventDefault();
|
||||
this.workflowDefinitionSelected.emit(workflowDefinition);
|
||||
await this.hide();
|
||||
};
|
||||
|
||||
private async loadWorkflowDefinitions() {
|
||||
const latestVersionOptions: VersionOptions = { isLatest: true };
|
||||
const publishedVersionOptions: VersionOptions = { isPublished: true };
|
||||
const latestVersionOptions: VersionOptions = {isLatest: true};
|
||||
const publishedVersionOptions: VersionOptions = {isPublished: true};
|
||||
|
||||
// TODO: Load only json-based workflow definitions for now.
|
||||
// Later, also allow CLR-based workflows to be "edited" (publish / unpublish / position activities / set variables, etc.)
|
||||
|
|
@ -107,7 +97,7 @@ export class WorkflowDefinitionBrowser {
|
|||
materializerName,
|
||||
page: this.currentPage,
|
||||
pageSize: this.currentPageSize,
|
||||
versionOptions: { isLatest: true },
|
||||
versionOptions: {isLatest: true},
|
||||
orderBy: this.orderBy,
|
||||
label: this.labels,
|
||||
});
|
||||
|
|
@ -149,7 +139,7 @@ export class WorkflowDefinitionBrowser {
|
|||
};
|
||||
|
||||
private getSelectAllState = () => {
|
||||
const { items } = this.workflowDefinitions;
|
||||
const {items} = this.workflowDefinitions;
|
||||
const selectedWorkflowInstanceIds = this.selectedWorkflowDefinitionIds;
|
||||
return items.findIndex(item => !selectedWorkflowInstanceIds.includes(item.definitionId)) < 0;
|
||||
};
|
||||
|
|
@ -208,100 +198,96 @@ export class WorkflowDefinitionBrowser {
|
|||
|
||||
return (
|
||||
<Host class="block">
|
||||
<elsa-modal-dialog ref={el => (this.modalDialog = el)} actions={actions}>
|
||||
<div class="pt-4">
|
||||
<h2 class="text-lg font-medium ml-4 mb-2">Workflow Definitions</h2>
|
||||
<Filter {...filterProps} />
|
||||
<div class="align-middle inline-block min-w-full border-b border-gray-200">
|
||||
<table class="default-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<input
|
||||
type="checkbox"
|
||||
value="true"
|
||||
checked={this.getSelectAllState()}
|
||||
onChange={e => this.onSelectAllCheckChange(e)}
|
||||
ref={el => (this.selectAllCheckbox = el)}
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
<span class="lg:pl-2">Name</span>
|
||||
</th>
|
||||
<th>Instances</th>
|
||||
<th class="optional align-right">Latest Version</th>
|
||||
<th class="optional align-right">Published Version</th>
|
||||
<th />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{workflowDefinitions.items.map(workflowDefinition => {
|
||||
const latestVersionNumber = workflowDefinition.version;
|
||||
const { isPublished } = workflowDefinition;
|
||||
const publishedVersion: WorkflowDefinitionSummary = isPublished
|
||||
? workflowDefinition
|
||||
: publishedWorkflowDefinitions.find(x => x.definitionId == workflowDefinition.definitionId);
|
||||
const publishedVersionNumber = !!publishedVersion ? publishedVersion.version : '-';
|
||||
<div class="pt-4">
|
||||
<h2 class="text-lg font-medium ml-4 mb-2">Workflow Definitions</h2>
|
||||
<Filter {...filterProps} />
|
||||
<div class="align-middle inline-block min-w-full border-b border-gray-200">
|
||||
<table class="default-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<input
|
||||
type="checkbox"
|
||||
value="true"
|
||||
checked={this.getSelectAllState()}
|
||||
onChange={e => this.onSelectAllCheckChange(e)}
|
||||
ref={el => (this.selectAllCheckbox = el)}
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
<span class="lg:pl-2">Name</span>
|
||||
</th>
|
||||
<th>Instances</th>
|
||||
<th class="optional align-right">Latest Version</th>
|
||||
<th class="optional align-right">Published Version</th>
|
||||
<th/>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{workflowDefinitions.items.map(workflowDefinition => {
|
||||
const latestVersionNumber = workflowDefinition.version;
|
||||
const {isPublished} = workflowDefinition;
|
||||
const publishedVersion: WorkflowDefinitionSummary = isPublished
|
||||
? workflowDefinition
|
||||
: publishedWorkflowDefinitions.find(x => x.definitionId == workflowDefinition.definitionId);
|
||||
const publishedVersionNumber = !!publishedVersion ? publishedVersion.version : '-';
|
||||
|
||||
const isSelected = this.selectedWorkflowDefinitionIds.findIndex(x => x === workflowDefinition.definitionId) >= 0;
|
||||
let workflowDisplayName = workflowDefinition.name;
|
||||
const isSelected = this.selectedWorkflowDefinitionIds.findIndex(x => x === workflowDefinition.definitionId) >= 0;
|
||||
let workflowDisplayName = workflowDefinition.name;
|
||||
|
||||
if (!workflowDisplayName || workflowDisplayName.trim().length == 0) workflowDisplayName = 'Untitled';
|
||||
if (!workflowDisplayName || workflowDisplayName.trim().length == 0) workflowDisplayName = 'Untitled';
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<input
|
||||
type="checkbox"
|
||||
value={workflowDefinition.definitionId}
|
||||
checked={isSelected}
|
||||
onChange={e => this.onWorkflowDefinitionCheckChange(e, workflowDefinition)}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex items-center space-x-3 lg:pl-2">
|
||||
<a onClick={e => this.onWorkflowDefinitionClick(e, workflowDefinition)} href="#" class="truncate hover:text-gray-600">
|
||||
<span>{workflowDisplayName}</span>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<input
|
||||
type="checkbox"
|
||||
value={workflowDefinition.definitionId}
|
||||
checked={isSelected}
|
||||
onChange={e => this.onWorkflowDefinitionCheckChange(e, workflowDefinition)}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex items-center space-x-3 lg:pl-2">
|
||||
<a onClick={e => this.onWorkflowDefinitionClick(e, workflowDefinition)} href="#" class="truncate hover:text-gray-600">
|
||||
<span>{workflowDisplayName}</span>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<div class="flex items-center space-x-3 lg:pl-2">
|
||||
<a href="#" class="truncate hover:text-gray-600">
|
||||
Instances
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex items-center space-x-3 lg:pl-2">
|
||||
<a href="#" class="truncate hover:text-gray-600">
|
||||
Instances
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="optional align-right">{latestVersionNumber}</td>
|
||||
<td class="optional align-right">{publishedVersionNumber}</td>
|
||||
<td class="pr-6">
|
||||
<elsa-context-menu
|
||||
menuItems={[
|
||||
{ text: 'Edit', clickHandler: e => this.onWorkflowDefinitionClick(e, workflowDefinition), icon: <EditIcon /> },
|
||||
isPublished
|
||||
? { text: 'Unpublish', clickHandler: e => this.onUnPublishClick(e, workflowDefinition), icon: <UnPublishIcon /> }
|
||||
: {
|
||||
text: 'Publish',
|
||||
clickHandler: e => this.onPublishClick(e, workflowDefinition),
|
||||
icon: <PublishIcon />,
|
||||
},
|
||||
{ text: 'Delete', clickHandler: e => this.onDeleteClick(e, workflowDefinition), icon: <DeleteIcon /> },
|
||||
]}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
<elsa-pager page={this.currentPage} pageSize={this.currentPageSize} totalCount={totalCount} onPaginated={this.onPaginated} />
|
||||
</div>
|
||||
|
||||
{/*<confirm-dialog ref={el => this.confirmDialog = el} culture={this.culture}/>*/}
|
||||
<td class="optional align-right">{latestVersionNumber}</td>
|
||||
<td class="optional align-right">{publishedVersionNumber}</td>
|
||||
<td class="pr-6">
|
||||
<elsa-context-menu
|
||||
menuItems={[
|
||||
{text: 'Edit', clickHandler: e => this.onWorkflowDefinitionClick(e, workflowDefinition), icon: <EditIcon/>},
|
||||
isPublished
|
||||
? {text: 'Unpublish', clickHandler: e => this.onUnPublishClick(e, workflowDefinition), icon: <UnPublishIcon/>}
|
||||
: {
|
||||
text: 'Publish',
|
||||
clickHandler: e => this.onPublishClick(e, workflowDefinition),
|
||||
icon: <PublishIcon/>,
|
||||
},
|
||||
{text: 'Delete', clickHandler: e => this.onDeleteClick(e, workflowDefinition), icon: <DeleteIcon/>},
|
||||
]}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
<elsa-pager page={this.currentPage} pageSize={this.currentPageSize} totalCount={totalCount} onPaginated={this.onPaginated}/>
|
||||
</div>
|
||||
</elsa-modal-dialog>
|
||||
</div>
|
||||
</Host>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,8 +49,7 @@ export class WorkflowDefinitionPropertiesEditor {
|
|||
|
||||
public render() {
|
||||
const workflowDefinition = this.workflowDefinition;
|
||||
const workflowDefinitionName = workflowDefinition?.name ?? 'Untitled';
|
||||
const title = workflowDefinitionName;
|
||||
const title = workflowDefinition?.name ?? 'Untitled';
|
||||
const subTitle = 'Workflow Definition'
|
||||
const tabs = this.model.tabModels.map(x => x.tab);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import {WorkflowDefinition, WorkflowDefinitionSummary} from "./models/entities";
|
|||
import {WorkflowDefinitionUpdatedArgs} from "./models/ui";
|
||||
import {PublishClickedArgs} from "./components/publish-button";
|
||||
import {WorkflowDefinitionsApi} from "./services/api";
|
||||
import {ModalDialogInstance, ModalDialogService} from "../../components/shared/modal-dialog";
|
||||
|
||||
const FlowchartTypeName = 'Elsa.Flowchart';
|
||||
|
||||
|
|
@ -25,14 +26,16 @@ const FlowchartTypeName = 'Elsa.Flowchart';
|
|||
export class WorkflowDefinitionsPlugin implements Plugin {
|
||||
private readonly eventBus: EventBus;
|
||||
private readonly workflowDefinitionManager: WorkflowDefinitionManager;
|
||||
private readonly modalDialogService: ModalDialogService;
|
||||
private api: WorkflowDefinitionsApi;
|
||||
private workflowDefinitionEditorElement: HTMLElsaWorkflowDefinitionEditorElement;
|
||||
private workflowDefinitionBrowserElement: HTMLElsaWorkflowDefinitionBrowserElement;
|
||||
private workflowDefinitionBrowserInstance: ModalDialogInstance;
|
||||
|
||||
constructor() {
|
||||
this.eventBus = Container.get(EventBus);
|
||||
this.api = Container.get(WorkflowDefinitionsApi);
|
||||
this.workflowDefinitionManager = Container.get(WorkflowDefinitionManager);
|
||||
this.modalDialogService = Container.get(ModalDialogService);
|
||||
|
||||
const newWorkflowDefinitionItem: MenuItem = {
|
||||
text: 'Workflow Definition',
|
||||
|
|
@ -47,10 +50,6 @@ export class WorkflowDefinitionsPlugin implements Plugin {
|
|||
|
||||
newButtonItemStore.items = [...newButtonItemStore.items, newWorkflowDefinitionItem];
|
||||
toolbarButtonMenuItemStore.items = [...toolbarButtonMenuItemStore.items, workflowDefinitionBrowserItem];
|
||||
|
||||
studioComponentStore.modalComponents = [
|
||||
...studioComponentStore.modalComponents,
|
||||
() => <elsa-workflow-definition-browser ref={el => this.workflowDefinitionBrowserElement = el} onWorkflowDefinitionSelected={this.onWorkflowDefinitionSelected} onNewWorkflowDefinitionSelected={this.onNewWorkflowDefinitionClick}/>];
|
||||
}
|
||||
|
||||
async initialize(): Promise<void> {
|
||||
|
|
@ -100,7 +99,10 @@ export class WorkflowDefinitionsPlugin implements Plugin {
|
|||
studioComponentStore.activeComponentFactory = () => <elsa-workflow-definition-editor workflowDefinition={workflowDefinition} onWorkflowUpdated={this.onWorkflowUpdated} ref={el => this.workflowDefinitionEditorElement = el}/>;
|
||||
};
|
||||
|
||||
private onNewWorkflowDefinitionClick = async () => await this.newWorkflow();
|
||||
private onNewWorkflowDefinitionClick = async () => {
|
||||
await this.newWorkflow();
|
||||
this.modalDialogService.hide(this.workflowDefinitionBrowserInstance);
|
||||
};
|
||||
|
||||
private onWorkflowUpdated = async (e: CustomEvent<WorkflowDefinitionUpdatedArgs>) => {
|
||||
const workflowDefinition = e.detail.workflowDefinition;
|
||||
|
|
@ -108,13 +110,15 @@ export class WorkflowDefinitionsPlugin implements Plugin {
|
|||
}
|
||||
|
||||
private onBrowseWorkflowDefinitions = async () => {
|
||||
await this.workflowDefinitionBrowserElement.show();
|
||||
this.workflowDefinitionBrowserInstance = this.modalDialogService.show(() =>
|
||||
<elsa-workflow-definition-browser onWorkflowDefinitionSelected={this.onWorkflowDefinitionSelected} onNewWorkflowDefinitionSelected={this.onNewWorkflowDefinitionClick}/>)
|
||||
}
|
||||
|
||||
private onWorkflowDefinitionSelected = async (e: CustomEvent<WorkflowDefinitionSummary>) => {
|
||||
const definitionId = e.detail.definitionId;
|
||||
const workflowDefinition = await this.api.get({definitionId});
|
||||
this.showWorkflowDefinitionEditor(workflowDefinition);
|
||||
this.modalDialogService.hide(this.workflowDefinitionBrowserInstance);
|
||||
}
|
||||
|
||||
private onPublishClicked = async (e: CustomEvent<PublishClickedArgs>) => {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ export class WorkflowInstanceBrowser {
|
|||
private readonly workflowInstancesApi: WorkflowInstancesApi;
|
||||
private readonly workflowDefinitionsApi: WorkflowDefinitionsApi;
|
||||
|
||||
private modalDialog: HTMLElsaModalDialogElement;
|
||||
private selectAllCheckbox: HTMLInputElement;
|
||||
private publishedOrLatestWorkflows: Array<WorkflowDefinitionSummary> = [];
|
||||
|
||||
|
|
@ -48,18 +47,11 @@ export class WorkflowInstanceBrowser {
|
|||
@State() private selectedSubStatus?: WorkflowSubStatus;
|
||||
@State() private orderBy?: OrderBy;
|
||||
|
||||
@Method()
|
||||
public async show() {
|
||||
await this.modalDialog.show();
|
||||
async componentWillLoad() {
|
||||
await this.loadWorkflows();
|
||||
await this.loadWorkflowInstances();
|
||||
}
|
||||
|
||||
@Method()
|
||||
public async hide() {
|
||||
await this.modalDialog.hide();
|
||||
}
|
||||
|
||||
public render() {
|
||||
const publishedOrLatestWorkflows = this.publishedOrLatestWorkflows;
|
||||
const workflowInstances = this.workflowInstances;
|
||||
|
|
@ -94,84 +86,80 @@ export class WorkflowInstanceBrowser {
|
|||
return (
|
||||
<Host class="block">
|
||||
|
||||
<elsa-modal-dialog ref={el => this.modalDialog = el} actions={actions} size="sm:w-fit max-w-fit">
|
||||
<div class="pt-4">
|
||||
<h2 class="text-lg font-medium ml-4 mb-2">Workflow Instances</h2>
|
||||
<div class="pt-4">
|
||||
<h2 class="text-lg font-medium ml-4 mb-2">Workflow Instances</h2>
|
||||
|
||||
<Search onSearch={this.onSearch}/>
|
||||
<Filter {...filterProps}/>
|
||||
<Search onSearch={this.onSearch}/>
|
||||
<Filter {...filterProps}/>
|
||||
|
||||
<div class="align-middle inline-block min-w-full border-b border-gray-200">
|
||||
<table class="default-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<input type="checkbox" value="true" checked={this.getSelectAllState()}
|
||||
onChange={e => this.onSelectAllCheckChange(e)}
|
||||
ref={el => this.selectAllCheckbox = el}/>
|
||||
</th>
|
||||
<th><span class="lg:pl-2">ID</span></th>
|
||||
<th class="optional">Correlation</th>
|
||||
<th>Workflow</th>
|
||||
<th class="align-right">Version</th>
|
||||
<th class="optional">Name</th>
|
||||
<th>Status</th>
|
||||
<th class="optional">Created</th>
|
||||
<th class="optional">Finished</th>
|
||||
<th class="optional">Executed</th>
|
||||
<th class="optional">Faulted</th>
|
||||
<th/>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white divide-y divide-gray-100">
|
||||
{workflowInstances.items.map(workflowInstance => {
|
||||
const statusColor = getSubStatusColor(workflowInstance.subStatus);
|
||||
const isSelected = this.selectedWorkflowInstanceIds.findIndex(x => x === workflowInstance.id) >= 0;
|
||||
const workflow: WorkflowDefinitionSummary = publishedOrLatestWorkflows.find(x => x.definitionId == workflowInstance.definitionId);
|
||||
const workflowName = !!workflow ? (workflow.name || 'Untitled') : '(Definition not found)';
|
||||
<div class="align-middle inline-block min-w-full border-b border-gray-200">
|
||||
<table class="default-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<input type="checkbox" value="true" checked={this.getSelectAllState()}
|
||||
onChange={e => this.onSelectAllCheckChange(e)}
|
||||
ref={el => this.selectAllCheckbox = el}/>
|
||||
</th>
|
||||
<th><span class="lg:pl-2">ID</span></th>
|
||||
<th class="optional">Correlation</th>
|
||||
<th>Workflow</th>
|
||||
<th class="align-right">Version</th>
|
||||
<th class="optional">Name</th>
|
||||
<th>Status</th>
|
||||
<th class="optional">Created</th>
|
||||
<th class="optional">Finished</th>
|
||||
<th class="optional">Executed</th>
|
||||
<th class="optional">Faulted</th>
|
||||
<th/>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white divide-y divide-gray-100">
|
||||
{workflowInstances.items.map(workflowInstance => {
|
||||
const statusColor = getSubStatusColor(workflowInstance.subStatus);
|
||||
const isSelected = this.selectedWorkflowInstanceIds.findIndex(x => x === workflowInstance.id) >= 0;
|
||||
const workflow: WorkflowDefinitionSummary = publishedOrLatestWorkflows.find(x => x.definitionId == workflowInstance.definitionId);
|
||||
const workflowName = !!workflow ? (workflow.name || 'Untitled') : '(Definition not found)';
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" value={workflowInstance.id} checked={isSelected} onChange={e => this.onWorkflowInstanceCheckChange(e, workflowInstance)}/>
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex items-center space-x-3 lg:pl-2">
|
||||
<a onClick={e => this.onWorkflowInstanceClick(e, workflowInstance)} href="#" class="truncate hover:text-gray-600"><span>{workflowInstance.id}</span></a>
|
||||
</div>
|
||||
</td>
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" value={workflowInstance.id} checked={isSelected} onChange={e => this.onWorkflowInstanceCheckChange(e, workflowInstance)}/>
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex items-center space-x-3 lg:pl-2">
|
||||
<a onClick={e => this.onWorkflowInstanceClick(e, workflowInstance)} href="#" class="truncate hover:text-gray-600"><span>{workflowInstance.id}</span></a>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="optional">{workflowInstance.correlationId}</td>
|
||||
<td class="optional">{workflowName}</td>
|
||||
<td class="align-right">{workflowInstance.version}</td>
|
||||
<td class="optional">{workflowInstance.name}</td>
|
||||
<td>
|
||||
<div class="flex items-center space-x-3 lg:pl-2">
|
||||
<div class={`flex-shrink-0 w-2.5 h-2.5 rounded-full ${statusColor}`}/>
|
||||
<span>{workflowInstance.status}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="optional">{formatTimestamp(workflowInstance.createdAt, '-')}</td>
|
||||
<td class="optional">{formatTimestamp(workflowInstance.finishedAt, '-')}</td>
|
||||
<td class="optional">{formatTimestamp(workflowInstance.lastExecutedAt, '-')}</td>
|
||||
<td class="optional">{formatTimestamp(workflowInstance.faultedAt, '-')}</td>
|
||||
<td class="pr-6">
|
||||
<elsa-context-menu menuItems={[
|
||||
{text: 'Edit', clickHandler: e => this.onWorkflowInstanceClick(e, workflowInstance), icon: <EditIcon/>},
|
||||
{text: 'Delete', clickHandler: e => this.onDeleteClick(e, workflowInstance), icon: <DeleteIcon/>}
|
||||
]}/>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
<elsa-pager page={this.currentPage} pageSize={this.currentPageSize} totalCount={totalCount} onPaginated={this.onPaginated}/>
|
||||
</div>
|
||||
|
||||
{/*<confirm-dialog ref={el => this.confirmDialog = el} culture={this.culture}/>*/}
|
||||
<td class="optional">{workflowInstance.correlationId}</td>
|
||||
<td class="optional">{workflowName}</td>
|
||||
<td class="align-right">{workflowInstance.version}</td>
|
||||
<td class="optional">{workflowInstance.name}</td>
|
||||
<td>
|
||||
<div class="flex items-center space-x-3 lg:pl-2">
|
||||
<div class={`flex-shrink-0 w-2.5 h-2.5 rounded-full ${statusColor}`}/>
|
||||
<span>{workflowInstance.status}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="optional">{formatTimestamp(workflowInstance.createdAt, '-')}</td>
|
||||
<td class="optional">{formatTimestamp(workflowInstance.finishedAt, '-')}</td>
|
||||
<td class="optional">{formatTimestamp(workflowInstance.lastExecutedAt, '-')}</td>
|
||||
<td class="optional">{formatTimestamp(workflowInstance.faultedAt, '-')}</td>
|
||||
<td class="pr-6">
|
||||
<elsa-context-menu menuItems={[
|
||||
{text: 'Edit', clickHandler: e => this.onWorkflowInstanceClick(e, workflowInstance), icon: <EditIcon/>},
|
||||
{text: 'Delete', clickHandler: e => this.onDeleteClick(e, workflowInstance), icon: <DeleteIcon/>}
|
||||
]}/>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
<elsa-pager page={this.currentPage} pageSize={this.currentPageSize} totalCount={totalCount} onPaginated={this.onPaginated}/>
|
||||
</div>
|
||||
</elsa-modal-dialog>
|
||||
</div>
|
||||
</Host>
|
||||
);
|
||||
}
|
||||
|
|
@ -270,7 +258,6 @@ export class WorkflowInstanceBrowser {
|
|||
private onWorkflowInstanceClick = async (e: MouseEvent, workflowInstance: WorkflowInstanceSummary) => {
|
||||
e.preventDefault();
|
||||
this.workflowInstanceSelected.emit(workflowInstance);
|
||||
await this.hide();
|
||||
}
|
||||
|
||||
private onSelectAllCheckChange(e: Event) {
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ export class Studio {
|
|||
return <Host>
|
||||
{studioComponentStore.activeComponentFactory()}
|
||||
{studioComponentStore.modalComponents.map(modal => modal())}
|
||||
<elsa-modal-dialog-container/>
|
||||
</Host>;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue