Skip to content

Commit

Permalink
PDButton - Added Operation and OperationIconCssClass parameters.
Browse files Browse the repository at this point in the history
PDFormFooter - Upgraded to use new Operation feature of PDButtons.
  • Loading branch information
MarkGoldring committed Oct 17, 2024
1 parent cfe5f50 commit 26f5515
Show file tree
Hide file tree
Showing 13 changed files with 199 additions and 112 deletions.
97 changes: 49 additions & 48 deletions PanoramicData.Blazor.Demo/Data/PersonDataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class PersonDataProvider : DataProviderBase<Person>
private static readonly List<Person> _people = [];
public static readonly string[] Locations = ["Paris", "Rome", "Milan", "New York", "Peckham", "Sydney"];

public PersonDataProvider() : this(255){}
public PersonDataProvider() : this(255) { }

public PersonDataProvider(int count)
{
Expand Down Expand Up @@ -150,18 +150,19 @@ await Task.Run(() =>
/// <param name="item">The item to be deleted.</param>
/// <param name="cancellationToken">A cancellation token for the async operation.</param>
/// <returns>A new OperationResponse instance that contains the results of the operation.</returns>
public override Task<OperationResponse> DeleteAsync(Person item, CancellationToken cancellationToken)
=> Task.Run(() =>
{
var existingPerson = _people.Find(x => x.Id == item.Id);
if (existingPerson == null)
{
return new OperationResponse { ErrorMessage = $"Person not found (id {item.Id})" };
}
public override async Task<OperationResponse> DeleteAsync(Person item, CancellationToken cancellationToken)
{
await Task.Delay(1000);

var existingPerson = _people.Find(x => x.Id == item.Id);
if (existingPerson == null)
{
return new OperationResponse { ErrorMessage = $"Person not found (id {item.Id})" };
}

_people.Remove(existingPerson);
return new OperationResponse { Success = true };
});
_people.Remove(existingPerson);
return new OperationResponse { Success = true };
}

/// <summary>
/// Requests the given item is updated by applying the given delta.
Expand All @@ -170,53 +171,53 @@ public override Task<OperationResponse> DeleteAsync(Person item, CancellationTok
/// <param name="delta">A dictionary with new property values.</param>
/// <param name="cancellationToken">A cancellation token for the async operation.</param>
/// <returns>A new OperationResponse instance that contains the results of the operation.</returns>
public override Task<OperationResponse> UpdateAsync(Person item, IDictionary<string, object?> delta, CancellationToken cancellationToken)
=> Task.Run(() =>
{
public override async Task<OperationResponse> UpdateAsync(Person item, IDictionary<string, object?> delta, CancellationToken cancellationToken)
{
await Task.Delay(1000);

var existingPerson = _people.Find(x => x.Id == item.Id);
if (existingPerson == null)
{
return new OperationResponse { ErrorMessage = $"Person not found (id {item.Id})" };
}

var existingPerson = _people.Find(x => x.Id == item.Id);
if (existingPerson == null)
foreach (var kvp in delta)
{
var prop = item.GetType().GetProperty(kvp.Key);
if (prop == null)
{
return new OperationResponse { ErrorMessage = $"Person does not contain a property named {kvp.Key}" };
}
else
{
try
{
return new OperationResponse { ErrorMessage = $"Person not found (id {item.Id})" };
var value = kvp.Value.Cast(prop.PropertyType);
prop.SetValue(existingPerson, value);
}

foreach (var kvp in delta)
catch (Exception ex)
{
var prop = item.GetType().GetProperty(kvp.Key);
if (prop == null)
{
return new OperationResponse { ErrorMessage = $"Person does not contain a property named {kvp.Key}" };
}
else
{
try
{
var value = kvp.Value.Cast(prop.PropertyType);
prop.SetValue(existingPerson, value);
}
catch (Exception ex)
{
return new OperationResponse { ErrorMessage = $"Failed to update property {kvp.Key} to {kvp.Value}: {ex.Message}" };
}
}
return new OperationResponse { ErrorMessage = $"Failed to update property {kvp.Key} to {kvp.Value}: {ex.Message}" };
}
}
}

existingPerson.DateModified = DateTime.Now;
return new OperationResponse { Success = true };
});
existingPerson.DateModified = DateTime.Now;
return new OperationResponse { Success = true };
}

/// <summary>
/// Requests the given item is created.
/// </summary>
/// <param name="item">New item details.</param>
/// <param name="cancellationToken">A cancellation token for the async operation.</param>
/// <returns>A new OperationResponse instance that contains the results of the operation.</returns>
public override Task<OperationResponse> CreateAsync(Person item, CancellationToken cancellationToken)
=> Task.Run(() =>
{
item.Id = _people.Max(x => x.Id) + 1;
item.DateModified = item.DateCreated = DateTime.Now;
_people.Add(item);
return new OperationResponse { Success = true };
});
public override async Task<OperationResponse> CreateAsync(Person item, CancellationToken cancellationToken)
{
await Task.Delay(1000);
item.Id = _people.Max(x => x.Id) + 1;
item.DateModified = item.DateCreated = DateTime.Now;
_people.Add(item);
return new OperationResponse { Success = true };
}
}
11 changes: 6 additions & 5 deletions PanoramicData.Blazor.Demo/Pages/PDButtonPage.razor
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<DemoSourceView SourceFiles="Pages/PDButtonPage.razor, Pages/PDButtonPage.razor.cs">

<div>
<PDButton Text="Click Me"
<PDButton Text="Counter++"
IconCssClass="fas fa-fw fa-plus"
CssClass="btn btn-primary"
ShortcutKey="_shortcut1"
Expand All @@ -20,11 +20,12 @@
</div>

<div class="mt-2">
<PDButton Text="Click Me 2"
IconCssClass="fas fa-fw fa-cog fa-spin"
<PDButton Text="Long running operation"
IconCssClass="fas fa-fw fa-cog"
CssClass="btn btn-secondary"
ToolTip="@($"Click me to see the event update")"
Click="OnButton2Click">
ToolTip="@($"Click me to start long running operation")"
Operation="DoLongRunningOperation"
OperationIconCssClass="fas fa-fw fa-cog fa-spin">
</PDButton>
</div>

Expand Down
18 changes: 12 additions & 6 deletions PanoramicData.Blazor.Demo/Pages/PDButtonPage.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

public partial class PDButtonPage : IAsyncDisposable
{
private bool _operationRunning = false;
private bool _buttonEnabled = true;
private IJSObjectReference? _commonModule;
private readonly ShortcutKey _shortcut1 = ShortcutKey.Create("Shift-Ctrl-Digit1");
private readonly ShortcutKey _shortcut2 = ShortcutKey.Create("Shift-Ctrl-Digit2");
private readonly ShortcutKey _shortcut3 = ShortcutKey.Create("Shift-Ctrl-Digit3");
private IJSObjectReference? _commonModule;
private bool _buttonEnabled = true;
private int Counter { get; set; }

[CascadingParameter] protected EventManager? EventManager { get; set; }
Expand All @@ -15,6 +16,15 @@ public partial class PDButtonPage : IAsyncDisposable

[Inject] private NavigationManager NavigationManager { get; set; } = null!;

private async Task DoLongRunningOperation(MouseEventArgs args)
{
EventManager?.Add(new Event("Long running operation started"));

await Task.Delay(5000);

EventManager?.Add(new Event("Long running operation stopped"));
}

protected override async Task OnInitializedAsync() => _commonModule = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./_content/PanoramicData.Blazor/js/common.js").ConfigureAwait(true);

private void OnButton1Click(MouseEventArgs args)
Expand All @@ -23,10 +33,6 @@ private void OnButton1Click(MouseEventArgs args)
Counter++;
}

private void OnButton2Click(MouseEventArgs args)
{
EventManager?.Add(new Event("Button 2 Click", new EventArgument("Ctrl", args.CtrlKey)));
}
private async Task OnButton3Click(MouseEventArgs args)
{
EventManager?.Add(new Event("Button 3 Click", new EventArgument("Ctrl", args.CtrlKey)));
Expand Down
2 changes: 1 addition & 1 deletion PanoramicData.Blazor.Demo/Pages/PDFormPage.razor
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
DeleteTitle="Delete Person - {0}"
ItemDescription="@((x) => $"{x.FirstName} {x.LastName}")" />

<PDFormBody TItem="Person" DebounceWait="3000">
<PDFormBody TItem="Person" DebounceWait="300">

<PDField TItem="Person"
Field="x => x.Id"
Expand Down
5 changes: 5 additions & 0 deletions PanoramicData.Blazor.Demo/Pages/PDFormPage.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ private async Task OnFooterClick(string key)
{
EventManager?.Add(new Event("FooterClick", new EventArgument("Key", key)));

if (key == "Save")
{
await Task.Delay(5000);
}

if (key == "Cancel")
{
SelectedPerson = null;
Expand Down
12 changes: 6 additions & 6 deletions PanoramicData.Blazor/PDButton.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
{
<button @attributes="Attributes"
class="pd-button btn @CssClass @ButtonSizeCssClass"
disabled="@(IsEnabled ? null : "true")"
disabled="@(ActualEnabledState ? null : "true")"
id="@Id"
title="@ToolTip.AppendShortcut(ShortcutKey)"
@onclick="Click"
@onclick="OnClickAsync"
@onclick:preventDefault="PreventDefault"
@onclick:stopPropagation="StopPropagation"
@onmousedown="MouseDown"
Expand All @@ -16,7 +16,7 @@
{
@if (!string.IsNullOrWhiteSpace(IconCssClass))
{
<span class="icon @IconCssClass"></span>
<span class="icon @GetIconCssClass()"></span>
}
<span class="@(string.IsNullOrWhiteSpace(IconCssClass) ? "" : "ps-1") @TextCssClass">@Text.GetShortcutMarkup()</span>
}
Expand All @@ -31,10 +31,10 @@ else
<a @attributes="Attributes"
href="@Url" target="@Target"
class="pd-button btn @CssClass @ButtonSizeCssClass"
disabled="@(IsEnabled ? null : "true")"
disabled="@(ActualEnabledState ? null : "true")"
id="@Id"
title="@ToolTip.AppendShortcut(ShortcutKey)"
@onclick="Click"
@onclick="OnClickAsync"
@onclick:preventDefault="PreventDefault"
@onclick:stopPropagation="StopPropagation"
@onmousedown="MouseDown"
Expand All @@ -44,7 +44,7 @@ else
{
@if (!string.IsNullOrWhiteSpace(IconCssClass))
{
<span class="icon @IconCssClass"></span>
<span class="icon @GetIconCssClass()"></span>
}
<span class="@(string.IsNullOrWhiteSpace(IconCssClass) ? "" : "ps-1") @TextCssClass">@Text.GetShortcutMarkup()</span>
}
Expand Down
37 changes: 37 additions & 0 deletions PanoramicData.Blazor/PDButton.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

public partial class PDButton : IDisposable
{
private bool _operationInProgress;

#region Inject
[Inject]
private IGlobalEventService GlobalEventService { get; set; } = null!;
Expand Down Expand Up @@ -46,6 +48,18 @@ public partial class PDButton : IDisposable
[Parameter]
public EventCallback<MouseEventArgs> MouseDown { get; set; }

/// <summary>
/// Async function to be called when button is clicked.
/// </summary>
[Parameter]
public Func<MouseEventArgs, Task>? Operation { get; set; }

/// <summary>
/// CSS Class for icon to be displayed on button when Operation is running.
/// </summary>
[Parameter] public string OperationIconCssClass { get; set; } = string.Empty;


[Parameter]
public bool PreventDefault { get; set; }

Expand Down Expand Up @@ -88,6 +102,8 @@ public partial class PDButton : IDisposable
/// </summary>
[Parameter] public string Url { get; set; } = string.Empty;

private bool ActualEnabledState => IsEnabled && (Operation is null || !_operationInProgress);

private string ButtonSizeCssClass
{
get
Expand All @@ -101,6 +117,27 @@ private string ButtonSizeCssClass
}
}

private string GetIconCssClass()
{
return Operation != null && _operationInProgress && !string.IsNullOrWhiteSpace(OperationIconCssClass)
? OperationIconCssClass
: IconCssClass;
}

private async Task OnClickAsync(MouseEventArgs args)
{
if (Operation is null)
{
await Click.InvokeAsync(args);
}
else
{
_operationInProgress = true;
await Operation.Invoke(args);
_operationInProgress = false;
}
}

protected override void OnInitialized()
{
GlobalEventService.KeyUpEvent += GlobalEventService_KeyUpEvent;
Expand Down
1 change: 1 addition & 0 deletions PanoramicData.Blazor/PDButton.razor.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.btn.disabled, .btn:disabled {
pointer-events: auto;
cursor: default;
}

.pd-button .icon {
Expand Down
22 changes: 12 additions & 10 deletions PanoramicData.Blazor/PDFormFooter.razor
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,29 @@ else if (Form.Mode != FormModes.Hidden && Form.Mode != FormModes.Empty)
<div class="pd-form-footer">
<PDToolbar>

<PDToolbarButton Click="OnButtonClick"
CssClass="btn-danger"
<PDToolbarButton CssClass="btn-danger"
IconCssClass="@DeleteButtonIconCssClass"
IsVisible="ShowDelete && Form.Mode == FormModes.Edit"
Key="Delete"
Operation="OnDeleteAsync"
Size="Size"
Text="@DeleteButtonText" />

<PDToolbarButton Click="OnButtonClick"
CssClass="@YesButtonCssClass"
<PDToolbarButton CssClass="@YesButtonCssClass"
IconCssClass="@YesButtonIconCssClass"
IsVisible="Form.Mode == FormModes.Delete || Form.Mode == FormModes.Cancel"
Key="Yes"
Operation="OnYesAsync"
OperationIconCssClass="fas fa-fw fa-circle-notch fa-spin"
ShiftRight="true"
Size="Size"
Text="@YesButtonText" />

<PDToolbarButton Click="OnButtonClick"
CssClass="@NoButtonCssClass"
<PDToolbarButton CssClass="@NoButtonCssClass"
IconCssClass="@NoButtonIconCssClass"
IsVisible="Form.Mode == FormModes.Delete || Form.Mode == FormModes.Cancel"
Key="No"
Operation="OnNoAsync"
Size="Size"
Text="@NoButtonText" />

Expand All @@ -41,20 +42,21 @@ else if (Form.Mode != FormModes.Hidden && Form.Mode != FormModes.Empty)
</div>
</PDToolbarPlaceholder>

<PDToolbarButton Click="OnButtonClick"
CssClass="@SaveButtonCssClass"
<PDToolbarButton CssClass="@SaveButtonCssClass"
IconCssClass="@SaveButtonIconCssClass"
IsEnabled="_errorCount == 0"
IsVisible="ShowSave && (Form.Mode == FormModes.Create || Form.Mode == FormModes.Edit)"
Key="Save"
Operation="OnSaveAsync"
OperationIconCssClass="fas fa-fw fa-circle-notch fa-spin"
Size="Size"
Text="@SaveButtonText" />

<PDToolbarButton Click="OnButtonClick"
CssClass="@CancelButtonCssClass"
<PDToolbarButton CssClass="@CancelButtonCssClass"
IconCssClass="@CancelButtonIconCssClass"
IsVisible="ShowCancel && (Form.Mode == FormModes.Create || Form.Mode == FormModes.Edit || (Form.Mode == FormModes.ReadOnly && ShowCancelWhenReadOnly))"
Key="Cancel"
Operation="OnCancelAsync"
Size="Size"
Text="@CancelButtonText" />
</PDToolbar>
Expand Down
Loading

0 comments on commit 26f5515

Please sign in to comment.