Skip to content

Dynamic Activity Outcomes from Activity property for custom activity #2415

Description

@PietroLubini

Feature
Create possibility to populate possible outcomes in designer from custom activity property's values basing on information in IActivity implementation (server side only)

Reality
There are several builtin activities that populates possible outcomes from their property's values (e.g. SendHttpRequest.SupportedStatusCodes, Fork.Branches).
Such support is hard-coded in JavaScript code of Elsa.Designer.Components.Web.

There is support of IOutcomesProvider implemented as fix for issue #873, but it cannot be used for requested feature

Suggestion
Either extend ActivityAttribute with DynamicOutcomesPropertyName property, or extend ActivityInputAttribute with TreatValuesAsOutcomes

[ActivityInput(
            Hint = "A list of possible HTTP status codes to handle.",
            UIHint = ActivityInputUIHints.MultiText,
            DefaultSyntax = SyntaxNames.Json,
            TreatValuesAsOutcomes = true,
            DefaultValue = new[] { 200 },
            SupportedSyntaxes = new[] { SyntaxNames.Json, SyntaxNames.JavaScript, SyntaxNames.Liquid }
        )]
        public ICollection<int>? SupportedStatusCodes { get; set; } = new HashSet<int>(new[] { 200 });

Remove the following code from custom plugins

 onActivityDesignDisplaying(context: ActivityDesignDisplayContext) {
    const activityModel = context.activityModel;

    if (activityModel.type !== 'SendHttpRequest')
      return;

    const props = activityModel.properties || [];
    const syntax = SyntaxNames.Json;
    const branches = props.find(x => x.name == 'SupportedStatusCodes') || {expressions: {'Json': '[]'}, syntax: syntax};
    const expression = branches.expressions[syntax] || [];
    let outcomes = !!expression['$values'] ? expression['$values'] : Array.isArray(expression) ? expression : parseJson(expression) || [];
    context.outcomes = [...outcomes, 'Done', 'Unsupported Status Code'];
  }

Replace by general DynamicOutcomesPlugin with the following code

class DynamicOutcomesPlugin {
      constructor() {
          eventBus.on(EventTypes.ActivityDesignDisplaying, this.onActivityDesignDisplaying);
      }

      onActivityDesignDisplaying = (context) => {
          const props = context.activityModel.properties || [];
          const syntax = SyntaxNames.Json;
          let dynamicOutcomes = [];
          props
             .filter(prop => prop.treatValuesAsOutcomes))
             .forEach(prop => {
                 const expression = prop.expressions[syntax] || [];
                 const dynamicPropertyOutcomes = !!expression['$values'] ? expression['$values'] : Array.isArray(expression) ? expression : parseJson(expression) || [];
                 dynamicOutcomes = [...dynamicOutcomes, ...dynamicPropertyOutcomes];
             });

          context.outcomes = [...dynamicOutcomes, ...context.outcomes];
      }
}

Benefits
Feature implementation will allow to get rid of

  • Code duplication in JS
  • IActivity implementation becomes closer to be fully self-descriptive

Minor existing issue
Outcomes of UserTask activity still contains obsolete expression

Outcomes = new[] { OutcomeNames.Done, "x => x.state.actions" }

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions