Activity picker + editor flows
This commit is contained in:
parent
32b349625f
commit
80912563d8
|
|
@ -1,17 +1,20 @@
|
|||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Elsa.Client.Models
|
||||
{
|
||||
[DataContract]
|
||||
public class ActivityDefinition
|
||||
{
|
||||
public string ActivityId { get; set; } = default!;
|
||||
public string Type { get; set; } = default!;
|
||||
public string? Name { get; set; }
|
||||
public string? DisplayName { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public int? Left { get; set; }
|
||||
public int? Top { get; set; }
|
||||
public bool PersistWorkflow { get; set; }
|
||||
public bool LoadWorkflowContext { get; set; }
|
||||
public bool SaveWorkflowContext { get; set; }
|
||||
public ActivityDefinitionProperties Properties { get; set; } = new ActivityDefinitionProperties();
|
||||
[DataMember(Order = 1)] public string ActivityId { get; set; } = default!;
|
||||
[DataMember(Order = 2)] public string Type { get; set; } = default!;
|
||||
[DataMember(Order = 3)] public string? Name { get; set; }
|
||||
[DataMember(Order = 4)] public string? DisplayName { get; set; }
|
||||
[DataMember(Order = 5)] public string? Description { get; set; }
|
||||
[DataMember(Order = 6)] public int? Left { get; set; }
|
||||
[DataMember(Order = 7)] public int? Top { get; set; }
|
||||
[DataMember(Order = 8)] public bool PersistWorkflow { get; set; }
|
||||
[DataMember(Order = 9)] public bool LoadWorkflowContext { get; set; }
|
||||
[DataMember(Order = 10)] public bool SaveWorkflowContext { get; set; }
|
||||
[DataMember(Order = 11)] public ActivityDefinitionProperties Properties { get; set; } = new ActivityDefinitionProperties();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Elsa.Client.Models
|
||||
{
|
||||
[DataContract]
|
||||
public class ActivityDefinitionProperties : Dictionary<string, ActivityDefinitionPropertyValue>
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Elsa.Client.Models
|
||||
{
|
||||
[DataContract]
|
||||
public class CompositeActivityDefinition : ActivityDefinition
|
||||
{
|
||||
public CompositeActivityDefinition()
|
||||
|
|
@ -10,8 +12,8 @@ namespace Elsa.Client.Models
|
|||
Connections = new System.Collections.Generic.List<ConnectionDefinition>();
|
||||
Type = "CompositeActivity";
|
||||
}
|
||||
|
||||
public ICollection<ActivityDefinition> Activities { get; set; }
|
||||
public ICollection<ConnectionDefinition> Connections { get; set; }
|
||||
|
||||
[DataMember(Order = 1)] public ICollection<ActivityDefinition> Activities { get; set; }
|
||||
[DataMember(Order = 2)] public ICollection<ConnectionDefinition> Connections { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Elsa.Client.Models
|
||||
{
|
||||
[DataContract]
|
||||
public class ConnectionDefinition
|
||||
{
|
||||
public ConnectionDefinition()
|
||||
|
|
@ -12,9 +15,9 @@ namespace Elsa.Client.Models
|
|||
TargetActivityId = targetActivityId;
|
||||
Outcome = outcome;
|
||||
}
|
||||
|
||||
public string? SourceActivityId { get; set; }
|
||||
public string? TargetActivityId { get; set; }
|
||||
public string? Outcome { get; set; }
|
||||
|
||||
[DataMember(Order = 1)] public string? SourceActivityId { get; set; }
|
||||
[DataMember(Order = 2)] public string? TargetActivityId { get; set; }
|
||||
[DataMember(Order = 3)] public string? Outcome { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Elsa.Client.Models
|
||||
{
|
||||
[DataContract]
|
||||
public class Variables
|
||||
{
|
||||
public Variables()
|
||||
|
|
@ -18,7 +20,7 @@ namespace Elsa.Client.Models
|
|||
Data = data;
|
||||
}
|
||||
|
||||
public IDictionary<string, object?> Data { get; set; }
|
||||
[DataMember(Order = 1)]public IDictionary<string, object?> Data { get; set; }
|
||||
|
||||
public object? Get(string name) => Has(name) ? Data[name] : default;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Elsa.Client.Models
|
||||
{
|
||||
[DataContract]
|
||||
public class WorkflowContextOptions
|
||||
{
|
||||
public Type ContextType { get; set; } = default!;
|
||||
public WorkflowContextFidelity ContextFidelity { get; set; }
|
||||
[DataMember(Order = 1)] public Type ContextType { get; set; } = default!;
|
||||
[DataMember(Order = 2)] public WorkflowContextFidelity ContextFidelity { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
namespace Elsa.Client.Models
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Elsa.Client.Models
|
||||
{
|
||||
[DataContract]
|
||||
public class WorkflowDefinition : CompositeActivityDefinition
|
||||
{
|
||||
public WorkflowDefinition()
|
||||
|
|
@ -8,17 +11,17 @@
|
|||
Type = "Workflow";
|
||||
}
|
||||
|
||||
public int Id { get; set; }
|
||||
public string WorkflowDefinitionId { get; set; } = default!;
|
||||
public string WorkflowDefinitionVersionId { get; set; } = default!;
|
||||
public int Version { get; set; }
|
||||
public Variables? Variables { get; set; }
|
||||
public WorkflowContextOptions? ContextOptions { get; set; }
|
||||
public bool IsSingleton { get; set; }
|
||||
public WorkflowPersistenceBehavior PersistenceBehavior { get; set; }
|
||||
public bool DeleteCompletedInstances { get; set; }
|
||||
public bool IsEnabled { get; set; }
|
||||
public bool IsPublished { get; set; }
|
||||
public bool IsLatest { get; set; }
|
||||
[DataMember(Order = 1)] public int Id { get; set; }
|
||||
[DataMember(Order = 2)] public string WorkflowDefinitionId { get; set; } = default!;
|
||||
[DataMember(Order = 3)] public string WorkflowDefinitionVersionId { get; set; } = default!;
|
||||
[DataMember(Order = 4)] public int Version { get; set; }
|
||||
[DataMember(Order = 5)] public Variables? Variables { get; set; }
|
||||
[DataMember(Order = 6)] public WorkflowContextOptions? ContextOptions { get; set; }
|
||||
[DataMember(Order = 7)] public bool IsSingleton { get; set; }
|
||||
[DataMember(Order = 8)] public WorkflowPersistenceBehavior PersistenceBehavior { get; set; }
|
||||
[DataMember(Order = 9)] public bool DeleteCompletedInstances { get; set; }
|
||||
[DataMember(Order = 10)] public bool IsEnabled { get; set; }
|
||||
[DataMember(Order = 11)] public bool IsPublished { get; set; }
|
||||
[DataMember(Order = 12)] public bool IsLatest { get; set; }
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -7,6 +7,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.8.26" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Threading.Tasks;
|
||||
using ElsaDashboard.Application.Models;
|
||||
using ElsaDashboard.Application.Services;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
|
|
@ -6,6 +7,29 @@ namespace ElsaDashboard.Application.Extensions
|
|||
{
|
||||
public static class FlyoutPanelServiceExtensions
|
||||
{
|
||||
public static ValueTask ShowAsync<T>(this IFlyoutPanelService service, string title) where T : ComponentBase => service.ShowAsync(typeof(T), title);
|
||||
public static ValueTask ShowAsync<T>(this IFlyoutPanelService service, string title) where T : ComponentBase =>
|
||||
service.ShowAsync<T>(new FlyoutPanelOptions
|
||||
{
|
||||
Title = title
|
||||
});
|
||||
|
||||
|
||||
|
||||
public static ValueTask ShowAsync<T>(this IFlyoutPanelService service, string title, object parameters, params ButtonDescriptor[] buttons) where T : ComponentBase =>
|
||||
service.ShowAsync<T>(new FlyoutPanelOptions
|
||||
{
|
||||
Title = title,
|
||||
Buttons = buttons,
|
||||
Parameters = parameters.ToDictionary()
|
||||
});
|
||||
|
||||
public static ValueTask ShowAsync<T>(this IFlyoutPanelService service, FlyoutPanelOptions options) where T : ComponentBase =>
|
||||
service.ShowAsync(new FlyoutPanelOptions
|
||||
{
|
||||
ContentComponentType = typeof(T),
|
||||
Buttons = options.Buttons,
|
||||
Parameters = options.Parameters,
|
||||
Title = options.Title
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace ElsaDashboard.Application.Extensions
|
||||
{
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
public static Dictionary<string, object?> ToDictionary(this object value) => value.GetType().GetProperties().ToDictionary(x => x.Name, x => x.GetValue(value, null));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using Elsa.Client.Models;
|
||||
|
||||
namespace ElsaDashboard.Application.Models
|
||||
{
|
||||
public class ActivityDescriptorSelectedEventArgs : EventArgs
|
||||
{
|
||||
public ActivityDescriptor ActivityDescriptor { get; }
|
||||
|
||||
public ActivityDescriptorSelectedEventArgs(ActivityDescriptor activityDescriptor)
|
||||
{
|
||||
ActivityDescriptor = activityDescriptor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace ElsaDashboard.Application.Pages.Designer
|
||||
namespace ElsaDashboard.Application.Models
|
||||
{
|
||||
public enum ActivityTraitFilter
|
||||
{
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using ElsaDashboard.Application.Services;
|
||||
|
||||
namespace ElsaDashboard.Application.Models
|
||||
{
|
||||
public class ButtonClickEventArgs : EventArgs
|
||||
{
|
||||
public ButtonClickEventArgs(ButtonDescriptor button)
|
||||
{
|
||||
Button = button;
|
||||
}
|
||||
|
||||
public ButtonDescriptor Button { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ElsaDashboard.Application.Services;
|
||||
using ElsaDashboard.Application.Shared;
|
||||
|
||||
namespace ElsaDashboard.Application.Models
|
||||
{
|
||||
public class FlyoutPanelOptions
|
||||
{
|
||||
public Type ContentComponentType { get; set; } = typeof(FlyoutPanelPlaceholder);
|
||||
public ICollection<ButtonDescriptor> Buttons { get; set; } = new List<ButtonDescriptor>();
|
||||
public string? Title { get; set; }
|
||||
public IDictionary<string, object?> Parameters { get; set; } = new Dictionary<string, object?>();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,85 +1,25 @@
|
|||
<div class="flex-1">
|
||||
<div class="py-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
||||
<!-- Project name -->
|
||||
@using Humanizer
|
||||
<div class="py-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
||||
|
||||
@foreach (var property in ActivityDescriptor.Properties)
|
||||
{
|
||||
var controlId = property.Name.ToLowerInvariant().Underscore();
|
||||
|
||||
<div class="space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:py-5">
|
||||
<div>
|
||||
<label for="project_name" class="block text-sm font-medium leading-5 text-gray-900 sm:mt-px sm:pt-2">
|
||||
Project name
|
||||
<label for="@controlId" class="block text-sm font-medium leading-5 text-gray-900 sm:mt-px sm:pt-2">
|
||||
@property.Label
|
||||
</label>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<div class="rounded-md shadow-sm">
|
||||
<input id="project_name" class="form-input block w-full sm:text-sm sm:leading-5" placeholder="">
|
||||
<input id="@controlId" class="form-input block w-full sm:text-sm sm:leading-5" placeholder="">
|
||||
</div>
|
||||
@if (!string.IsNullOrWhiteSpace(property.Hint))
|
||||
{
|
||||
<p class="mt-2 text-sm text-gray-500">@property.Hint</p>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Project description -->
|
||||
<div class="space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:py-5">
|
||||
<div>
|
||||
<label for="project_description" class="block text-sm font-medium leading-5 text-gray-900 sm:mt-px sm:pt-2">
|
||||
Description
|
||||
</label>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<div class="flex rounded-md shadow-sm">
|
||||
<textarea id="project_description" rows="3" class="form-textarea block w-full transition duration-150 ease-in-out sm:text-sm sm:leading-5"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Team members -->
|
||||
<div class="space-y-2 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-center sm:px-6 sm:py-5">
|
||||
<div>
|
||||
<h3 class="text-sm font-medium leading-5 text-gray-900">
|
||||
Team Members
|
||||
</h3>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<div class="flex space-x-2">
|
||||
|
||||
<a href="#" class="flex-shrink-0 rounded-full hover:opacity-75 focus:outline-none focus:shadow-outline transition ease-in-out duration-150">
|
||||
<img class="inline-block h-8 w-8 rounded-full" src="https://images.unsplash.com/photo-1491528323818-fdd1faba62cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="Tom Warner">
|
||||
</a>
|
||||
|
||||
<a href="#" class="flex-shrink-0 rounded-full hover:opacity-75 focus:outline-none focus:shadow-outline transition ease-in-out duration-150">
|
||||
<img class="inline-block h-8 w-8 rounded-full" src="https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="Tom Warner">
|
||||
</a>
|
||||
|
||||
<a href="#" class="flex-shrink-0 rounded-full hover:opacity-75 focus:outline-none focus:shadow-outline transition ease-in-out duration-150">
|
||||
<img class="inline-block h-8 w-8 rounded-full" src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="Tom Warner">
|
||||
</a>
|
||||
|
||||
<a href="#" class="flex-shrink-0 rounded-full hover:opacity-75 focus:outline-none focus:shadow-outline transition ease-in-out duration-150">
|
||||
<img class="inline-block h-8 w-8 rounded-full" src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="Tom Warner">
|
||||
</a>
|
||||
|
||||
<a href="#" class="flex-shrink-0 rounded-full hover:opacity-75 focus:outline-none focus:shadow-outline transition ease-in-out duration-150">
|
||||
<img class="inline-block h-8 w-8 rounded-full" src="https://images.unsplash.com/photo-1586297098710-0382a496c814?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="Tom Warner">
|
||||
</a>
|
||||
|
||||
|
||||
<button type="button" class="flex-shrink-0 inline-flex h-8 w-8 items-center justify-center rounded-full border-2 border-dashed border-gray-200 text-gray-400 hover:text-gray-500 hover:border-gray-300 focus:text-gray-500 focus:border-gray-300 focus:outline-none transition ease-in-out duration-150" aria-label="Add team member">
|
||||
<svg class="h-5 w-5" x-description="Heroicon name: plus" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M10 5a1 1 0 011 1v3h3a1 1 0 110 2h-3v3a1 1 0 11-2 0v-3H6a1 1 0 110-2h3V6a1 1 0 011-1z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-shrink-0 px-4 border-t border-gray-200 py-5 sm:px-6">
|
||||
<div class="space-x-3 flex justify-end">
|
||||
<span class="inline-flex rounded-md shadow-sm">
|
||||
<button type="button" class="py-2 px-4 border border-gray-300 rounded-md text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800 transition duration-150 ease-in-out">
|
||||
Cancel
|
||||
</button>
|
||||
</span>
|
||||
<span class="inline-flex rounded-md shadow-sm">
|
||||
<button type="submit" class="inline-flex justify-center py-2 px-4 border border-transparent text-sm leading-5 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition duration-150 ease-in-out">
|
||||
Create
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
|
@ -5,6 +5,6 @@ namespace ElsaDashboard.Application.Pages.Designer
|
|||
{
|
||||
partial class ActivityEditor
|
||||
{
|
||||
//[Parameter] public ActivityDescriptor ActivityDescriptor { get; set; } = default!;
|
||||
[Parameter] public ActivityDescriptor ActivityDescriptor { get; set; } = default!;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +1,61 @@
|
|||
<div class="flex-1">
|
||||
<div class="p-6">
|
||||
<div class="relative rounded-md shadow-sm">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<svg class="h-6 w-6 text-gray-400" width="24" height="24" viewBox="0 0 24 24"
|
||||
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||
<circle cx="10" cy="10" r="7"/>
|
||||
<line x1="21" y1="21" x2="15" y2="15"/>
|
||||
</svg>
|
||||
</div>
|
||||
<input type="text" @bind="ActivitySearchText" @bind:event="oninput" class="form-input block w-full pl-10 sm:text-sm sm:leading-5" placeholder="Search activities">
|
||||
<div class="p-6">
|
||||
<div class="relative rounded-md shadow-sm">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<svg class="h-6 w-6 text-gray-400" width="24" height="24" viewBox="0 0 24 24"
|
||||
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||
<circle cx="10" cy="10" r="7"/>
|
||||
<line x1="21" y1="21" x2="15" y2="15"/>
|
||||
</svg>
|
||||
</div>
|
||||
<input type="text" @bind="ActivitySearchText" @bind:event="oninput" class="form-input block w-full pl-10 sm:text-sm sm:leading-5" placeholder="Search activities">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-b border-gray-200">
|
||||
<div class="px-6">
|
||||
<nav class="-mb-px flex space-x-6" x-descriptions="Tab component">
|
||||
@foreach (var activityTypeFilter in ActivityTraitFilters)
|
||||
<div class="border-b border-gray-200">
|
||||
<div class="px-6">
|
||||
<nav class="-mb-px flex space-x-6" x-descriptions="Tab component">
|
||||
@foreach (var activityTypeFilter in ActivityTraitFilters)
|
||||
{
|
||||
var activeClass = activityTypeFilter == SelectedActivityTraitFilter ? "border-blue-500 text-blue-600 focus:text-blue-800 focus:border-blue-700" : "border-transparent text-gray-500 focus:text-gray-700 focus:border-gray-300";
|
||||
<a href="#" @onclick:preventDefault @onclick="@(() => OnActivityTypeFilterClick(activityTypeFilter))" class="whitespace-no-wrap pb-4 px-1 border-b-2 font-medium text-sm leading-5 focus:outline-none @activeClass" aria-current="page">
|
||||
@activityTypeFilter.ToString()
|
||||
</a>
|
||||
}
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-6 space-y-6 overflow-y-auto">
|
||||
|
||||
@foreach (var grouping in ActivityGroupings)
|
||||
{
|
||||
<div>
|
||||
<h2>@grouping.Key</h2>
|
||||
|
||||
<ul class="grid grid-cols-1 gap-4 mt-3" x-max="1">
|
||||
@foreach (var activity in grouping)
|
||||
{
|
||||
var activeClass = activityTypeFilter == SelectedActivityTraitFilter ? "border-blue-500 text-blue-600 focus:text-blue-800 focus:border-blue-700" : "border-transparent text-gray-500 focus:text-gray-700 focus:border-gray-300";
|
||||
<a href="#" @onclick:preventDefault @onclick="@(() => OnActivityTypeFilterClick(activityTypeFilter))" class="whitespace-no-wrap pb-4 px-1 border-b-2 font-medium text-sm leading-5 focus:outline-none @activeClass" aria-current="page">
|
||||
@activityTypeFilter.ToString()
|
||||
</a>
|
||||
<li @onclick="(() => OnActivityClick(activity))" class="relative col-span-1 flex shadow-sm rounded-md select-none cursor-pointer">
|
||||
<div class="flex-shrink-0 flex items-center justify-center w-16 bg-blue-600 text-white text-sm leading-5 font-medium rounded-l-md">
|
||||
<svg class="h-10 w-10 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1 flex items-center justify-between border-t border-r border-b border-gray-200 bg-white rounded-r-md">
|
||||
<div class="flex-1 px-4 py-2 text-sm leading-5">
|
||||
<span class="text-gray-900 font-medium hover:text-gray-600 transition ease-in-out duration-150">
|
||||
@activity.DisplayName
|
||||
</span>
|
||||
<p class="text-gray-500">
|
||||
@activity.Description
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
}
|
||||
</nav>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-6 space-y-6 overflow-y-auto">
|
||||
|
||||
@foreach (var grouping in ActivityGroupings)
|
||||
{
|
||||
<div>
|
||||
<h2>@grouping.Key</h2>
|
||||
|
||||
<ul class="grid grid-cols-1 gap-4 mt-3" x-max="1">
|
||||
@foreach (var activity in grouping)
|
||||
{
|
||||
<li @onclick="(() => OnActivityClick(activity))" class="relative col-span-1 flex shadow-sm rounded-md select-none cursor-pointer">
|
||||
<div class="flex-shrink-0 flex items-center justify-center w-16 bg-blue-600 text-white text-sm leading-5 font-medium rounded-l-md">
|
||||
<svg class="h-10 w-10 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1 flex items-center justify-between border-t border-r border-b border-gray-200 bg-white rounded-r-md">
|
||||
<div class="flex-1 px-4 py-2 text-sm leading-5">
|
||||
<span class="text-gray-900 font-medium hover:text-gray-600 transition ease-in-out duration-150">
|
||||
@activity.DisplayName
|
||||
</span>
|
||||
<p class="text-gray-500">
|
||||
@activity.Description
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
|
@ -3,18 +3,16 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Client.Models;
|
||||
using ElsaDashboard.Application.Extensions;
|
||||
using ElsaDashboard.Application.Services;
|
||||
using ElsaDashboard.Application.Models;
|
||||
using ElsaDashboard.Shared.Rpc;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
|
||||
namespace ElsaDashboard.Application.Pages.Designer
|
||||
{
|
||||
partial class ActivityPicker
|
||||
{
|
||||
[Parameter] public EventCallback<ActivityDescriptorSelectedEventArgs> ActivitySelected { get; set; }
|
||||
[Inject] private IActivityService ActivityService { get; set; } = default!;
|
||||
[Inject] private IFlyoutPanelService FlyoutPanelService { get; set; } = default!;
|
||||
private ActivityTraitFilter SelectedActivityTraitFilter { get; set; }
|
||||
private string? ActivitySearchText { get; set; }
|
||||
private ICollection<ActivityTraitFilter> ActivityTraitFilters => new[] { ActivityTraitFilter.All, ActivityTraitFilter.Actions, ActivityTraitFilter.Triggers };
|
||||
|
|
@ -57,13 +55,11 @@ namespace ElsaDashboard.Application.Pages.Designer
|
|||
where
|
||||
(activity.Description ?? "").Contains(searchText, StringComparison.InvariantCultureIgnoreCase) ||
|
||||
(activity.DisplayName ?? "").Contains(searchText, StringComparison.InvariantCultureIgnoreCase) ||
|
||||
activity.Type.Contains(searchText, StringComparison.InvariantCultureIgnoreCase)
|
||||
activity.Type.Contains(searchText, StringComparison.InvariantCultureIgnoreCase) ||
|
||||
activity.Category.Contains(searchText, StringComparison.InvariantCultureIgnoreCase)
|
||||
select activity;
|
||||
}
|
||||
|
||||
private async Task OnActivityClick(ActivityDescriptor activity)
|
||||
{
|
||||
await FlyoutPanelService.ShowAsync<ActivityEditor>(activity.DisplayName);
|
||||
}
|
||||
private Task OnActivityClick(ActivityDescriptor activityDescriptor) => ActivitySelected.InvokeAsync(new ActivityDescriptorSelectedEventArgs(activityDescriptor));
|
||||
}
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
<div class="inline-flex flex flex-col items-center">
|
||||
<button id="start-button" type="button"
|
||||
class="px-6 py-3 border border-transparent text-base leading-6 font-medium rounded-md text-white bg-green-600 hover:bg-green-500 focus:outline-none focus:border-green-700 focus:shadow-outline-green active:bg-green-700 transition ease-in-out duration-150"
|
||||
@onclick="@(async e => await OnStartClick(e))">
|
||||
@onclick="@(async e => await OnStartClick())">
|
||||
Start
|
||||
</button>
|
||||
<div id="start-button-plus" class="mt-6">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Client.Models;
|
||||
using ElsaDashboard.Application.Extensions;
|
||||
using ElsaDashboard.Application.Models;
|
||||
using ElsaDashboard.Application.Services;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
|
|
@ -23,13 +26,36 @@ namespace ElsaDashboard.Application.Pages.Designer
|
|||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if(_designerModule != null!)
|
||||
if (_designerModule != null!)
|
||||
await _designerModule.DisposeAsync();
|
||||
}
|
||||
|
||||
private async ValueTask OnStartClick(MouseEventArgs e)
|
||||
private async ValueTask ClosePanelAsync() => await FlyoutPanelService.HideAsync();
|
||||
|
||||
private async ValueTask ShowActivityPickerAsync()
|
||||
{
|
||||
await FlyoutPanelService.ShowAsync<ActivityPicker>("Activities");
|
||||
await FlyoutPanelService.ShowAsync<ActivityPicker>(
|
||||
"Activities",
|
||||
new { ActivitySelected = new EventCallback<ActivityDescriptorSelectedEventArgs>(this, (Func<ActivityDescriptorSelectedEventArgs, ValueTask>) OnActivityPickedAsync) },
|
||||
new ButtonDescriptor("Cancel", new EventCallback<ButtonClickEventArgs>(this, (Func<ButtonClickEventArgs, ValueTask>) (_ => ClosePanelAsync()))));
|
||||
}
|
||||
|
||||
private async ValueTask AddActivityAsync(ActivityDescriptor activityDescriptor)
|
||||
{
|
||||
await FlyoutPanelService.HideAsync();
|
||||
}
|
||||
|
||||
private async ValueTask OnStartClick() => await ShowActivityPickerAsync();
|
||||
|
||||
private async ValueTask OnActivityPickedAsync(ActivityDescriptorSelectedEventArgs e)
|
||||
{
|
||||
var activityDescriptor = e.ActivityDescriptor;
|
||||
|
||||
await FlyoutPanelService.ShowAsync<ActivityEditor>(
|
||||
activityDescriptor.DisplayName,
|
||||
new { activityDescriptor },
|
||||
new ButtonDescriptor("Cancel", new EventCallback<ButtonClickEventArgs>(this, (Func<ButtonClickEventArgs, ValueTask>) (_ => ShowActivityPickerAsync()))),
|
||||
new ButtonDescriptor("OK", new EventCallback<ButtonClickEventArgs>(this, (Func<ButtonClickEventArgs, ValueTask>) (_ => AddActivityAsync(activityDescriptor))), true));
|
||||
}
|
||||
|
||||
private async ValueTask OnActivityClick(MouseEventArgs e)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
using ElsaDashboard.Application.Models;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace ElsaDashboard.Application.Services
|
||||
{
|
||||
public sealed record ButtonDescriptor
|
||||
{
|
||||
public ButtonDescriptor(string text, EventCallback<ButtonClickEventArgs>? clickHandler = default, bool isPrimary = false)
|
||||
{
|
||||
Text = text;
|
||||
ClickHandler = clickHandler;
|
||||
IsPrimary = isPrimary;
|
||||
}
|
||||
|
||||
public ButtonDescriptor(string text, EventCallback<ButtonClickEventArgs>? clickHandler) : this(text, clickHandler, false)
|
||||
{
|
||||
}
|
||||
|
||||
public string Text { get; }
|
||||
public bool IsPrimary { get; }
|
||||
public EventCallback<ButtonClickEventArgs>? ClickHandler { get; }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using ElsaDashboard.Application.Models;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
|
|
@ -17,22 +18,20 @@ namespace ElsaDashboard.Application.Services
|
|||
|
||||
public event Action? OnShow;
|
||||
public event Action? OnHide;
|
||||
public FlyoutPanelOptions Options { get; private set; } = new();
|
||||
|
||||
public Type? ContentComponentType { get; private set; }
|
||||
public string? Title { get; private set; }
|
||||
|
||||
public async ValueTask ShowAsync(Type contentComponentType, string title)
|
||||
public async ValueTask ShowAsync(FlyoutPanelOptions options)
|
||||
{
|
||||
if (!typeof(ComponentBase).IsAssignableFrom(contentComponentType))
|
||||
throw new ArgumentException($"{contentComponentType!.FullName} must be a Blazor Component");
|
||||
Options = options;
|
||||
|
||||
if (!typeof(ComponentBase).IsAssignableFrom(options.ContentComponentType))
|
||||
throw new ArgumentException($"{options.ContentComponentType.FullName} must be a Blazor Component");
|
||||
|
||||
await InitJSModuleAsync();
|
||||
await _module.InvokeVoidAsync("show");
|
||||
ContentComponentType = contentComponentType;
|
||||
Title = title;
|
||||
OnShow?.Invoke();
|
||||
}
|
||||
|
||||
|
||||
public async ValueTask HideAsync()
|
||||
{
|
||||
await InitJSModuleAsync();
|
||||
|
|
@ -45,7 +44,7 @@ namespace ElsaDashboard.Application.Services
|
|||
if (_module != null!)
|
||||
await _module.DisposeAsync();
|
||||
}
|
||||
|
||||
|
||||
private async Task InitJSModuleAsync()
|
||||
{
|
||||
_module = await _jsRuntime.InvokeAsync<IJSObjectReference>("import", "./_content/ElsaDashboard.Application/flyoutPanel.js");
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using ElsaDashboard.Application.Models;
|
||||
|
||||
namespace ElsaDashboard.Application.Services
|
||||
{
|
||||
|
|
@ -7,9 +8,8 @@ namespace ElsaDashboard.Application.Services
|
|||
{
|
||||
event Action? OnShow;
|
||||
event Action? OnHide;
|
||||
Type? ContentComponentType { get; }
|
||||
string? Title { get; }
|
||||
ValueTask ShowAsync(Type contentComponentType, string title);
|
||||
FlyoutPanelOptions Options { get; }
|
||||
ValueTask ShowAsync(FlyoutPanelOptions options);
|
||||
ValueTask HideAsync();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +1,47 @@
|
|||
<div x-show="$store.flyoutPanel.show" x-data="{}" x-on:keydown.window.escape="$store.flyoutPanel.show = false" class="fixed inset-0 overflow-hidden">
|
||||
@using ElsaDashboard.Application.Services
|
||||
<div x-show="$store.flyoutPanel.show" x-data="{}" x-on:keydown.window.escape="$store.flyoutPanel.show = false" class="fixed inset-0 overflow-hidden">
|
||||
<div class="absolute inset-0 overflow-hidden">
|
||||
<section x-on:click.away="$store.flyoutPanel.show = false" class="absolute inset-y-0 right-0 pl-10 max-w-md md:max-w-full flex sm:pl-16">
|
||||
<div class="w-screen max-w-2xl" x-description="Slide-over panel, show/hide based on slide-over state." x-show="$store.flyoutPanel.show == true" x-transition:enter="transform transition ease-in-out duration-500 sm:duration-700" x-transition:enter-start="translate-x-full" x-transition:enter-end="translate-x-0" x-transition:leave="transform transition ease-in-out duration-500 sm:duration-700" x-transition:leave-start="translate-x-0" x-transition:leave-end="translate-x-full">
|
||||
<div class="h-full flex flex-col bg-white shadow-xl overflow-y-scroll">
|
||||
|
||||
|
||||
<!-- Header -->
|
||||
<header class="p-6">
|
||||
<div class="flex items-start justify-between space-x-3">
|
||||
@if (!string.IsNullOrWhiteSpace(Title))
|
||||
{
|
||||
<h2 class="text-lg leading-7 font-medium text-gray-900">
|
||||
@Title
|
||||
</h2>
|
||||
}
|
||||
<div class="h-7 flex items-center">
|
||||
<button x-on:click="$store.flyoutPanel.show = false" aria-label="Close panel" class="text-gray-400 hover:text-gray-500 transition ease-in-out duration-150">
|
||||
<svg class="h-6 w-6" x-description="Heroicon name: x" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="flex-1">
|
||||
<!-- Header -->
|
||||
<header class="p-6">
|
||||
<div class="flex items-start justify-between space-x-3">
|
||||
@if (!string.IsNullOrWhiteSpace(Title))
|
||||
{
|
||||
<h2 class="text-lg leading-7 font-medium text-gray-900">
|
||||
@Title
|
||||
</h2>
|
||||
}
|
||||
<div class="h-7 flex items-center">
|
||||
<button x-on:click="$store.flyoutPanel.show = false" aria-label="Close panel" class="text-gray-400 hover:text-gray-500 transition ease-in-out duration-150">
|
||||
<svg class="h-6 w-6" x-description="Heroicon name: x" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@if (Content != null)
|
||||
{
|
||||
</header>
|
||||
@Content
|
||||
}
|
||||
else
|
||||
</div>
|
||||
|
||||
@if (Buttons.Any())
|
||||
{
|
||||
<div class="p-6">
|
||||
<p>Loading...</p>
|
||||
<div class="flex-shrink-0 px-4 py-4 space-x-4 flex justify-end">
|
||||
@{ var buttonKey = 0; }
|
||||
@foreach (var button in Buttons)
|
||||
{
|
||||
var styleClass = button.IsPrimary ? "border-transparent text-white bg-blue-600 hover:bg-blue-500 focus:border-blue-700 active:bg-blue-700" : "border-gray-300 text-gray-700 hover:text-gray-500 focus:border-blue-300 active:bg-gray-50 active:text-gray-800";
|
||||
<span @key="@buttonKey" class="inline-flex rounded-md shadow-sm">
|
||||
<button @onclick="async () => await OnButtonClickAsync(button)" type="button" class="inline-flex justify-center py-2 px-4 border rounded-md text-sm leading-5 font-medium focus:outline-none focus:shadow-outline-blue transition duration-150 ease-in-out @styleClass">
|
||||
@button.Text
|
||||
</button>
|
||||
</span>
|
||||
|
||||
buttonKey++;
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
using ElsaDashboard.Application.Services;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using ElsaDashboard.Application.Models;
|
||||
using ElsaDashboard.Application.Services;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
|
||||
namespace ElsaDashboard.Application.Shared
|
||||
{
|
||||
|
|
@ -7,7 +12,8 @@ namespace ElsaDashboard.Application.Shared
|
|||
{
|
||||
[Inject] private IFlyoutPanelService FlyoutPanelService { get; set; } = default!;
|
||||
[Parameter] public string? Title { get; set; }
|
||||
[Parameter] public RenderFragment? Content { get; set; }
|
||||
[Parameter] public RenderFragment Content { get; set; } = default!;
|
||||
[Parameter] public ICollection<ButtonDescriptor> Buttons { get; set; } = new List<ButtonDescriptor>();
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
|
|
@ -16,17 +22,31 @@ namespace ElsaDashboard.Application.Shared
|
|||
|
||||
private async void Update()
|
||||
{
|
||||
var options = FlyoutPanelService.Options;
|
||||
|
||||
await InvokeAsync(() =>
|
||||
{
|
||||
Content = builder =>
|
||||
{
|
||||
builder.OpenComponent(0, FlyoutPanelService.ContentComponentType!);
|
||||
builder.OpenComponent(0, options.ContentComponentType);
|
||||
|
||||
var i = 0;
|
||||
foreach (var (name, value) in options.Parameters)
|
||||
builder.AddAttribute(i++, name, value);
|
||||
|
||||
builder.CloseComponent();
|
||||
};
|
||||
|
||||
Title = FlyoutPanelService.Title;
|
||||
Buttons = options.Buttons;
|
||||
Title = options.Title;
|
||||
StateHasChanged();
|
||||
});
|
||||
}
|
||||
|
||||
private async ValueTask OnButtonClickAsync(ButtonDescriptor button)
|
||||
{
|
||||
if(button.ClickHandler != null)
|
||||
await button.ClickHandler.Value.InvokeAsync(new ButtonClickEventArgs(button));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<div class="p-6">
|
||||
</div>
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Elsa.Client.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using ProtoBuf.Meta;
|
||||
|
||||
namespace ElsaDashboard.Shared.Surrogates
|
||||
|
|
|
|||
Loading…
Reference in a new issue