diff --git a/src/bundles/Elsa.AllInOne.Web/Program.cs b/src/bundles/Elsa.AllInOne.Web/Program.cs index 34fa515f4..153e59915 100644 --- a/src/bundles/Elsa.AllInOne.Web/Program.cs +++ b/src/bundles/Elsa.AllInOne.Web/Program.cs @@ -23,7 +23,7 @@ var services = builder.Services; services .AddElsa(elsa => elsa .UseWorkflows() - .UseRuntime() + .UseWorkflowRuntime() .UseWorkflowManagement(management => management .AddActivity() .AddActivity() diff --git a/src/bundles/Elsa.WorkflowServer.Web/Program.cs b/src/bundles/Elsa.WorkflowServer.Web/Program.cs index 3ea250e8d..1c1da9794 100644 --- a/src/bundles/Elsa.WorkflowServer.Web/Program.cs +++ b/src/bundles/Elsa.WorkflowServer.Web/Program.cs @@ -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)); diff --git a/src/designer/elsa-workflows-designer/src/components.d.ts b/src/designer/elsa-workflows-designer/src/components.d.ts index f4cee0274..d849e868c 100644 --- a/src/designer/elsa-workflows-designer/src/components.d.ts +++ b/src/designer/elsa-workflows-designer/src/components.d.ts @@ -244,6 +244,9 @@ export namespace Components { "getVariable": () => Promise; "variable": Variable; } + interface ElsaVariablePickerInput { + "inputContext": ActivityInputContext; + } interface ElsaVariablesEditor { "variables"?: Array; } @@ -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) => void; "variable"?: Variable; } + interface ElsaVariablePickerInput { + "inputContext"?: ActivityInputContext; + } interface ElsaVariablesEditor { "onVariablesChanged"?: (event: CustomEvent>) => void; "variables"?: Array; @@ -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; "elsa-tooltip": LocalJSX.ElsaTooltip & JSXBase.HTMLAttributes; "elsa-variable-editor-dialog-content": LocalJSX.ElsaVariableEditorDialogContent & JSXBase.HTMLAttributes; + "elsa-variable-picker-input": LocalJSX.ElsaVariablePickerInput & JSXBase.HTMLAttributes; "elsa-variables-editor": LocalJSX.ElsaVariablesEditor & JSXBase.HTMLAttributes; "elsa-workflow-definition-browser": LocalJSX.ElsaWorkflowDefinitionBrowser & JSXBase.HTMLAttributes; "elsa-workflow-definition-editor": LocalJSX.ElsaWorkflowDefinitionEditor & JSXBase.HTMLAttributes; diff --git a/src/designer/elsa-workflows-designer/src/components/designer/variables-editor/variable-editor-dialog-content.tsx b/src/designer/elsa-workflows-designer/src/components/designer/variables-editor/variable-editor-dialog-content.tsx index 33f6bcae4..8e8ed84e5 100644 --- a/src/designer/elsa-workflows-designer/src/components/designer/variables-editor/variable-editor-dialog-content.tsx +++ b/src/designer/elsa-workflows-designer/src/components/designer/variables-editor/variable-editor-dialog-content.tsx @@ -20,9 +20,9 @@ export class VariableEditorDialogContent { } render() { - const variable: Variable = this.variable ?? {name: '', type: 'Object'}; - const variableType = variable.type; - const availableTypes: Array = ['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 = ['Object', 'String', 'Boolean', 'Int32', 'Int64', 'Single', 'Double']; // TODO: Fetch these from backend. const storageDrivers: Array = [{id: null, displayName: '-'}, ...descriptorsStore.storageDrivers]; return ( @@ -36,9 +36,9 @@ export class VariableEditorDialogContent { - - + {availableTypeNames.map(typeName => )} @@ -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; diff --git a/src/designer/elsa-workflows-designer/src/components/designer/variables-editor/variables-editor.tsx b/src/designer/elsa-workflows-designer/src/components/designer/variables-editor/variables-editor.tsx index 83f0a368b..07dcdc1f1 100644 --- a/src/designer/elsa-workflows-designer/src/components/designer/variables-editor/variables-editor.tsx +++ b/src/designer/elsa-workflows-designer/src/components/designer/variables-editor/variables-editor.tsx @@ -67,7 +67,7 @@ export class VariablesEditor { return ( {variable.name} - {variable.type} + {variable.typeName} {variable.value} {storageName} @@ -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(() => , {actions: [this.saveAction]}) }; diff --git a/src/designer/elsa-workflows-designer/src/components/inputs/dropdown.tsx b/src/designer/elsa-workflows-designer/src/components/inputs/dropdown.tsx index 7746304db..2a4476b14 100644 --- a/src/designer/elsa-workflows-designer/src/components/inputs/dropdown.tsx +++ b/src/designer/elsa-workflows-designer/src/components/inputs/dropdown.tsx @@ -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}; diff --git a/src/designer/elsa-workflows-designer/src/components/inputs/variable-picker.tsx b/src/designer/elsa-workflows-designer/src/components/inputs/variable-picker.tsx new file mode 100644 index 000000000..f2d1eb186 --- /dev/null +++ b/src/designer/elsa-workflows-designer/src/components/inputs/variable-picker.tsx @@ -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 ( + + {({workflowDefinition}) => { + const variables = workflowDefinition?.variables ?? []; + return + + + }} + + ); + } + + 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); + } +} diff --git a/src/designer/elsa-workflows-designer/src/models/core.ts b/src/designer/elsa-workflows-designer/src/models/core.ts index 68f24c97f..2f65ad27c 100644 --- a/src/designer/elsa-workflows-designer/src/models/core.ts +++ b/src/designer/elsa-workflows-designer/src/models/core.ts @@ -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; diff --git a/src/designer/elsa-workflows-designer/src/modules/flowchart/flowchart.tsx b/src/designer/elsa-workflows-designer/src/modules/flowchart/flowchart.tsx index 026cfb63f..726c9c33e 100644 --- a/src/designer/elsa-workflows-designer/src/modules/flowchart/flowchart.tsx +++ b/src/designer/elsa-workflows-designer/src/modules/flowchart/flowchart.tsx @@ -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) => { - debugger; const node = e.node as ActivityNodeShape; const activity = e.node.data as Activity; diff --git a/src/designer/elsa-workflows-designer/src/modules/workflow-definitions/components/activity-properties-editor.tsx b/src/designer/elsa-workflows-designer/src/modules/workflow-definitions/components/activity-properties-editor.tsx index 71ebd385c..4095b171a 100644 --- a/src/designer/elsa-workflows-designer/src/modules/workflow-definitions/components/activity-properties-editor.tsx +++ b/src/designer/elsa-workflows-designer/src/modules/workflow-definitions/components/activity-properties-editor.tsx @@ -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); } diff --git a/src/designer/elsa-workflows-designer/src/modules/workflow-definitions/components/editor.tsx b/src/designer/elsa-workflows-designer/src/modules/workflow-definitions/components/editor.tsx index 2d1a6a47d..43dcfe209 100644 --- a/src/designer/elsa-workflows-designer/src/modules/workflow-definitions/components/editor.tsx +++ b/src/designer/elsa-workflows-designer/src/modules/workflow-definitions/components/editor.tsx @@ -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 { - 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) => { 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) => { @@ -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) => { @@ -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 ( -
this.container = el}> - - this.onActivityPickerPanelStateChanged(e.detail)}> - this.toolbox = el}/> - - this.canvas = el} - interactiveMode={true} - onDragOver={this.onDragOver} - onDrop={this.onDrop}/> - this.onWorkflowEditorPanelStateChanged(e.detail)}> -
- this.onWorkflowPropsUpdated(e)} - onVersionSelected={e => this.onVersionSelected(e)} - onDeleteVersionClicked={e => this.onDeleteVersionClicked(e)} - onRevertVersionClicked={e => this.onRevertVersionClicked(e)} - /> -
-
- this.onActivityEditorPanelStateChanged(e.detail)}> -
- {this.renderSelectedObject()} -
-
-
+ +
this.container = el}> + + this.onActivityPickerPanelStateChanged(e.detail)}> + this.toolbox = el}/> + + this.canvas = el} + interactiveMode={true} + onDragOver={this.onDragOver} + onDrop={this.onDrop}/> + this.onWorkflowEditorPanelStateChanged(e.detail)}> +
+ this.onWorkflowPropsUpdated(e)} + onVersionSelected={e => this.onVersionSelected(e)} + onDeleteVersionClicked={e => this.onDeleteVersionClicked(e)} + onRevertVersionClicked={e => this.onRevertVersionClicked(e)} + /> +
+
+ this.onActivityEditorPanelStateChanged(e.detail)}> +
+ {this.renderSelectedObject()} +
+
+
+
); } } diff --git a/src/designer/elsa-workflows-designer/src/modules/workflow-definitions/plugin.tsx b/src/designer/elsa-workflows-designer/src/modules/workflow-definitions/plugin.tsx index c8f1e2803..800643a21 100644 --- a/src/designer/elsa-workflows-designer/src/modules/workflow-definitions/plugin.tsx +++ b/src/designer/elsa-workflows-designer/src/modules/workflow-definitions/plugin.tsx @@ -110,18 +110,15 @@ export class WorkflowDefinitionsPlugin implements Plugin { private onWorkflowUpdated = async (e: CustomEvent) => { 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(() => - , + , {actions}) } diff --git a/src/designer/elsa-workflows-designer/src/modules/workflow-definitions/state.tsx b/src/designer/elsa-workflows-designer/src/modules/workflow-definitions/state.tsx new file mode 100644 index 000000000..9ccf894f4 --- /dev/null +++ b/src/designer/elsa-workflows-designer/src/modules/workflow-definitions/state.tsx @@ -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( + { + workflowDefinition: null, + }, + (subscribe, child) => () +); diff --git a/src/designer/elsa-workflows-designer/src/modules/workflow-instances/plugin.tsx b/src/designer/elsa-workflows-designer/src/modules/workflow-instances/plugin.tsx index 3e8c775fa..a10db0793 100644 --- a/src/designer/elsa-workflows-designer/src/modules/workflow-instances/plugin.tsx +++ b/src/designer/elsa-workflows-designer/src/modules/workflow-instances/plugin.tsx @@ -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); } diff --git a/src/designer/elsa-workflows-designer/src/services/input-control-registry.tsx b/src/designer/elsa-workflows-designer/src/services/input-control-registry.tsx index 1ae75d6eb..0f0307bfd 100644 --- a/src/designer/elsa-workflows-designer/src/services/input-control-registry.tsx +++ b/src/designer/elsa-workflows-designer/src/services/input-control-registry.tsx @@ -18,6 +18,7 @@ export class InputControlRegistry { this.add('multi-text', c => ); this.add('code-editor', c => ); this.add('checkbox', c => ); + this.add('variable-picker', c => ); } public add(uiHint: UIHint, control: RenderActivityPropInputControl) { diff --git a/src/designer/elsa-workflows-designer/src/utils/utils.ts b/src/designer/elsa-workflows-designer/src/utils/utils.ts index c7aeb606e..18b8c6fa3 100644 --- a/src/designer/elsa-workflows-designer/src/utils/utils.ts +++ b/src/designer/elsa-workflows-designer/src/utils/utils.ts @@ -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); diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/ActivityDescriptors/List/Endpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/ActivityDescriptors/List/Endpoint.cs index 4d6fb6d8a..ba370eeb5 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/ActivityDescriptors/List/Endpoint.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/ActivityDescriptors/List/Endpoint.cs @@ -8,7 +8,7 @@ public class List : ElsaEndpointWithoutRequest { private readonly IActivityRegistry _registry; - public List(IActivityRegistry registry, IWellKnownTypeRegistry wellKnownTypeRegistry) + public List(IActivityRegistry registry) { _registry = registry; } diff --git a/src/modules/Elsa.Workflows.Core/Activities/SetVariable.cs b/src/modules/Elsa.Workflows.Core/Activities/SetVariable.cs index 76d164cb3..eecfa91b0 100644 --- a/src/modules/Elsa.Workflows.Core/Activities/SetVariable.cs +++ b/src/modules/Elsa.Workflows.Core/Activities/SetVariable.cs @@ -48,8 +48,8 @@ public class SetVariable : 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 Value { get; set; } = new(default(object)); - public Variable Variable { get; set; } = default!; protected override void Execute(ActivityExecutionContext context) { diff --git a/src/modules/Elsa.Workflows.Core/Models/InputDescriptor.cs b/src/modules/Elsa.Workflows.Core/Models/InputDescriptor.cs index 375bc8cfd..8d9e476db 100644 --- a/src/modules/Elsa.Workflows.Core/Models/InputDescriptor.cs +++ b/src/modules/Elsa.Workflows.Core/Models/InputDescriptor.cs @@ -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; } diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Converters/VariableConverter.cs b/src/modules/Elsa.Workflows.Core/Serialization/Converters/VariableConverter.cs index d4e25eaa3..8d392ca4e 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/Converters/VariableConverter.cs +++ b/src/modules/Elsa.Workflows.Core/Serialization/Converters/VariableConverter.cs @@ -34,6 +34,9 @@ public class VariableConverter : JsonConverter public Variable? Map(VariableModel source) { + if (string.IsNullOrWhiteSpace(source.TypeName)) + return null; + if (!_wellKnownTypeRegistry.TryGetTypeOrDefault(source.TypeName, out var type)) return null; diff --git a/src/modules/Elsa.Workflows.Management/Implementations/ActivityDescriber.cs b/src/modules/Elsa.Workflows.Management/Implementations/ActivityDescriber.cs index cc0945f89..ede819aab 100644 --- a/src/modules/Elsa.Workflows.Management/Implementations/ActivityDescriber.cs +++ b/src/modules/Elsa.Workflows.Management/Implementations/ActivityDescriber.cs @@ -102,12 +102,14 @@ public class ActivityDescriber : IActivityDescriber var inputAttribute = propertyInfo.GetCustomAttribute(); var descriptionAttribute = propertyInfo.GetCustomAttribute(); 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; } diff --git a/src/modules/Elsa.Workflows.Management/Mappers/VariableDefinitionMapper.cs b/src/modules/Elsa.Workflows.Management/Mappers/VariableDefinitionMapper.cs index 7db6a48d9..824c53d24 100644 --- a/src/modules/Elsa.Workflows.Management/Mappers/VariableDefinitionMapper.cs +++ b/src/modules/Elsa.Workflows.Management/Mappers/VariableDefinitionMapper.cs @@ -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); diff --git a/src/modules/Elsa.Workflows.Management/Models/InputUIHints.cs b/src/modules/Elsa.Workflows.Management/Models/InputUIHints.cs index cb7e152bf..a46a3a074 100644 --- a/src/modules/Elsa.Workflows.Management/Models/InputUIHints.cs +++ b/src/modules/Elsa.Workflows.Management/Models/InputUIHints.cs @@ -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"; /// /// An editor that allows the user to write a blob of JSON. diff --git a/src/modules/Elsa.Workflows.Management/Models/VariableDefinition.cs b/src/modules/Elsa.Workflows.Management/Models/VariableDefinition.cs index 24ea3b00f..1ab8abd95 100644 --- a/src/modules/Elsa.Workflows.Management/Models/VariableDefinition.cs +++ b/src/modules/Elsa.Workflows.Management/Models/VariableDefinition.cs @@ -1,3 +1,3 @@ namespace Elsa.Workflows.Management.Models; -public record VariableDefinition(string Name, string Type, string? Value, string? StorageDriverId); \ No newline at end of file +public record VariableDefinition(string Name, string TypeName, string? Value, string? StorageDriverId); \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Runtime/Extensions/DependencyInjectionExtensions.cs b/src/modules/Elsa.Workflows.Runtime/Extensions/DependencyInjectionExtensions.cs index 05f945035..b719ec7a1 100644 --- a/src/modules/Elsa.Workflows.Runtime/Extensions/DependencyInjectionExtensions.cs +++ b/src/modules/Elsa.Workflows.Runtime/Extensions/DependencyInjectionExtensions.cs @@ -7,7 +7,7 @@ namespace Elsa.Workflows.Runtime.Extensions; public static class DependencyInjectionExtensions { - public static IModule UseRuntime(this IModule module, Action? configure = default) + public static IModule UseWorkflowRuntime(this IModule module, Action? configure = default) { module.Configure(configure); return module; diff --git a/src/samples/aspnet/Elsa.Samples.TelnyxIntegration/Program.cs b/src/samples/aspnet/Elsa.Samples.TelnyxIntegration/Program.cs index c9ac3ee3e..7d25158e2 100644 --- a/src/samples/aspnet/Elsa.Samples.TelnyxIntegration/Program.cs +++ b/src/samples/aspnet/Elsa.Samples.TelnyxIntegration/Program.cs @@ -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 => {