Skip to content

Commit

Permalink
Merge pull request #21 from EasyAbp/default-state-flag
Browse files Browse the repository at this point in the history
Default process state flag
  • Loading branch information
gdlcf88 authored Jul 3, 2024
2 parents 373e474 + 1e88570 commit bfc8789
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,25 +63,25 @@ protected virtual async Task SeedDemoProcessAsync(DataSeedContext context)
await _userIdUserGroupContributor.CreateGroupKeyAsync(adminUser!.Id.ToString())), now.AddHours(-5));

await _processManager.UpdateStateAsync(process1,
new ProcessStateInfoModel(now.AddHours(-4), "Exporting",
new ProcessStateCustomModel("Loading data",
ProcessStateFlag.Running,
"Loading the data...",
"<b>Loading the data...</b>")));
new UpdateProcessStateModel(now.AddHours(-4), "Exporting",
"Loading data",
ProcessStateFlag.Running,
"Loading the data...",
"<b>Loading the data...</b>"));

await _processManager.UpdateStateAsync(process1,
new ProcessStateInfoModel(now.AddHours(-3), "Exporting",
new ProcessStateCustomModel("Exporting to ZIP",
ProcessStateFlag.Running,
"Exporting to the .zip file...",
"<b>Exporting to the .zip file...</b>")));
new UpdateProcessStateModel(now.AddHours(-3), "Exporting",
"Exporting to ZIP",
ProcessStateFlag.Running,
"Exporting to the .zip file...",
"<b>Exporting to the .zip file...</b>"));

await _processManager.UpdateStateAsync(process1,
new ProcessStateInfoModel(now.AddHours(-2), "Succeeded",
new ProcessStateCustomModel("Export is done!",
ProcessStateFlag.Success,
"Congratulations! Export successful.",
"<b>Congratulations!</b><br/>Everything is done.")));
new UpdateProcessStateModel(now.AddHours(-2), "Succeeded",
"Export is done!",
ProcessStateFlag.Success,
"Congratulations! Export successful.",
"<b>Congratulations!</b><br/>Everything is done."));

await _processRepository.InsertAsync(process1, true);

Expand All @@ -90,11 +90,11 @@ await _processManager.UpdateStateAsync(process1,
await _userIdUserGroupContributor.CreateGroupKeyAsync(adminUser!.Id.ToString())), now);

await _processManager.UpdateStateAsync(process2,
new ProcessStateInfoModel(now.AddHours(-1), "Exporting",
new ProcessStateCustomModel("Loading data",
ProcessStateFlag.Running,
"Loading the data...",
"<b>Loading the data...</b>")));
new UpdateProcessStateModel(now.AddHours(-1), "Exporting",
"Loading data",
ProcessStateFlag.Running,
"Loading the data...",
"<b>Loading the data...</b>"));

await _processRepository.InsertAsync(process2, true);

Expand All @@ -103,18 +103,18 @@ await _processManager.UpdateStateAsync(process2,
await _userIdUserGroupContributor.CreateGroupKeyAsync(adminUser!.Id.ToString())), now);

await _processManager.UpdateStateAsync(process3,
new ProcessStateInfoModel(now.AddHours(-2), "Exporting",
new ProcessStateCustomModel("Loading data",
ProcessStateFlag.Running,
"Loading the data...",
"<b>Loading the data...</b>")));
new UpdateProcessStateModel(now.AddHours(-2), "Exporting",
"Loading data",
ProcessStateFlag.Running,
"Loading the data...",
"<b>Loading the data...</b>"));

await _processManager.UpdateStateAsync(process3,
new ProcessStateInfoModel(now.AddHours(-1), "Failed",
new ProcessStateCustomModel("Failed...",
ProcessStateFlag.Failure,
"Oops, the task failed!",
null)));
new UpdateProcessStateModel(now.AddHours(-1), "Failed",
"Failed...",
ProcessStateFlag.Failure,
"Oops, the task failed!",
null));

await _processRepository.InsertAsync(process3, true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using EasyAbp.ProcessManagement.EntityFrameworkCore;
using EasyAbp.ProcessManagement.MultiTenancy;
using EasyAbp.ProcessManagement.Options;
using EasyAbp.ProcessManagement.Processes;
using EasyAbp.ProcessManagement.Web;
using Microsoft.OpenApi.Models;
using Volo.Abp;
Expand Down Expand Up @@ -89,11 +90,16 @@ public override void ConfigureServices(ServiceConfigurationContext context)
Configure<ProcessManagementOptions>(options =>
{
var definition = new ProcessDefinition("FakeExport", "Fake export")
.AddState(new ProcessStateDefinition("Ready", "Ready", null))
.AddState(new ProcessStateDefinition("FailedToStartExporting", "Failed", "Ready"))
.AddState(new ProcessStateDefinition("Exporting", "Exporting", "Ready"))
.AddState(new ProcessStateDefinition("ExportFailed", "Failed", "Exporting"))
.AddState(new ProcessStateDefinition("Succeeded", "Succeeded", "Exporting"));
.AddState(new ProcessStateDefinition(
"Ready", "Ready", null, ProcessStateFlag.Information))
.AddState(new ProcessStateDefinition(
"FailedToStartExporting", "Failed", "Ready", ProcessStateFlag.Failure))
.AddState(new ProcessStateDefinition(
"Exporting", "Exporting", "Ready", ProcessStateFlag.Running))
.AddState(new ProcessStateDefinition(
"ExportFailed", "Failed", "Exporting", ProcessStateFlag.Failure))
.AddState(new ProcessStateDefinition(
"Succeeded", "Succeeded", "Exporting", ProcessStateFlag.Success));

options.AddOrUpdateProcessDefinition(definition);
});
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ namespace EasyAbp.ProcessManagement.Processes;

public enum ProcessStateFlag
{
Unspecified,
Information,
Success,
Failure,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using EasyAbp.ProcessManagement.Processes;
using Volo.Abp;

namespace EasyAbp.ProcessManagement.Options;
Expand All @@ -16,6 +17,13 @@ public class ProcessStateDefinition
/// </summary>
public string? DisplayName { get; }

/// <summary>
/// The default state flag.
/// This flag is converted to a state icon and displayed on the UI.
/// For example, when the flag is Warning, the UI shows ⚠️.
/// </summary>
public ProcessStateFlag DefaultStateFlag { get; }

/// <summary>
/// Name of the father state. Stages can only transition from their father state.
/// If null, this state is the initial state. A process can have only one initial state.
Expand All @@ -34,10 +42,14 @@ public class ProcessStateDefinition
/// <param name="displayName">Localized display name.</param>
/// <param name="fatherStateName">Name of the father state. Stages can only transition from their father state.
/// If null, this state is the initial state. A process can have only one initial state.</param>
public ProcessStateDefinition(string name, string? displayName, string? fatherStateName)
/// <param name="defaultStateFlag">The default state flag. This flag is converted to a state icon and displayed
/// on the UI. For example, when the flag is Warning, the UI shows ⚠️.</param>
public ProcessStateDefinition(string name, string? displayName, string? fatherStateName,
ProcessStateFlag defaultStateFlag)
{
Name = Check.NotNullOrWhiteSpace(name, nameof(name));
DisplayName = displayName;
FatherStateName = fatherStateName;
DefaultStateFlag = defaultStateFlag;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using EasyAbp.ProcessManagement.Options;
using EasyAbp.ProcessManagement.ProcessStateHistories;
using Microsoft.Extensions.Options;
using Volo.Abp;
using Volo.Abp.Domain.Services;
using Volo.Abp.Uow;

Expand All @@ -20,7 +19,9 @@ public class ProcessManager : DomainService
public virtual async Task<Process> CreateAsync(CreateProcessModel model, DateTime now)
{
var processDefinition = Options.GetProcessDefinition(model.ProcessName);
var stateDefinition = processDefinition.GetState(processDefinition.InitialStateName);

model.StateFlag = NormalizeStateFlag(stateDefinition, model.StateFlag);
var id = GuidGenerator.Create();

var process = new Process(id, CurrentTenant.Id, processDefinition, now, model.GroupKey,
Expand All @@ -32,23 +33,34 @@ public virtual async Task<Process> CreateAsync(CreateProcessModel model, DateTim
}

[UnitOfWork]
public virtual async Task UpdateStateAsync(Process process, IProcessState nextState)
public virtual async Task UpdateStateAsync(Process process, UpdateProcessStateModel state)
{
if (nextState.StateName != process.StateName)
var processDefinition = Options.GetProcessDefinition(process.ProcessName);
var stateDefinition = processDefinition.GetState(state.StateName);

state.StateFlag = NormalizeStateFlag(stateDefinition, state.StateFlag);

if (state.StateName != process.StateName)
{
await UpdateToDifferentStateAsync(process, nextState);
await UpdateToDifferentStateAsync(processDefinition, stateDefinition, process, state);
}
else
{
await UpdateStateCustomInfoAsync(process, nextState);
await UpdateStateCustomInfoAsync(process, state);
}
}

[UnitOfWork]
protected virtual async Task UpdateToDifferentStateAsync(Process process, IProcessState state)
private static ProcessStateFlag NormalizeStateFlag(ProcessStateDefinition stateDefinition, ProcessStateFlag flag)
{
var processDefinition = Options.GetProcessDefinition(process.ProcessName);
var newFlag = flag != ProcessStateFlag.Unspecified ? flag : stateDefinition.DefaultStateFlag;

return newFlag == ProcessStateFlag.Unspecified ? ProcessStateFlag.Information : newFlag;
}

[UnitOfWork]
protected virtual async Task UpdateToDifferentStateAsync(ProcessDefinition processDefinition,
ProcessStateDefinition stateDefinition, Process process, UpdateProcessStateModel state)
{
var availableStates = processDefinition.GetChildrenStateNames(process.StateName);

if (availableStates.Contains(state.StateName))
Expand All @@ -64,9 +76,6 @@ protected virtual async Task UpdateToDifferentStateAsync(Process process, IProce
}
else
{
// get or throw.
processDefinition.GetState(state.StateName);

/* If this incoming state is a descendant of the current state, it will be accepted in the future.
* So we throw an exception and skip handling it this time.
* The next time the event handling is attempted, it may succeed.
Expand All @@ -93,7 +102,7 @@ protected virtual async Task UpdateToDifferentStateAsync(Process process, IProce
}
}

protected virtual async Task UpdateStateCustomInfoAsync(Process process, IProcessState state)
protected virtual async Task UpdateStateCustomInfoAsync(Process process, UpdateProcessStateModel state)
{
/* If it receives a state update event out of order (event.StateUpdateTime < process.StateUpdateTime),
* we will only add a new state history entity without updating the process entity properties.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public void Should_Get_Definitions()
processDefinition.GetState("Exporting").ShouldNotBeNull();
processDefinition.GetState("ExportFailed").ShouldNotBeNull();
processDefinition.GetState("Succeeded").ShouldNotBeNull();
Should.Throw<KeyNotFoundException>(() => processDefinition.GetState("Step10000"));
Should.Throw<UndefinedProcessStateException>(() => processDefinition.GetState("Step10000"));

processDefinition.InitialStateName.ShouldBe("Ready");
processDefinition.GetChildrenStateNames("Ready").ToArray()
Expand All @@ -42,9 +42,11 @@ public void Should_Not_Add_Duplicate_State()
var processDefinition = options.GetProcessDefinition("FakeExport");

Should.Throw<AbpException>(() =>
processDefinition.AddState(new ProcessStateDefinition("Ready", "Ready", null)));
processDefinition.AddState(new ProcessStateDefinition("Ready", "Ready", null,
ProcessStateFlag.Information)));

Should.Throw<AbpException>(() =>
processDefinition.AddState(new ProcessStateDefinition("Exporting", "Exporting", "Ready")));
processDefinition.AddState(new ProcessStateDefinition("Exporting", "Exporting", "Ready",
ProcessStateFlag.Information)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
using System.Threading.Tasks;
using EasyAbp.ProcessManagement.Options;
using EasyAbp.ProcessManagement.ProcessStateHistories;
using Microsoft.Extensions.Options;
using Shouldly;
using Volo.Abp;
using Xunit;

namespace EasyAbp.ProcessManagement.Processes;
Expand All @@ -14,12 +14,14 @@ public class ProcessManagerTests : ProcessManagementDomainTestBase
protected ProcessManager ProcessManager { get; }
protected IProcessRepository ProcessRepository { get; }
protected IProcessStateHistoryRepository ProcessStateHistoryRepository { get; }
protected ProcessManagementOptions Options { get; }

public ProcessManagerTests()
{
ProcessManager = GetRequiredService<ProcessManager>();
ProcessRepository = GetRequiredService<IProcessRepository>();
ProcessStateHistoryRepository = GetRequiredService<IProcessStateHistoryRepository>();
Options = GetRequiredService<IOptions<ProcessManagementOptions>>().Value;
}

[Fact]
Expand Down Expand Up @@ -70,7 +72,10 @@ public async Task Should_Update_To_Child_State()
public async Task Should_Update_State_Custom_Info()
{
var process = await ProcessManager.CreateAsync(
new CreateProcessModel("FakeExport", null, "groupKey"), DateTime.Now);
new CreateProcessModel("FakeExport", null, "groupKey", "hi", ProcessStateFlag.Information, null, null),
DateTime.Now);

process.StateFlag.ShouldBe(ProcessStateFlag.Information);

await ProcessRepository.InsertAsync(process, true);

Expand All @@ -85,7 +90,8 @@ await ProcessManager.UpdateStateAsync(process,
histories.Count.ShouldBe(2);
histories.Count(x => x.StateName == "Ready").ShouldBe(2);
histories.ShouldContain(x =>
x.StateName == "Ready" && x.ActionName == "balalala" && x.StateUpdateTime == updateTime);
x.StateName == "Ready" && x.ActionName == "balalala" && x.StateFlag == ProcessStateFlag.Running &&
x.StateUpdateTime == updateTime);
}

[Fact]
Expand Down Expand Up @@ -137,4 +143,17 @@ await Should.ThrowAsync<UpdatingToNonDescendantStateException>(() =>
ProcessManager.UpdateStateAsync(process,
new UpdateProcessStateModel(DateTime.Now, "FailedToStartExporting")));
}

[Fact]
public async Task Should_Use_Default_State_If_Not_Set()
{
var process = await ProcessManager.CreateAsync(
new CreateProcessModel("FakeExport", null, "groupKey"), DateTime.Now);

process.StateFlag.ShouldBe(Options.GetProcessDefinition("FakeExport").GetState("Ready").DefaultStateFlag);

await ProcessManager.UpdateStateAsync(process, new UpdateProcessStateModel(DateTime.Now, "Exporting"));

process.StateFlag.ShouldBe(Options.GetProcessDefinition("FakeExport").GetState("Exporting").DefaultStateFlag);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using EasyAbp.ProcessManagement.Options;
using EasyAbp.ProcessManagement.Processes;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
using Volo.Abp.Authorization;
Expand Down Expand Up @@ -35,11 +36,16 @@ private void ConfigureDemoProcessDefinitions(ServiceConfigurationContext context
* FailedToStartExporting
*/
var processDefinition = new ProcessDefinition("FakeExport", "Fake export")
.AddState(new ProcessStateDefinition("Ready", "Ready", null))
.AddState(new ProcessStateDefinition("FailedToStartExporting", "Failed", "Ready"))
.AddState(new ProcessStateDefinition("Exporting", "Exporting", "Ready"))
.AddState(new ProcessStateDefinition("ExportFailed", "Failed", "Exporting"))
.AddState(new ProcessStateDefinition("Succeeded", "Succeeded", "Exporting"));
.AddState(new ProcessStateDefinition(
"Ready", "Ready", null, ProcessStateFlag.Information))
.AddState(new ProcessStateDefinition(
"FailedToStartExporting", "Failed", "Ready", ProcessStateFlag.Failure))
.AddState(new ProcessStateDefinition(
"Exporting", "Exporting", "Ready", ProcessStateFlag.Running))
.AddState(new ProcessStateDefinition(
"ExportFailed", "Failed", "Exporting", ProcessStateFlag.Failure))
.AddState(new ProcessStateDefinition(
"Succeeded", "Succeeded", "Exporting", ProcessStateFlag.Success));

context.Services.Configure<ProcessManagementOptions>(options =>
{
Expand Down

0 comments on commit bfc8789

Please sign in to comment.