Skip to content

Commit

Permalink
Handle null checks and improve error handling. (#339)
Browse files Browse the repository at this point in the history
Added missing null checks in various areas to prevent runtime errors. Enhanced error-handling mechanisms by logging warnings and ignoring specific exceptions. These improvements ensure stability and better troubleshooting during execution.
  • Loading branch information
sfmskywalker authored Dec 13, 2024
1 parent a1453d5 commit fd86c49
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import {getElement} from "./get-element";

export function getVisibleHeight(elementOrQuerySelector: Element | string): number {
const element = getElement(elementOrQuerySelector);

if(!element)
return 0;

const rect = element.getBoundingClientRect();
const windowHeight = window.innerHeight;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ export function calculateActivitySize(activity: Activity): Promise<Size> {
return new Promise((resolve, reject) => {
const checkSize = () => {
const activityElement: Element = wrapper.getElementsByTagName(activityTagName)[0];

if(activityElement == null) {
reject('Activity element not found.');
return;
}

const activityElementRect = activityElement.getBoundingClientRect();

// If the custom element has no width or height yet, it means it has not yet rendered.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using Elsa.Studio.Workflows.UI.Models;
using Humanizer;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Logging;
using Microsoft.JSInterop;
using MudBlazor.Utilities;
using ThrottleDebounce;
Expand All @@ -28,9 +29,9 @@ public partial class FlowchartDesigner : IDisposable, IAsyncDisposable
{
private readonly string _containerId = $"container-{Guid.NewGuid():N}";
private DotNetObjectReference<FlowchartDesigner>? _componentRef;
private IFlowchartMapper? _flowchartMapper = default!;
private IActivityMapper? _activityMapper = default!;
private X6GraphApi _graphApi = default!;
private IFlowchartMapper? _flowchartMapper = null!;
private IActivityMapper? _activityMapper = null!;
private X6GraphApi _graphApi = null!;
private readonly PendingActionsQueue _pendingGraphActions;
private RateLimitedFunc<Task> _rateLimitedLoadFlowchartAction;
private IDictionary<string, ActivityStats>? _activityStats;
Expand All @@ -39,12 +40,12 @@ public partial class FlowchartDesigner : IDisposable, IAsyncDisposable
/// <inheritdoc />
public FlowchartDesigner()
{
_pendingGraphActions = new PendingActionsQueue(() => new(_graphApi != null!));
_pendingGraphActions = new PendingActionsQueue(() => new(_graphApi != null!), () => Logger);
_rateLimitedLoadFlowchartAction = Debouncer.Debounce(async () => { await InvokeAsync(async () => await LoadFlowchartAsync(Flowchart, ActivityStats)); }, TimeSpan.FromMilliseconds(100));
}

/// The flowchart to render.
[Parameter] public JsonObject Flowchart { get; set; } = default!;
[Parameter] public JsonObject Flowchart { get; set; } = null!;

/// The activity stats to render.
[Parameter] public IDictionary<string, ActivityStats>? ActivityStats { get; set; }
Expand All @@ -67,12 +68,13 @@ public FlowchartDesigner()
/// An event raised when the graph is updated.
[Parameter] public EventCallback GraphUpdated { get; set; }

[Inject] private DesignerJsInterop DesignerJsInterop { get; set; } = default!;
[Inject] private IThemeService ThemeService { get; set; } = default!;
[Inject] private IActivityRegistry ActivityRegistry { get; set; } = default!;
[Inject] private IMapperFactory MapperFactory { get; set; } = default!;
[Inject] private IIdentityGenerator IdentityGenerator { get; set; } = default!;
[Inject] private IActivityNameGenerator ActivityNameGenerator { get; set; } = default!;
[Inject] private DesignerJsInterop DesignerJsInterop { get; set; } = null!;
[Inject] private IThemeService ThemeService { get; set; } = null!;
[Inject] private IActivityRegistry ActivityRegistry { get; set; } = null!;
[Inject] private IMapperFactory MapperFactory { get; set; } = null!;
[Inject] private IIdentityGenerator IdentityGenerator { get; set; } = null!;
[Inject] private IActivityNameGenerator ActivityNameGenerator { get; set; } = null!;
[Inject] private ILogger<FlowchartDesigner> Logger { get; set; } = null!;

/// <summary>
/// Invoked from JavaScript when an activity is selected.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ internal class DesignerJsInterop(IJSRuntime jsRuntime, IServiceProvider serviceP
/// <returns>The ID of the graph.</returns>
public async ValueTask<X6GraphApi> CreateGraphAsync(string containerId, DotNetObjectReference<FlowchartDesigner> componentRef, bool isReadOnly = false)
{
return await InvokeAsync(async module =>
return await TryInvokeAsync(async module =>
{
await module.InvokeAsync<string>("createGraph", containerId, componentRef, isReadOnly);
return new X6GraphApi(module, serviceProvider, containerId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ protected async Task<T> TryInvokeAsync<T>(Func<IJSObjectReference, ValueTask<T>>
{
// Ignore.
}
catch(ObjectDisposedException)
{
// Ignore.
}

return default!;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
using Microsoft.Extensions.Logging;

namespace Elsa.Studio.Workflows.Designer.Services;

public class PendingActionsQueue(Func<ValueTask<bool>> shortCircuit)
/// <summary>
/// A queue for pending actions that can be processed in a FIFO manner.
/// </summary>
public class PendingActionsQueue(Func<ValueTask<bool>> shortCircuit, Func<ILogger> logger)
{
private readonly Queue<Func<Task>> _pendingActions = new();

/// <summary>
/// Processes all pending actions.
/// </summary>
public async Task ProcessAsync()
{
while (_pendingActions.Any())
{
var action = _pendingActions.Dequeue();
await action();
await TryExecuteActionAsync(action);
}
}

/// <summary>
/// Enqueues an action to be executed.
/// </summary>
public async Task EnqueueAsync(Func<Task> action)
{
if(await shortCircuit())
{
await action();
await TryExecuteActionAsync(action);
return;
}

Expand All @@ -30,6 +41,9 @@ public async Task EnqueueAsync(Func<Task> action)
await tsc.Task;
}

/// <summary>
/// Enqueues an action to be executed.
/// </summary>
public async Task<T> EnqueueAsync<T>(Func<Task<T>> action)
{
if(await shortCircuit())
Expand All @@ -43,4 +57,16 @@ public async Task<T> EnqueueAsync<T>(Func<Task<T>> action)
});
return await tsc.Task;
}

private async Task TryExecuteActionAsync(Func<Task> action)
{
try
{
await action();
}
catch(Exception ex)
{
logger().LogWarning(ex, "An error occurred while executing a pending action.");
}
}
}

0 comments on commit fd86c49

Please sign in to comment.