Incremental work on enhancements
This commit is contained in:
parent
ef4fa49571
commit
d71d89cda0
|
|
@ -24,6 +24,7 @@ namespace Elsa.Design
|
|||
/// <summary>
|
||||
/// Optionally provide an object containing useful information for the list select items provider to determine what items to provide.
|
||||
/// </summary>
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.All)]
|
||||
public object? Context { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { Component, h, Prop, Event, EventEmitter, State, Watch } from '@stencil/core';
|
||||
import { MultiTextDefinition } from '../../../models/domain';
|
||||
import { SelectListItem } from '../../../models';
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-input-tags-dropdown',
|
||||
|
|
@ -11,15 +11,15 @@ export class ElsaInputTagsDropdown {
|
|||
@Prop() fieldName?: string;
|
||||
@Prop() fieldId?: string;
|
||||
@Prop() placeHolder?: string = 'Add tag';
|
||||
@Prop() values?: Array<string | MultiTextDefinition> = [];
|
||||
@Prop() dropdownValues?: Array<MultiTextDefinition> = [];
|
||||
@Event({ bubbles: true }) valueChanged: EventEmitter<Array<string | MultiTextDefinition>>;
|
||||
@State() currentValues?: Array<MultiTextDefinition> = [];
|
||||
@State() dropdownTags?: Array<MultiTextDefinition> = [];
|
||||
@Prop() values?: Array<string | SelectListItem> = [];
|
||||
@Prop() dropdownValues?: Array<SelectListItem> = [];
|
||||
@Event({ bubbles: true }) valueChanged: EventEmitter<Array<string | SelectListItem>>;
|
||||
@State() currentValues?: Array<SelectListItem> = [];
|
||||
@State() dropdownTags?: Array<SelectListItem> = [];
|
||||
|
||||
@Watch('values')
|
||||
valuesChangedHandler(newValue: Array<string | MultiTextDefinition>) {
|
||||
let values: Array<MultiTextDefinition> = [];
|
||||
valuesChangedHandler(newValue: Array<string | SelectListItem>) {
|
||||
let values: Array<SelectListItem> = [];
|
||||
|
||||
newValue.forEach(value => {
|
||||
this.dropdownValues.forEach(tag => {
|
||||
|
|
@ -33,7 +33,7 @@ export class ElsaInputTagsDropdown {
|
|||
|
||||
componentWillLoad() {
|
||||
this.dropdownTags = this.dropdownValues;
|
||||
let values: Array<MultiTextDefinition> = [];
|
||||
let values: Array<SelectListItem> = [];
|
||||
|
||||
this.values.forEach(value => {
|
||||
this.dropdownValues.forEach(tag => {
|
||||
|
|
@ -52,7 +52,7 @@ export class ElsaInputTagsDropdown {
|
|||
e.preventDefault();
|
||||
|
||||
const input = e.target as HTMLSelectElement;
|
||||
const currentTag: MultiTextDefinition = {
|
||||
const currentTag: SelectListItem = {
|
||||
text: input.options[input.selectedIndex].text.trim(),
|
||||
value: input.value
|
||||
}
|
||||
|
|
@ -60,7 +60,7 @@ export class ElsaInputTagsDropdown {
|
|||
if (currentTag.value.length == 0)
|
||||
return;
|
||||
|
||||
const values: Array<MultiTextDefinition> = [...this.currentValues];
|
||||
const values: Array<SelectListItem> = [...this.currentValues];
|
||||
values.push(currentTag);
|
||||
this.currentValues = values.distinct();
|
||||
input.value = "Add";
|
||||
|
|
@ -68,7 +68,7 @@ export class ElsaInputTagsDropdown {
|
|||
await this.valueChanged.emit(values);
|
||||
}
|
||||
|
||||
async onDeleteTagClick(e: any, currentTag: MultiTextDefinition) {
|
||||
async onDeleteTagClick(e: any, currentTag: SelectListItem) {
|
||||
e.preventDefault();
|
||||
|
||||
this.currentValues = this.currentValues.filter(tag => tag.value !== currentTag.value);
|
||||
|
|
@ -77,7 +77,7 @@ export class ElsaInputTagsDropdown {
|
|||
}
|
||||
|
||||
render() {
|
||||
let values: Array<MultiTextDefinition> = this.currentValues || [];
|
||||
let values: Array<SelectListItem> = this.currentValues || [];
|
||||
|
||||
if (!Array.isArray(values))
|
||||
values = [];
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import {Component, h, Prop, State} from '@stencil/core';
|
||||
import {ActivityDefinitionProperty, ActivityPropertyDescriptor, SyntaxNames} from "../../../../models";
|
||||
import {parseJson} from "../../../../utils/utils";
|
||||
import {getSelectListItems} from "../../../../utils/select-list-items";
|
||||
import Tunnel from "../../../../data/workflow-editor";
|
||||
import {ElsaDropdownProperty} from "../elsa-dropdown-property/elsa-dropdown-property";
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-check-list-property',
|
||||
|
|
@ -11,8 +14,11 @@ export class ElsaCheckListProperty {
|
|||
|
||||
@Prop() propertyDescriptor: ActivityPropertyDescriptor;
|
||||
@Prop() propertyModel: ActivityDefinitionProperty;
|
||||
@Prop({mutable: true}) serverUrl: string;
|
||||
@State() currentValue?: string;
|
||||
|
||||
monacoEditor: HTMLElsaMonacoElement;
|
||||
items: any[];
|
||||
|
||||
async componentWillLoad() {
|
||||
this.currentValue = this.propertyModel.expressions[SyntaxNames.Json] || '[]';
|
||||
|
|
@ -37,11 +43,15 @@ export class ElsaCheckListProperty {
|
|||
this.currentValue = e.detail;
|
||||
}
|
||||
|
||||
async componentWillRender(){
|
||||
this.items = await getSelectListItems(this.serverUrl, this.propertyDescriptor);
|
||||
}
|
||||
|
||||
render() {
|
||||
const propertyDescriptor = this.propertyDescriptor;
|
||||
const propertyModel = this.propertyModel;
|
||||
const fieldId = propertyDescriptor.name;
|
||||
const options = propertyDescriptor.options as Array<any>;
|
||||
const items = this.items;
|
||||
const values = parseJson(this.currentValue) || [];
|
||||
|
||||
return (
|
||||
|
|
@ -51,11 +61,11 @@ export class ElsaCheckListProperty {
|
|||
editor-height="2.75em"
|
||||
single-line={true}>
|
||||
<div class="max-w-lg space-y-3 my-4">
|
||||
{options.map((option, index) => {
|
||||
{items.map((item, index) => {
|
||||
const inputId = `${fieldId}_${index}`;
|
||||
const optionIsString = typeof(option) == 'string';
|
||||
const value = optionIsString ? option : option.value;
|
||||
const text = optionIsString ? option : option.text;
|
||||
const optionIsString = typeof(item) == 'string';
|
||||
const value = optionIsString ? item : item.value;
|
||||
const text = optionIsString ? item : item.text;
|
||||
const isSelected = values.findIndex(x => x == value) >= 0;
|
||||
|
||||
return (
|
||||
|
|
@ -74,3 +84,5 @@ export class ElsaCheckListProperty {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
Tunnel.injectProps(ElsaCheckListProperty, ['serverUrl']);
|
||||
|
|
@ -2,6 +2,7 @@ import {Component, h, Prop, State} from '@stencil/core';
|
|||
import {ActivityDefinitionProperty, ActivityPropertyDescriptor, RuntimeSelectListItemsProviderSettings, SelectListItem, SyntaxNames} from "../../../../models";
|
||||
import Tunnel from "../../../../data/workflow-editor";
|
||||
import {createElsaClient} from "../../../../services/elsa-client";
|
||||
import {getSelectListItems} from "../../../../utils/select-list-items";
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-dropdown-property',
|
||||
|
|
@ -33,22 +34,7 @@ export class ElsaDropdownProperty {
|
|||
}
|
||||
|
||||
async componentWillRender(){
|
||||
const propertyDescriptor = this.propertyDescriptor;
|
||||
const options = propertyDescriptor.options;
|
||||
let items = [];
|
||||
|
||||
if (!!options.runtimeSelectListItemsProviderType) {
|
||||
items = await this.fetchRuntimeItems(options);
|
||||
} else {
|
||||
items = options as Array<any> || [];
|
||||
}
|
||||
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
async fetchRuntimeItems(options: RuntimeSelectListItemsProviderSettings): Promise<Array<SelectListItem>>{
|
||||
const elsaClient = createElsaClient(this.serverUrl);
|
||||
return await elsaClient.designerApi.runtimeSelectItemsApi.get(options.runtimeSelectListItemsProviderType, options.context || {});
|
||||
this.items = await getSelectListItems(this.serverUrl, this.propertyDescriptor);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import {Component, h, Prop, State} from '@stencil/core';
|
||||
import {ActivityDefinitionProperty, ActivityPropertyDescriptor, SyntaxNames, MultiTextDefinition} from "../../../../models";
|
||||
import {ActivityDefinitionProperty, ActivityPropertyDescriptor, SyntaxNames, SelectListItem} from "../../../../models";
|
||||
import {parseJson} from "../../../../utils/utils";
|
||||
import Tunnel from "../../../../data/workflow-editor";
|
||||
import {getSelectListItems} from "../../../../utils/select-list-items";
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-multi-text-property',
|
||||
|
|
@ -11,15 +13,20 @@ export class ElsaMultiTextProperty {
|
|||
|
||||
@Prop() propertyDescriptor: ActivityPropertyDescriptor;
|
||||
@Prop() propertyModel: ActivityDefinitionProperty;
|
||||
@Prop({mutable: true}) serverUrl: string;
|
||||
@State() currentValue?: string;
|
||||
|
||||
items: any[];
|
||||
|
||||
async componentWillLoad() {
|
||||
this.currentValue = this.propertyModel.expressions[SyntaxNames.Json] || '[]';
|
||||
}
|
||||
|
||||
onValueChanged(newValue: Array<string | MultiTextDefinition>) {
|
||||
onValueChanged(newValue: Array<string | number | boolean | SelectListItem>) {
|
||||
const newValues = newValue.map(dropdown => {
|
||||
if (typeof dropdown === 'string') return dropdown;
|
||||
if (typeof dropdown === 'number') return dropdown.toString();
|
||||
if (typeof dropdown === 'boolean') return dropdown.toString();
|
||||
|
||||
return dropdown.value;
|
||||
})
|
||||
|
|
@ -32,13 +39,17 @@ export class ElsaMultiTextProperty {
|
|||
this.currentValue = e.detail;
|
||||
}
|
||||
|
||||
createKeyValueOptions(options: Array<MultiTextDefinition>) {
|
||||
createKeyValueOptions(options: Array<SelectListItem>) {
|
||||
if (options === null)
|
||||
return options;
|
||||
|
||||
return options.map(option => typeof option === 'string' ? { text: option, value: option } : option);
|
||||
}
|
||||
|
||||
async componentWillRender(){
|
||||
this.items = await getSelectListItems(this.serverUrl, this.propertyDescriptor);
|
||||
}
|
||||
|
||||
render() {
|
||||
const propertyDescriptor = this.propertyDescriptor;
|
||||
const propertyModel = this.propertyModel;
|
||||
|
|
@ -46,9 +57,9 @@ export class ElsaMultiTextProperty {
|
|||
const fieldId = propertyName;
|
||||
const fieldName = propertyName;
|
||||
const values = parseJson(this.currentValue);
|
||||
propertyDescriptor.options = propertyDescriptor.options || null;
|
||||
const items = this.items;
|
||||
const valueType = propertyDescriptor.options !== null ? 'dropdown' : 'multi-text';
|
||||
const propertyOptions = this.createKeyValueOptions(propertyDescriptor.options);
|
||||
const propertyOptions = this.createKeyValueOptions(items);
|
||||
|
||||
const elsaInputTags = valueType === 'multi-text' ?
|
||||
<elsa-input-tags values={values} fieldId={fieldId} fieldName={fieldName} onValueChanged={e => this.onValueChanged(e.detail)} /> :
|
||||
|
|
@ -65,3 +76,5 @@ export class ElsaMultiTextProperty {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
Tunnel.injectProps(ElsaMultiTextProperty, ['serverUrl']);
|
||||
|
|
|
|||
|
|
@ -168,11 +168,6 @@ export interface ConnectionDefinitionMapped {
|
|||
outcome: string;
|
||||
}
|
||||
|
||||
export interface MultiTextDefinition {
|
||||
text: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface ActivityDefinitionProperty {
|
||||
name: string;
|
||||
syntax?: string;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
import {ActivityPropertyDescriptor, RuntimeSelectListItemsProviderSettings, SelectListItem} from "../models";
|
||||
import {createElsaClient, ElsaClient} from "../services/elsa-client";
|
||||
|
||||
async function fetchRuntimeItems(serverUrl: string, options: RuntimeSelectListItemsProviderSettings): Promise<Array<SelectListItem>> {
|
||||
const elsaClient = createElsaClient(serverUrl);
|
||||
return await elsaClient.designerApi.runtimeSelectItemsApi.get(options.runtimeSelectListItemsProviderType, options.context || {});
|
||||
}
|
||||
|
||||
export async function getSelectListItems(serverUrl: string, propertyDescriptor: ActivityPropertyDescriptor): Promise<Array<SelectListItem>> {
|
||||
const options = propertyDescriptor.options;
|
||||
let items = [];
|
||||
|
||||
if (!!options.runtimeSelectListItemsProviderType) {
|
||||
items = await fetchRuntimeItems(serverUrl, options);
|
||||
} else {
|
||||
items = options as Array<any> || [];
|
||||
}
|
||||
|
||||
return items || [];
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
|
|
@ -15,6 +16,13 @@ namespace Elsa.Samples.Server.Host.Activities
|
|||
[Action]
|
||||
public class VehicleActivity : Activity, IActivityPropertyOptionsProvider, IRuntimeSelectListItemsProvider
|
||||
{
|
||||
private Random _random;
|
||||
|
||||
public VehicleActivity()
|
||||
{
|
||||
_random = new Random();
|
||||
}
|
||||
|
||||
[ActivityProperty(
|
||||
UIHint = ActivityPropertyUIHints.Dropdown,
|
||||
OptionsProvider = typeof(VehicleActivity),
|
||||
|
|
@ -23,15 +31,18 @@ namespace Elsa.Samples.Server.Host.Activities
|
|||
)]
|
||||
public string? Brand { get; set; }
|
||||
|
||||
public object GetOptions(PropertyInfo property) => new RuntimeSelectListItemsProviderSettings(GetType());
|
||||
public object GetOptions(PropertyInfo property) => new RuntimeSelectListItemsProviderSettings(GetType(), new VehicleContext(_random.Next(100)));
|
||||
|
||||
public ValueTask<IEnumerable<SelectListItem>> GetItemsAsync(object? context, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var brands = new[] { "BMW", "Peugot", "Tesla" };
|
||||
var vehicleContext = (VehicleContext) context!;
|
||||
var brands = new[] { "BMW", "Peugot", "Tesla", vehicleContext.RandomNumber.ToString() };
|
||||
var items = brands.Select(x => new SelectListItem(x)).ToList();
|
||||
return new ValueTask<IEnumerable<SelectListItem>>(items);
|
||||
}
|
||||
|
||||
protected override IActivityExecutionResult OnExecute() => Done(Brand);
|
||||
}
|
||||
|
||||
public record VehicleContext(int RandomNumber);
|
||||
}
|
||||
|
|
@ -3,9 +3,11 @@ using System.Linq;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Design;
|
||||
using Elsa.Serialization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
|
||||
namespace Elsa.Server.Api.Endpoints.Designer.RuntimeSelectListItems
|
||||
|
|
@ -17,10 +19,12 @@ namespace Elsa.Server.Api.Endpoints.Designer.RuntimeSelectListItems
|
|||
public class Get : Controller
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IContentSerializer _contentSerializer;
|
||||
|
||||
public Get(IServiceProvider serviceProvider)
|
||||
public Get(IServiceProvider serviceProvider, IContentSerializer contentSerializer)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_contentSerializer = contentSerializer;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
|
|
@ -31,13 +35,23 @@ namespace Elsa.Server.Api.Endpoints.Designer.RuntimeSelectListItems
|
|||
OperationId = "Designer.RuntimeSelectListItems.Get",
|
||||
Tags = new[] { "Designer.RuntimeSelectListItems" })
|
||||
]
|
||||
public async Task<IActionResult> Handle(string providerTypeName, object? context = default, CancellationToken cancellationToken = default)
|
||||
public async Task<IActionResult> Handle([FromBody]RuntimeSelectListItemsContextHolder model, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var type = Type.GetType(providerTypeName)!;
|
||||
var provider = (IRuntimeSelectListItemsProvider)ActivatorUtilities.GetServiceOrCreateInstance(_serviceProvider, type);
|
||||
var type = Type.GetType(model.ProviderTypeName)!;
|
||||
var provider = (IRuntimeSelectListItemsProvider) ActivatorUtilities.GetServiceOrCreateInstance(_serviceProvider, type);
|
||||
var context = model?.Context;
|
||||
var items = (await provider.GetItemsAsync(context, cancellationToken)).ToList();
|
||||
var serializerSettings = _contentSerializer.GetSettings();
|
||||
|
||||
return Ok(items);
|
||||
return Json(items, serializerSettings);
|
||||
}
|
||||
}
|
||||
|
||||
public record RuntimeSelectListItemsContextHolder
|
||||
{
|
||||
[FromRoute] public string ProviderTypeName { get; set; } = default!;
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.All)]
|
||||
public object? Context { get; set; }
|
||||
};
|
||||
}
|
||||
Loading…
Reference in a new issue