Skip to content

Commit

Permalink
RX State all new State handling
Browse files Browse the repository at this point in the history
Make CRUD example similar to external DB
  • Loading branch information
Bernhard Straub committed Mar 24, 2024
1 parent b3c4fed commit 5c12bc1
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 43 deletions.
2 changes: 1 addition & 1 deletion RxMudBlazorLight/RxMudBlazorLight.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<PackageTags>Blazor,MudBlazor,Rx,Reactive</PackageTags>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageOutputPath>..\Nuget</PackageOutputPath>
<PackageVersion>0.6.7</PackageVersion>
<PackageVersion>0.6.8</PackageVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion RxMudBlazorLightTestBase/CRUD/CRUDItemDialog.razor
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<EditForm Model=@_scope OnValidSubmit="OnValidSubmit">
<MudCard>
<MudCardContent>
<MudTextFieldRx State=@_scope.Text Validation=@CrudService.CrudItemInput.ValidateText AutoFocus="true" Immediate="true" Label="ToDo" />
<MudTextFieldRx State=@_scope.Text Validation=@CrudService.CrudItemInput.ValidateText CanChange=@_scope.CanUpdateText AutoFocus ="true" Immediate="true" Label="ToDo" />
<MudDatePickerRx State=@_scope.DueDateDate Validation=@CrudService.CrudItemInput.ValidateDueDate CanChange=@_scope.CanUpdateDueDate Label="Due Date" Editable="true" />
<MudTimePickerRx PickerVariant=@PickerVariant.Dialog State=@_scope.DueDateTime Validation=@_scope.ValidateDueDateTime CanChange=@_scope.CanUpdateTime />
</MudCardContent>
Expand Down
14 changes: 7 additions & 7 deletions RxMudBlazorLightTestBase/CRUD/CRUDTable.razor
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
<MudSelectRx StateGroup=@Service.CRUDDBRoleGroup CanChange=Service.CanChangeRole FullWidth=@false />
<CRUDItemAddOrUpdate AddMode=@true Item=@null />
<MudFabAsyncRx Color="Color.Error" StartIcon="@Icons.Material.Filled.AutoDelete" Size="Size.Small" ConfirmExecutionAsync=@(() => ConfirmDelete(DeleteType.Completed))
State=@Service.CRUDItemDB CanChange=@Service.CanRemoveCompletedCRUDItems ChangeStateAsync=@(CrudService.RemoveCompletedCRUDItems()) />
State=@Service.CRUDDBState CanChange=@Service.CanRemoveCompletedCRUDItems ChangeStateAsync=@(Service.RemoveCompletedCRUDItems()) />
<MudFabAsyncRx Color="Color.Error" StartIcon="@Icons.Material.Filled.DeleteForever" Size="Size.Small" ConfirmExecutionAsync=@(() => ConfirmDelete(DeleteType.All))
State=@Service.CRUDItemDB CanChange=@Service.CanRemoveAllCRUDItems ChangeStateAsync=@(CrudService.RemoveAllCRUDItems()) />
State=@Service.CRUDDBState CanChange=@Service.CanRemoveAllCRUDItems ChangeStateAsync=@(Service.RemoveAllCRUDItems()) />
</MudStack>
</CardHeaderActions>
</MudCardHeader>
<MudCardContent>
<MudTable T="CRUDToDoItem" Items=@Service.CRUDItemDB.Value.Values Dense="true">
<MudTable T="CRUDToDoItem" Items=@Service.CRUDItems Dense="true">
<ColGroup>
<col style="width:55%;" />
<col style="width:30%;" />
Expand Down Expand Up @@ -55,15 +55,15 @@
<MudTd DataLabel="ToDo"><MudText Style=@ColorForItem(context)>@context.Text</MudText></MudTd>
<MudTd DataLabel="DueDate"><MudText Style=@ColorForItem(context)>@DateTimeForItem(context)</MudText></MudTd>
<MudTd DataLabel="Completed" Style="text-align:center">
<MudIconButtonAsyncCancelRx Icon=@(context.Completed ? Icons.Material.Filled.CheckBox : Icons.Material.Filled.CheckBoxOutlineBlank) State=@Service.CRUDItemDB
CanChange=@Service.CanToggleCRUDItemCompleted ChangeStateAsync=@(CrudService.ToggleCRUDItemCompletedAsync(context)) />
<MudIconButtonAsyncCancelRx Icon=@(context.Completed ? Icons.Material.Filled.CheckBox : Icons.Material.Filled.CheckBoxOutlineBlank) State=@Service.CRUDDBState
HasProgress=@false CanChange=@Service.CanToggleCRUDItemCompleted ChangeStateAsync=@(Service.ToggleCRUDItemCompletedAsync(context)) />
</MudTd>
<MudTd DataLabel="Edit" Style="text-align:center">
<CRUDItemAddOrUpdate AddMode=@false Item=@context />
</MudTd>
<MudTd DataLabel="DeleteItem" Style="text-align:center">
<MudIconButtonAsyncRx Color="Color.Error" Icon=@Icons.Material.Filled.Delete State=@Service.CRUDItemDB CanChange=@Service.CanRemoveCRUDItem
ConfirmExecutionAsync=@(() => ConfirmDelete(DeleteType.One)) ChangeStateAsync=@(CrudService.RemoveCRUDItem(context)) />
<MudIconButtonAsyncRx Color="Color.Error" Icon=@Icons.Material.Filled.Delete State=@Service.CRUDDBState CanChange=@Service.CanRemoveCRUDItem
ConfirmExecutionAsync=@(() => ConfirmDelete(DeleteType.One)) ChangeStateAsync=@(Service.RemoveCRUDItem(context)) />
</MudTd>
</RowTemplate>
</MudTable>
Expand Down
111 changes: 77 additions & 34 deletions RxMudBlazorLightTestBase/Service/CrudService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using MudBlazor;

using RxBlazorLightCore;
using System.Reactive;

namespace RxMudBlazorLightTestBase.Service
{
Expand All @@ -19,6 +20,44 @@ public enum DBRole
Guest
}

public static class CrudServiceExtensions
{
public static bool CanAdd(this IStateGroup<DBRole> roleGroup)
{
return roleGroup.Value is DBRole.Admin;
}

public static bool CanUpdateText(this IStateGroup<DBRole> roleGroup)
{
return roleGroup.Value is DBRole.Admin;
}

public static bool CanUpdateDueDate(this IStateGroup<DBRole> roleGroup)
{
return roleGroup.Value is DBRole.Admin || roleGroup.Value is DBRole.User;
}

public static bool CanUpdateCompleted(this IStateGroup<DBRole> roleGroup)
{
return roleGroup.Value is DBRole.Admin || roleGroup.Value is DBRole.User;
}

public static bool CanDeleteCompleted(this IStateGroup<DBRole> roleGroup)
{
return roleGroup.Value is DBRole.Admin || roleGroup.Value is DBRole.User;
}

public static bool CanDeleteOne(this IStateGroup<DBRole> roleGroup)
{
return roleGroup.Value is DBRole.Admin || roleGroup.Value is DBRole.User;
}

public static bool CanDeleteAll(this IStateGroup<DBRole> roleGroup)
{
return roleGroup.Value is DBRole.Admin;
}
}

public class CrudService : RxBLService
{
public sealed partial class CrudItemInput(CrudService service, CRUDToDoItem? item)
Expand All @@ -32,7 +71,7 @@ public sealed partial class CrudItemInput(CrudService service, CRUDToDoItem? ite
public async Task SubmitAsync()
{
var newItem = new CRUDToDoItem(Text.Value, DueDateDate.Value + DueDateTime.Value, false, _item?.Id ?? Guid.NewGuid());
await service.CRUDItemDB.ChangeAsync(AddCRUDItem(newItem));
await service.CRUDDBState.ChangeAsync(service.AddCRUDItem(newItem));
}
public bool CanSubmit()
{
Expand Down Expand Up @@ -88,11 +127,16 @@ public bool CanSubmit()
}
}

public IStateAsync<IDictionary<Guid, CRUDToDoItem>> CRUDItemDB { get; }
public IEnumerable<CRUDToDoItem> CRUDItems => _db.Values;

public IStateAsync<Unit> CRUDDBState { get; }
public IStateGroup<DBRole> CRUDDBRoleGroup { get; }

private readonly Dictionary<Guid, CRUDToDoItem> _db;
public CrudService()
{
CRUDItemDB = this.CreateStateAsync<IDictionary<Guid, CRUDToDoItem>>(new Dictionary<Guid, CRUDToDoItem>());
_db = [];
CRUDDBState = this.CreateStateAsync(Unit.Default);
CRUDDBRoleGroup = this.CreateStateGroup([DBRole.Admin, DBRole.User, DBRole.Guest], DBRole.Admin);
}

Expand All @@ -101,97 +145,96 @@ public CrudItemInput CreateItemInput(CRUDToDoItem? item = null)
return new CrudItemInput(this, item);
}

public Func<IState<DBRole>, bool> CanChangeRole => _ => !CRUDItemDB.Changing();
public Func<IState<DBRole>, bool> CanChangeRole => _ => !CRUDDBState.Changing();

public bool CanAdd => CRUDDBRoleGroup.Value is DBRole.Admin && !CRUDItemDB.Changing();
public bool CanUpdate => (CanUpdateText || CanUpdateDueDate) && !CRUDItemDB.Changing();
public bool CanAdd => !CRUDDBState.Changing() && CRUDDBRoleGroup.CanAdd();
public bool CanUpdate => (CanUpdateText || CanUpdateDueDate) && !CRUDDBState.Changing();

public static Func<IStateAsync<IDictionary<Guid, CRUDToDoItem>>, Task> AddCRUDItem(CRUDToDoItem item)
public Func<IStateAsync<Unit>, Task> AddCRUDItem(CRUDToDoItem item)
{
return async s =>
return async _ =>
{
ArgumentNullException.ThrowIfNull(item.Id, nameof(item.Id));
s.Value[item.Id!.Value] = item;
_db[item.Id!.Value] = item;
await Task.Delay(200);
};
}

public static Func<IStateAsync<IDictionary<Guid, CRUDToDoItem>>, Task> UpdateCRUDItemAsync(CRUDToDoItem item)
public Func<IStateAsync<Unit>, Task> UpdateCRUDItemAsync(CRUDToDoItem item)
{
return async s =>
return async _ =>
{
ArgumentNullException.ThrowIfNull(item.Id, nameof(item.Id));
s.Value[item.Id!.Value] = item;
_db[item.Id!.Value] = item;
await Task.Delay(200);
};
}

public Func<IStateAsync<IDictionary<Guid, CRUDToDoItem>>, bool> CanToggleCRUDItemCompleted =>
_ => (CRUDDBRoleGroup.Value is DBRole.Admin || CRUDDBRoleGroup.Value is DBRole.User) && !CRUDItemDB.Changing();
public Func<IStateAsync<Unit>, bool> CanToggleCRUDItemCompleted =>
_ => !CRUDDBState.Changing() && CRUDDBRoleGroup.CanUpdateCompleted();

public static Func<IStateAsync<IDictionary<Guid, CRUDToDoItem>>, CancellationToken, Task> ToggleCRUDItemCompletedAsync(CRUDToDoItem item)
public Func<IStateAsync<Unit>, CancellationToken, Task> ToggleCRUDItemCompletedAsync(CRUDToDoItem item)
{
return async (s, ct) =>
return async (_, ct) =>
{
ArgumentNullException.ThrowIfNull(item.Id, nameof(item.Id));
item = item with { Completed = !item.Completed };
await Task.Delay(2000, ct);
s.Value[item.Id!.Value] = item;
_db[item.Id!.Value] = item;
};
}

public Func<IStateAsync<IDictionary<Guid, CRUDToDoItem>>, bool> CanRemoveCRUDItem => _ =>
public Func<IStateAsync<Unit>, bool> CanRemoveCRUDItem => _ =>
{
return !CRUDItemDB.Changing();
return !CRUDDBState.Changing() && CRUDDBRoleGroup.CanDeleteOne();
};

public static Func<IStateAsync<IDictionary<Guid, CRUDToDoItem>>, Task> RemoveCRUDItem(CRUDToDoItem item)
public Func<IStateAsync<Unit>, Task> RemoveCRUDItem(CRUDToDoItem item)
{
return async s =>
{
ArgumentNullException.ThrowIfNull(item.Id, nameof(item.Id));
s.Value.Remove(item.Id!.Value);
_db.Remove(item.Id!.Value);
await Task.Delay(200);
};
}

public Func<IStateAsync<IDictionary<Guid, CRUDToDoItem>>, bool> CanRemoveCompletedCRUDItems => s =>
public Func<IStateAsync<Unit>, bool> CanRemoveCompletedCRUDItems => s =>
{
return s.Value.Values.Where(x => x.Completed).Any() &&
(CRUDDBRoleGroup.Value is DBRole.Admin || CRUDDBRoleGroup.Value is DBRole.User) && !CRUDItemDB.Changing();
return _db.Values.Where(x => x.Completed).Any() && !CRUDDBState.Changing() && CRUDDBRoleGroup.CanDeleteCompleted();
};


public static Func<IStateAsync<IDictionary<Guid, CRUDToDoItem>>, Task> RemoveCompletedCRUDItems()
public Func<IStateAsync<Unit>, Task> RemoveCompletedCRUDItems()
{
return async s =>
{
foreach (var item in s.Value.Values)
foreach (var item in _db.Values)
{
if (item.Completed)
{
s.Value.Remove(item.Id!.Value);
_db.Remove(item.Id!.Value);
}
}
await Task.Delay(200);
};
}

public Func<IStateAsync<IDictionary<Guid, CRUDToDoItem>>, bool> CanRemoveAllCRUDItems => s =>
public Func<IStateAsync<Unit>, bool> CanRemoveAllCRUDItems => s =>
{
return s.Value.Values.Count != 0 && !CRUDItemDB.Changing();
return _db.Values.Count != 0 && !CRUDDBState.Changing() && CRUDDBRoleGroup.CanDeleteAll();
};

public static Func<IStateAsync<IDictionary<Guid, CRUDToDoItem>>, Task> RemoveAllCRUDItems()
public Func<IStateAsync<Unit>, Task> RemoveAllCRUDItems()
{
return async s =>
{
s.Value.Clear();
_db.Clear();
await Task.Delay(200);
};
}

private bool CanUpdateText => CRUDDBRoleGroup.Value is DBRole.Admin || CRUDDBRoleGroup.Value is DBRole.User;
private bool CanUpdateDueDate => CRUDDBRoleGroup.Value is DBRole.Admin;
private bool CanUpdateText => CRUDDBRoleGroup.CanUpdateText();
private bool CanUpdateDueDate => CRUDDBRoleGroup.CanUpdateDueDate();
}
}

0 comments on commit 5c12bc1

Please sign in to comment.