Implement variable picker
This commit is contained in:
parent
c3a3d85f47
commit
2567eb6535
|
|
@ -23,7 +23,7 @@ var services = builder.Services;
|
|||
services
|
||||
.AddElsa(elsa => elsa
|
||||
.UseWorkflows()
|
||||
.UseRuntime()
|
||||
.UseWorkflowRuntime()
|
||||
.UseWorkflowManagement(management => management
|
||||
.AddActivity<Sequence>()
|
||||
.AddActivity<WriteLine>()
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ services
|
|||
identity.CreateDefaultUser = true;
|
||||
identity.IdentityOptions = options => identitySection.Bind(options);
|
||||
})
|
||||
.UseRuntime(runtime =>
|
||||
.UseWorkflowRuntime(runtime =>
|
||||
{
|
||||
runtime.UseProtoActor(proto => proto.PersistenceProvider = _ => new SqliteProvider(new SqliteConnectionStringBuilder(sqliteConnectionString)));
|
||||
runtime.UseEntityFrameworkCore(ef => ef.UseSqlite(sqliteConnectionString));
|
||||
|
|
|
|||
|
|
@ -244,6 +244,9 @@ export namespace Components {
|
|||
"getVariable": () => Promise<Variable>;
|
||||
"variable": Variable;
|
||||
}
|
||||
interface ElsaVariablePickerInput {
|
||||
"inputContext": ActivityInputContext;
|
||||
}
|
||||
interface ElsaVariablesEditor {
|
||||
"variables"?: Array<Variable>;
|
||||
}
|
||||
|
|
@ -562,6 +565,12 @@ declare global {
|
|||
prototype: HTMLElsaVariableEditorDialogContentElement;
|
||||
new (): HTMLElsaVariableEditorDialogContentElement;
|
||||
};
|
||||
interface HTMLElsaVariablePickerInputElement extends Components.ElsaVariablePickerInput, HTMLStencilElement {
|
||||
}
|
||||
var HTMLElsaVariablePickerInputElement: {
|
||||
prototype: HTMLElsaVariablePickerInputElement;
|
||||
new (): HTMLElsaVariablePickerInputElement;
|
||||
};
|
||||
interface HTMLElsaVariablesEditorElement extends Components.ElsaVariablesEditor, HTMLStencilElement {
|
||||
}
|
||||
var HTMLElsaVariablesEditorElement: {
|
||||
|
|
@ -700,6 +709,7 @@ declare global {
|
|||
"elsa-switch-editor": HTMLElsaSwitchEditorElement;
|
||||
"elsa-tooltip": HTMLElsaTooltipElement;
|
||||
"elsa-variable-editor-dialog-content": HTMLElsaVariableEditorDialogContentElement;
|
||||
"elsa-variable-picker-input": HTMLElsaVariablePickerInputElement;
|
||||
"elsa-variables-editor": HTMLElsaVariablesEditorElement;
|
||||
"elsa-workflow-definition-browser": HTMLElsaWorkflowDefinitionBrowserElement;
|
||||
"elsa-workflow-definition-editor": HTMLElsaWorkflowDefinitionEditorElement;
|
||||
|
|
@ -922,6 +932,9 @@ declare namespace LocalJSX {
|
|||
"onVariableChanged"?: (event: CustomEvent<Variable>) => void;
|
||||
"variable"?: Variable;
|
||||
}
|
||||
interface ElsaVariablePickerInput {
|
||||
"inputContext"?: ActivityInputContext;
|
||||
}
|
||||
interface ElsaVariablesEditor {
|
||||
"onVariablesChanged"?: (event: CustomEvent<Array<Variable>>) => void;
|
||||
"variables"?: Array<Variable>;
|
||||
|
|
@ -1036,6 +1049,7 @@ declare namespace LocalJSX {
|
|||
"elsa-switch-editor": ElsaSwitchEditor;
|
||||
"elsa-tooltip": ElsaTooltip;
|
||||
"elsa-variable-editor-dialog-content": ElsaVariableEditorDialogContent;
|
||||
"elsa-variable-picker-input": ElsaVariablePickerInput;
|
||||
"elsa-variables-editor": ElsaVariablesEditor;
|
||||
"elsa-workflow-definition-browser": ElsaWorkflowDefinitionBrowser;
|
||||
"elsa-workflow-definition-editor": ElsaWorkflowDefinitionEditor;
|
||||
|
|
@ -1099,6 +1113,7 @@ declare module "@stencil/core" {
|
|||
"elsa-switch-editor": LocalJSX.ElsaSwitchEditor & JSXBase.HTMLAttributes<HTMLElsaSwitchEditorElement>;
|
||||
"elsa-tooltip": LocalJSX.ElsaTooltip & JSXBase.HTMLAttributes<HTMLElsaTooltipElement>;
|
||||
"elsa-variable-editor-dialog-content": LocalJSX.ElsaVariableEditorDialogContent & JSXBase.HTMLAttributes<HTMLElsaVariableEditorDialogContentElement>;
|
||||
"elsa-variable-picker-input": LocalJSX.ElsaVariablePickerInput & JSXBase.HTMLAttributes<HTMLElsaVariablePickerInputElement>;
|
||||
"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>;
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ export class VariableEditorDialogContent {
|
|||
}
|
||||
|
||||
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 variable: Variable = this.variable ?? {name: '', typeName: 'Object'};
|
||||
const variableTypeName = variable.typeName;
|
||||
const availableTypeNames: Array<string> = ['Object', 'String', 'Boolean', 'Int32', 'Int64', 'Single', 'Double']; // TODO: Fetch these from backend.
|
||||
const storageDrivers: Array<StorageDriverDescriptor> = [{id: null, displayName: '-'}, ...descriptorsStore.storageDrivers];
|
||||
|
||||
return (
|
||||
|
|
@ -36,9 +36,9 @@ export class VariableEditorDialogContent {
|
|||
<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>)}
|
||||
<FormEntry fieldId="variableTypeName" label="Type" hint="The type of the variable.">
|
||||
<select id="variableTypeName" name="variableTypeName">
|
||||
{availableTypeNames.map(typeName => <option value={typeName} selected={typeName == variableTypeName}>{typeName}</option>)}
|
||||
</select>
|
||||
</FormEntry>
|
||||
|
||||
|
|
@ -65,7 +65,6 @@ export class VariableEditorDialogContent {
|
|||
}
|
||||
|
||||
private onSubmit = async (e: Event) => {
|
||||
debugger;
|
||||
e.preventDefault();
|
||||
const form = e.target as HTMLFormElement;
|
||||
const variable = this.getVariableInternal(form);
|
||||
|
|
@ -76,12 +75,12 @@ export class VariableEditorDialogContent {
|
|||
const formData = new FormData(form as HTMLFormElement);
|
||||
const name = formData.get('variableName') as string;
|
||||
const value = formData.get('variableValue') as string;
|
||||
const type = formData.get('variableType') as string;
|
||||
const type = formData.get('variableTypeName') as string;
|
||||
const driverId = formData.get('variableStorageDriverId') as string;
|
||||
const variable = this.variable;
|
||||
|
||||
variable.name = name;
|
||||
variable.type = type;
|
||||
variable.typeName = type;
|
||||
variable.value = value;
|
||||
variable.storageDriverId = isNullOrWhitespace(driverId) ? null : driverId;
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ export class VariablesEditor {
|
|||
return (
|
||||
<tr>
|
||||
<td class="whitespace-nowrap">{variable.name}</td>
|
||||
<td class="whitespace-nowrap">{variable.type}</td>
|
||||
<td class="whitespace-nowrap">{variable.typeName}</td>
|
||||
<td>{variable.value}</td>
|
||||
<td>{storageName}</td>
|
||||
<td class="pr-6">
|
||||
|
|
@ -109,7 +109,7 @@ export class VariablesEditor {
|
|||
|
||||
private onAddVariableClick = async () => {
|
||||
const newVariableName = this.generateNewVariableName();
|
||||
const variable = {name: newVariableName, type: 'Object', value: null};
|
||||
const variable = {name: newVariableName, typeName: 'Object', value: null};
|
||||
|
||||
this.modalDialogInstance = this.modalDialogService.show(() => <elsa-variable-editor-dialog-content variable={variable}/>, {actions: [this.saveAction]})
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {ExpressionChangedArs} from "../designer/input-control-switch/input-contr
|
|||
tag: 'elsa-dropdown-input',
|
||||
shadow: false
|
||||
})
|
||||
export class SingleLineInput {
|
||||
export class DropdownInput {
|
||||
@Prop() public inputContext: ActivityInputContext;
|
||||
|
||||
private selectList: SelectList = {items: [], isFlagsEnum: false};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
import {Component, Prop, h} from '@stencil/core';
|
||||
import {LiteralExpression, SelectList, SyntaxNames, Variable} from "../../models";
|
||||
import {ActivityInputContext} from "../../services/node-input-driver";
|
||||
import {getInputPropertyValue, getPropertyValue, getSelectListItems} from "../../utils";
|
||||
import {ExpressionChangedArs} from "../designer/input-control-switch/input-control-switch";
|
||||
import WorkflowDefinitionEditorTunnel from "../../modules/workflow-definitions/state";
|
||||
import {FormEntry} from "../shared/forms/form-entry";
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-variable-picker-input',
|
||||
shadow: false
|
||||
})
|
||||
export class VariablePickerInput {
|
||||
@Prop() public inputContext: ActivityInputContext;
|
||||
|
||||
public render() {
|
||||
const inputContext = this.inputContext;
|
||||
const inputDescriptor = inputContext.inputDescriptor;
|
||||
const fieldName = inputDescriptor.name;
|
||||
const fieldId = inputDescriptor.name;
|
||||
const displayName = inputDescriptor.displayName;
|
||||
const description = inputDescriptor.description;
|
||||
const value = getPropertyValue(inputContext) as Variable;
|
||||
let currentValue = value;
|
||||
|
||||
if (currentValue == undefined) {
|
||||
const defaultValue = inputDescriptor.defaultValue;
|
||||
currentValue = defaultValue ? defaultValue.toString() : undefined;
|
||||
}
|
||||
|
||||
debugger;
|
||||
|
||||
return (
|
||||
<WorkflowDefinitionEditorTunnel.Consumer>
|
||||
{({workflowDefinition}) => {
|
||||
const variables = workflowDefinition?.variables ?? [];
|
||||
return<FormEntry fieldId={fieldId} label={displayName} hint={description}>
|
||||
<select id={fieldId} name={fieldName} onChange={e => this.onChange(e)}>
|
||||
{variables.map((variable: Variable) => {
|
||||
const isSelected = variable.name == currentValue?.name;
|
||||
const json = JSON.stringify(variable);
|
||||
return <option value={variable.name} selected={isSelected} data-variable={json}>{variable.name}</option>;
|
||||
})}
|
||||
</select>
|
||||
</FormEntry>
|
||||
}}
|
||||
</WorkflowDefinitionEditorTunnel.Consumer>
|
||||
);
|
||||
}
|
||||
|
||||
private onChange = (e: Event) => {
|
||||
debugger;
|
||||
const inputElement = e.target as HTMLSelectElement;
|
||||
const variable = inputElement.selectedOptions.length == 0 ? null : JSON.parse(inputElement.selectedOptions[0].dataset.variable);
|
||||
this.inputContext.inputChanged(variable, SyntaxNames.Literal);
|
||||
}
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ export interface Container extends Activity {
|
|||
|
||||
export interface Variable {
|
||||
name: string;
|
||||
type: string;
|
||||
typeName: string;
|
||||
value?: any;
|
||||
storageDriverId?: string;
|
||||
}
|
||||
|
|
@ -91,6 +91,7 @@ export interface PropertyDescriptor {
|
|||
}
|
||||
|
||||
export interface InputDescriptor extends PropertyDescriptor {
|
||||
isWrapped?: boolean;
|
||||
uiHint?: string;
|
||||
options?: any;
|
||||
category?: string;
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ import {Hash} from "../../utils";
|
|||
import PositionEventArgs = NodeView.PositionEventArgs;
|
||||
import FromJSONData = Model.FromJSONData;
|
||||
import PointLike = Point.PointLike;
|
||||
import FlowchartTunnel, {FlowchartState} from "./state";
|
||||
import {generateUniqueActivityName} from "../../utils/generate-activity-name";
|
||||
import { DagreLayout, OutNode} from '@antv/layout';
|
||||
import FlowchartTunnel, {FlowchartState} from "./state";
|
||||
|
||||
const FlowchartTypeName = 'Elsa.Flowchart';
|
||||
|
||||
|
|
@ -131,7 +131,7 @@ export class FlowchartComponent implements ContainerActivityComponent {
|
|||
nodesep: 15,
|
||||
controlPoints: true,
|
||||
});
|
||||
|
||||
|
||||
let flowchartModel = this.getFlowchartModel();
|
||||
|
||||
let nodes = [];
|
||||
|
|
@ -550,7 +550,6 @@ export class FlowchartComponent implements ContainerActivityComponent {
|
|||
};
|
||||
|
||||
private onNodeContextMenu = async (e: PositionEventArgs<JQuery.ContextMenuEvent>) => {
|
||||
debugger;
|
||||
const node = e.node as ActivityNodeShape;
|
||||
const activity = e.node.data as Activity;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {ActivityInputContext} from "../../../services/node-input-driver";
|
|||
import {CheckboxFormEntry, FormEntry} from "../../../components/shared/forms/form-entry";
|
||||
import {isNullOrWhitespace} from "../../../utils";
|
||||
import descriptorsStore from "../../../data/descriptors-store";
|
||||
import {Input} from "postcss";
|
||||
|
||||
export interface ActivityUpdatedArgs {
|
||||
originalId: string;
|
||||
|
|
@ -127,11 +128,10 @@ export class ActivityPropertiesEditor {
|
|||
tabs.push(outputTab);
|
||||
}
|
||||
|
||||
if(isTask)
|
||||
{
|
||||
if (isTask) {
|
||||
const taskTab: TabDefinition = {
|
||||
displayText: 'Task',
|
||||
order:12,
|
||||
order: 12,
|
||||
content: () => this.renderTaskTab()
|
||||
};
|
||||
|
||||
|
|
@ -222,15 +222,20 @@ export class ActivityPropertiesEditor {
|
|||
private onInputPropertyEditorChanged = (inputDescriptor: InputDescriptor, propertyValue: any, syntax: string) => {
|
||||
const activity = this.activity;
|
||||
const propertyName = inputDescriptor.name;
|
||||
const isWrapped = inputDescriptor.isWrapped;
|
||||
const camelCasePropertyName = camelCase(propertyName);
|
||||
|
||||
activity[camelCasePropertyName] = {
|
||||
type: inputDescriptor.type,
|
||||
expression: {
|
||||
type: syntax,
|
||||
value: propertyValue // TODO: The "value" field is currently hardcoded, but we should be able to be more flexible and potentially have different fields for a given syntax.
|
||||
}
|
||||
};
|
||||
if (isWrapped) {
|
||||
activity[camelCasePropertyName] = {
|
||||
type: inputDescriptor.type,
|
||||
expression: {
|
||||
type: syntax,
|
||||
value: propertyValue // TODO: The "value" field is currently hardcoded, but we should be able to be more flexible and potentially have different fields for a given syntax.
|
||||
}
|
||||
};
|
||||
} else {
|
||||
activity[camelCasePropertyName] = propertyValue;
|
||||
}
|
||||
|
||||
this.updateActivity(propertyName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,20 +4,19 @@ import {Container} from "typedi";
|
|||
import {PanelPosition, PanelStateChangedArgs} from '../../../components/panel/models';
|
||||
import {
|
||||
Activity,
|
||||
ActivityDeletedArgs,
|
||||
ActivityDescriptor,
|
||||
ActivitySelectedArgs,
|
||||
ChildActivitySelectedArgs,
|
||||
ContainerSelectedArgs,
|
||||
GraphUpdatedArgs,
|
||||
VersionedEntity
|
||||
GraphUpdatedArgs
|
||||
} from '../../../models';
|
||||
import {ActivityIdUpdatedArgs, ActivityUpdatedArgs} from './activity-properties-editor';
|
||||
import {ActivityUpdatedArgs} from './activity-properties-editor';
|
||||
import {ActivityDriverRegistry, ActivityNameFormatter, EventBus, PluginRegistry, PortProviderRegistry} from '../../../services';
|
||||
import {MonacoEditorSettings} from "../../../services/monaco-editor-settings";
|
||||
import {ActivityPropertyChangedEventArgs, WorkflowDefinitionPropsUpdatedArgs, WorkflowDefinitionUpdatedArgs, WorkflowEditorEventTypes} from "../models/ui";
|
||||
import {WorkflowDefinition} from "../models/entities";
|
||||
import {WorkflowDefinitionsApi} from "../../workflow-definitions/services/api";
|
||||
import {WorkflowDefinitionsApi} from "../services/api"
|
||||
import WorkflowDefinitionEditorTunnel, {WorkflowDefinitionEditorState} from "../state";
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-workflow-definition-editor',
|
||||
|
|
@ -146,12 +145,10 @@ export class WorkflowDefinitionEditor {
|
|||
|
||||
@Method()
|
||||
async loadWorkflowVersions(): Promise<void> {
|
||||
if(this.workflowDefinitionState.definitionId != null && this.workflowDefinitionState.definitionId.length > 0)
|
||||
{
|
||||
if (this.workflowDefinitionState.definitionId != null && this.workflowDefinitionState.definitionId.length > 0) {
|
||||
const workflowVersions = await this.workflowDefinitionApi.getVersions(this.workflowDefinitionState.definitionId);
|
||||
this.workflowVersions = workflowVersions.sort(x => x.version).reverse();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.workflowVersions = [];
|
||||
}
|
||||
}
|
||||
|
|
@ -256,7 +253,7 @@ export class WorkflowDefinitionEditor {
|
|||
onVersionSelected = async (e: CustomEvent<WorkflowDefinition>) => {
|
||||
const workflowToView = e.detail;
|
||||
const workflowDefinition = await this.workflowDefinitionApi.get({definitionId: workflowToView.definitionId, versionOptions: {version: workflowToView.version}});
|
||||
this.importWorkflow(workflowDefinition);
|
||||
await this.importWorkflow(workflowDefinition);
|
||||
};
|
||||
|
||||
onDeleteVersionClicked = async (e: CustomEvent<WorkflowDefinition>) => {
|
||||
|
|
@ -264,7 +261,7 @@ export class WorkflowDefinitionEditor {
|
|||
await this.workflowDefinitionApi.deleteVersion({definitionId: workflowToDelete.definitionId, version: workflowToDelete.version});
|
||||
const latestWorkflowDefinition = await this.workflowDefinitionApi.get({definitionId: workflowToDelete.definitionId, versionOptions: {isLatest: true}});
|
||||
await this.loadWorkflowVersions();
|
||||
this.importWorkflow(latestWorkflowDefinition);
|
||||
await this.importWorkflow(latestWorkflowDefinition);
|
||||
};
|
||||
|
||||
onRevertVersionClicked = async (e: CustomEvent<WorkflowDefinition>) => {
|
||||
|
|
@ -272,49 +269,54 @@ export class WorkflowDefinitionEditor {
|
|||
await this.workflowDefinitionApi.revertVersion({definitionId: workflowToRevert.definitionId, version: workflowToRevert.version});
|
||||
const workflowDefinition = await this.workflowDefinitionApi.get({definitionId: workflowToRevert.definitionId, versionOptions: {isLatest: true}});
|
||||
await this.loadWorkflowVersions();
|
||||
this.importWorkflow(workflowDefinition);
|
||||
await this.importWorkflow(workflowDefinition);
|
||||
};
|
||||
|
||||
render() {
|
||||
const state: WorkflowDefinitionEditorState = {
|
||||
workflowDefinition: this.workflowDefinition
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="absolute inset-0" ref={el => this.container = el}>
|
||||
<elsa-workflow-definition-editor-toolbar zoomToFit={this.onZoomToFit} autoLayout={this.onAutoLayout}/>
|
||||
<elsa-panel
|
||||
class="elsa-activity-picker-container z-30"
|
||||
position={PanelPosition.Left}
|
||||
onExpandedStateChanged={e => this.onActivityPickerPanelStateChanged(e.detail)}>
|
||||
<elsa-workflow-definition-editor-toolbox ref={el => this.toolbox = el}/>
|
||||
</elsa-panel>
|
||||
<elsa-canvas
|
||||
class="absolute" ref={el => this.canvas = el}
|
||||
interactiveMode={true}
|
||||
onDragOver={this.onDragOver}
|
||||
onDrop={this.onDrop}/>
|
||||
<elsa-panel
|
||||
class="elsa-workflow-editor-container z-30"
|
||||
position={PanelPosition.Right}
|
||||
onExpandedStateChanged={e => this.onWorkflowEditorPanelStateChanged(e.detail)}>
|
||||
<div class="object-editor-container">
|
||||
<elsa-workflow-definition-properties-editor
|
||||
workflowDefinition={this.workflowDefinitionState}
|
||||
workflowVersions={this.workflowVersions}
|
||||
onWorkflowPropsUpdated={e => this.onWorkflowPropsUpdated(e)}
|
||||
onVersionSelected={e => this.onVersionSelected(e)}
|
||||
onDeleteVersionClicked={e => this.onDeleteVersionClicked(e)}
|
||||
onRevertVersionClicked={e => this.onRevertVersionClicked(e)}
|
||||
/>
|
||||
</div>
|
||||
</elsa-panel>
|
||||
<elsa-panel
|
||||
class="elsa-activity-editor-container"
|
||||
position={PanelPosition.Bottom}
|
||||
onExpandedStateChanged={e => this.onActivityEditorPanelStateChanged(e.detail)}>
|
||||
<div class="activity-editor-container">
|
||||
{this.renderSelectedObject()}
|
||||
</div>
|
||||
</elsa-panel>
|
||||
</div>
|
||||
<WorkflowDefinitionEditorTunnel.Provider state={state}>
|
||||
<div class="absolute inset-0" ref={el => this.container = el}>
|
||||
<elsa-workflow-definition-editor-toolbar zoomToFit={this.onZoomToFit} autoLayout={this.onAutoLayout}/>
|
||||
<elsa-panel
|
||||
class="elsa-activity-picker-container z-30"
|
||||
position={PanelPosition.Left}
|
||||
onExpandedStateChanged={e => this.onActivityPickerPanelStateChanged(e.detail)}>
|
||||
<elsa-workflow-definition-editor-toolbox ref={el => this.toolbox = el}/>
|
||||
</elsa-panel>
|
||||
<elsa-canvas
|
||||
class="absolute" ref={el => this.canvas = el}
|
||||
interactiveMode={true}
|
||||
onDragOver={this.onDragOver}
|
||||
onDrop={this.onDrop}/>
|
||||
<elsa-panel
|
||||
class="elsa-workflow-editor-container z-30"
|
||||
position={PanelPosition.Right}
|
||||
onExpandedStateChanged={e => this.onWorkflowEditorPanelStateChanged(e.detail)}>
|
||||
<div class="object-editor-container">
|
||||
<elsa-workflow-definition-properties-editor
|
||||
workflowDefinition={this.workflowDefinitionState}
|
||||
workflowVersions={this.workflowVersions}
|
||||
onWorkflowPropsUpdated={e => this.onWorkflowPropsUpdated(e)}
|
||||
onVersionSelected={e => this.onVersionSelected(e)}
|
||||
onDeleteVersionClicked={e => this.onDeleteVersionClicked(e)}
|
||||
onRevertVersionClicked={e => this.onRevertVersionClicked(e)}
|
||||
/>
|
||||
</div>
|
||||
</elsa-panel>
|
||||
<elsa-panel
|
||||
class="elsa-activity-editor-container"
|
||||
position={PanelPosition.Bottom}
|
||||
onExpandedStateChanged={e => this.onActivityEditorPanelStateChanged(e.detail)}>
|
||||
<div class="activity-editor-container">
|
||||
{this.renderSelectedObject()}
|
||||
</div>
|
||||
</elsa-panel>
|
||||
</div>
|
||||
</WorkflowDefinitionEditorTunnel.Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,18 +110,15 @@ export class WorkflowDefinitionsPlugin implements Plugin {
|
|||
private onWorkflowUpdated = async (e: CustomEvent<WorkflowDefinitionUpdatedArgs>) => {
|
||||
const updatedWorkflowDefinition = e.detail.workflowDefinition;
|
||||
|
||||
if(e.detail.latestVersionNumber == undefined)
|
||||
{
|
||||
if (e.detail.latestVersionNumber == undefined) {
|
||||
await this.saveWorkflowDefinition(updatedWorkflowDefinition, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if(updatedWorkflowDefinition.version == e.detail.latestVersionNumber || updatedWorkflowDefinition.isPublished)
|
||||
{
|
||||
if (updatedWorkflowDefinition.version == e.detail.latestVersionNumber || updatedWorkflowDefinition.isPublished) {
|
||||
const currentWorkflowDefinition = await this.api.get({definitionId: updatedWorkflowDefinition.definitionId, versionOptions: {version: updatedWorkflowDefinition.version}});
|
||||
if(!isEqual(currentWorkflowDefinition.root.activities, updatedWorkflowDefinition.root.activities))
|
||||
{
|
||||
if(updatedWorkflowDefinition.isPublished)
|
||||
if (!isEqual(currentWorkflowDefinition.root.activities, updatedWorkflowDefinition.root.activities) || !isEqual(currentWorkflowDefinition.variables, updatedWorkflowDefinition.variables)) {
|
||||
if (updatedWorkflowDefinition.isPublished)
|
||||
updatedWorkflowDefinition.version = e.detail.latestVersionNumber;
|
||||
|
||||
await this.saveWorkflowDefinition(updatedWorkflowDefinition, false);
|
||||
|
|
@ -135,7 +132,7 @@ export class WorkflowDefinitionsPlugin implements Plugin {
|
|||
const actions = [closeAction, newAction];
|
||||
|
||||
this.workflowDefinitionBrowserInstance = this.modalDialogService.show(() =>
|
||||
<elsa-workflow-definition-browser onWorkflowDefinitionSelected={this.onWorkflowDefinitionSelected} onNewWorkflowDefinitionSelected={this.onNewWorkflowDefinitionClick}/>,
|
||||
<elsa-workflow-definition-browser onWorkflowDefinitionSelected={this.onWorkflowDefinitionSelected} onNewWorkflowDefinitionSelected={this.onNewWorkflowDefinitionClick}/>,
|
||||
{actions})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
import {createProviderConsumer} from "@stencil/state-tunnel";
|
||||
import {h} from "@stencil/core";
|
||||
import {WorkflowDefinition} from "./models/entities";
|
||||
|
||||
export interface WorkflowDefinitionEditorState {
|
||||
workflowDefinition: WorkflowDefinition;
|
||||
}
|
||||
|
||||
export default createProviderConsumer<WorkflowDefinitionEditorState>(
|
||||
{
|
||||
workflowDefinition: null,
|
||||
},
|
||||
(subscribe, child) => (<context-consumer subscribe={subscribe} renderer={child}/>)
|
||||
);
|
||||
|
|
@ -62,7 +62,6 @@ export class WorkflowInstancesPlugin implements Plugin {
|
|||
const version = e.detail.version;
|
||||
const workflowDefinition = await this.workflowDefinitionsApi.get({definitionId, versionOptions: {version}});
|
||||
const workflowInstance = await this.workflowInstancesApi.get({id: instanceId});
|
||||
debugger;
|
||||
this.showWorkflowInstanceViewer(workflowDefinition, workflowInstance);
|
||||
this.modalDialogService.hide(this.workflowInstanceBrowserInstance);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ export class InputControlRegistry {
|
|||
this.add('multi-text', c => <elsa-multi-text-input inputContext={c}/>);
|
||||
this.add('code-editor', c => <elsa-code-editor-input inputContext={c}/>);
|
||||
this.add('checkbox', c => <elsa-checkbox-input inputContext={c}/>);
|
||||
this.add('variable-picker', c => <elsa-variable-picker-input inputContext={c}/>);
|
||||
}
|
||||
|
||||
public add(uiHint: UIHint, control: RenderActivityPropInputControl) {
|
||||
|
|
|
|||
|
|
@ -74,6 +74,11 @@ export const getInputPropertyValue = (inputContext: ActivityInputContext): Activ
|
|||
return inputContext.node[propName] as ActivityInput;
|
||||
};
|
||||
|
||||
export const getPropertyValue = (inputContext: ActivityInputContext): any => {
|
||||
const propName = getInputPropertyName(inputContext);
|
||||
return inputContext.node[propName] as any
|
||||
};
|
||||
|
||||
export const stripActivityNameSpace = (name: string): string => {
|
||||
const lastDotIndex = name.lastIndexOf('.');
|
||||
return lastDotIndex < 0 ? name : name.substr(lastDotIndex + 1);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ public class List : ElsaEndpointWithoutRequest<Response>
|
|||
{
|
||||
private readonly IActivityRegistry _registry;
|
||||
|
||||
public List(IActivityRegistry registry, IWellKnownTypeRegistry wellKnownTypeRegistry)
|
||||
public List(IActivityRegistry registry)
|
||||
{
|
||||
_registry = registry;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ public class SetVariable<T> : Activity
|
|||
[Activity("Elsa", "Primitives", "Set a workflow variable to a given value.")]
|
||||
public class SetVariable : Activity
|
||||
{
|
||||
[Input] public Variable Variable { get; set; } = default!;
|
||||
[Input] public Input<object?> Value { get; set; } = new(default(object));
|
||||
public Variable Variable { get; set; } = default!;
|
||||
|
||||
protected override void Execute(ActivityExecutionContext context)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ public class InputDescriptor : PropertyDescriptor
|
|||
public InputDescriptor(
|
||||
string name,
|
||||
Type type,
|
||||
bool isWrapped,
|
||||
string uiHint,
|
||||
string displayName,
|
||||
string? description = default,
|
||||
|
|
@ -23,6 +24,7 @@ public class InputDescriptor : PropertyDescriptor
|
|||
{
|
||||
Name = name;
|
||||
Type = type;
|
||||
IsWrapped = isWrapped;
|
||||
UIHint = uiHint;
|
||||
DisplayName = displayName;
|
||||
Description = description;
|
||||
|
|
@ -36,6 +38,7 @@ public class InputDescriptor : PropertyDescriptor
|
|||
IsBrowsable = isBrowsable;
|
||||
}
|
||||
|
||||
public bool IsWrapped { get; set; }
|
||||
public string UIHint { get; set; } = default!;
|
||||
public object? Options { get; set; }
|
||||
public string? Category { get; set; }
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ public class VariableConverter : JsonConverter<Variable>
|
|||
|
||||
public Variable? Map(VariableModel source)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(source.TypeName))
|
||||
return null;
|
||||
|
||||
if (!_wellKnownTypeRegistry.TryGetTypeOrDefault(source.TypeName, out var type))
|
||||
return null;
|
||||
|
||||
|
|
|
|||
|
|
@ -102,12 +102,14 @@ public class ActivityDescriber : IActivityDescriber
|
|||
var inputAttribute = propertyInfo.GetCustomAttribute<InputAttribute>();
|
||||
var descriptionAttribute = propertyInfo.GetCustomAttribute<DescriptionAttribute>();
|
||||
var propertyType = propertyInfo.PropertyType;
|
||||
var wrappedPropertyType = !typeof(Input).IsAssignableFrom(propertyType) ? propertyType : propertyInfo.PropertyType.GenericTypeArguments[0];
|
||||
var isWrappedProperty = typeof(Input).IsAssignableFrom(propertyType);
|
||||
var wrappedPropertyType = !isWrappedProperty ? propertyType : propertyInfo.PropertyType.GenericTypeArguments[0];
|
||||
|
||||
yield return new InputDescriptor
|
||||
(
|
||||
inputAttribute?.Name ?? propertyInfo.Name,
|
||||
wrappedPropertyType,
|
||||
isWrappedProperty,
|
||||
GetUIHint(wrappedPropertyType, inputAttribute),
|
||||
inputAttribute?.DisplayName ?? propertyInfo.Name.Humanize(LetterCasing.Title),
|
||||
descriptionAttribute?.Description ?? inputAttribute?.Description,
|
||||
|
|
@ -159,6 +161,9 @@ public class ActivityDescriber : IActivityDescriber
|
|||
|
||||
if (wrappedPropertyType.IsEnum || wrappedPropertyType.IsNullableType() && wrappedPropertyType.GetTypeOfNullable().IsEnum)
|
||||
return InputUIHints.Dropdown;
|
||||
|
||||
if (wrappedPropertyType == typeof(Variable))
|
||||
return InputUIHints.VariablePicker;
|
||||
|
||||
return InputUIHints.SingleLine;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ public class VariableDefinitionMapper
|
|||
|
||||
public Variable? Map(VariableDefinition source)
|
||||
{
|
||||
if (!_wellKnownTypeRegistry.TryGetTypeOrDefault(source.Type, out var type))
|
||||
if (!_wellKnownTypeRegistry.TryGetTypeOrDefault(source.TypeName, out var type))
|
||||
return null;
|
||||
|
||||
var variableGenericType = typeof(Variable<>).MakeGenericType(type);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ public static class InputUIHints
|
|||
public const string Dropdown = "dropdown";
|
||||
public const string MultiText = "multi-text";
|
||||
public const string CodeEditor = "code-editor";
|
||||
public const string VariablePicker = "variable-picker";
|
||||
|
||||
/// <summary>
|
||||
/// An editor that allows the user to write a blob of JSON.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
namespace Elsa.Workflows.Management.Models;
|
||||
|
||||
public record VariableDefinition(string Name, string Type, string? Value, string? StorageDriverId);
|
||||
public record VariableDefinition(string Name, string TypeName, string? Value, string? StorageDriverId);
|
||||
|
|
@ -7,7 +7,7 @@ namespace Elsa.Workflows.Runtime.Extensions;
|
|||
|
||||
public static class DependencyInjectionExtensions
|
||||
{
|
||||
public static IModule UseRuntime(this IModule module, Action<WorkflowRuntimeFeature>? configure = default)
|
||||
public static IModule UseWorkflowRuntime(this IModule module, Action<WorkflowRuntimeFeature>? configure = default)
|
||||
{
|
||||
module.Configure(configure);
|
||||
return module;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Features.Extensions;
|
||||
using Elsa.Identity;
|
||||
using Elsa.Identity.Extensions;
|
||||
using Elsa.Identity.Features;
|
||||
using Elsa.Identity.Options;
|
||||
using Elsa.JavaScript.Activities;
|
||||
using Elsa.JavaScript.Extensions;
|
||||
|
|
@ -66,7 +64,7 @@ services
|
|||
identity.CreateDefaultUser = true;
|
||||
identity.IdentityOptions = options => identitySection.Bind(options);
|
||||
})
|
||||
.UseRuntime(runtime =>
|
||||
.UseWorkflowRuntime(runtime =>
|
||||
{
|
||||
runtime.UseProtoActor(proto =>
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue