Skip to content

Commit

Permalink
feat(hrui): Update HR notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
dr1rrb committed Jul 5, 2024
1 parent 4e7f321 commit 8fc3672
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 161 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ private async ValueTask Notify(HotReloadEvent evt, HotReloadEventSource source =
break;

case HotReloadEvent.RudeEdit:
case HotReloadEvent.RudeEditDialogButton:
//case HotReloadEvent.RudeEditDialogButton:
await (await StartOrContinueHotReload()).Complete(HotReloadServerResult.RudeEdit);
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,15 @@ partial class ClientHotReloadProcessor
private readonly TaskCompletionSource<bool> _hotReloadWorkloadSpaceLoaded = new();

private void WorkspaceLoadResult(HotReloadWorkspaceLoadResult hotReloadWorkspaceLoadResult)
=> _hotReloadWorkloadSpaceLoaded.SetResult(hotReloadWorkspaceLoadResult.WorkspaceInitialized);
{
// If we get a workspace loaded message, we can assume that we are running with the dev-server
// This mean that HR won't work with the debugger attached.
if (Debugger.IsAttached)
{
_status.ReportServerState(HotReloadState.Disabled);
}
_hotReloadWorkloadSpaceLoaded.SetResult(hotReloadWorkspaceLoadResult.WorkspaceInitialized);
}

/// <summary>
/// Waits for the server's hot reload workspace to be loaded
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,16 @@ private class StatusSink(ClientHotReloadProcessor owner)
private ImmutableList<HotReloadClientOperation> _localOperations = ImmutableList<HotReloadClientOperation>.Empty;
private HotReloadSource _source;

public void ReportServerState(HotReloadState state)
{
_serverState = state;
NotifyStatusChanged();
}

#if HAS_UNO_WINUI
public void ReportServerStatus(HotReloadStatusMessage status)
{
_serverState = status.State;
_serverState ??= status.State; // Do not override the state if it has already been set (debugger attached with dev-server)
ImmutableInterlocked.Update(ref _serverOperations, UpdateOperations, status.Operations);
NotifyStatusChanged();

Expand Down Expand Up @@ -180,7 +186,7 @@ internal HotReloadClientOperation(HotReloadSource source, Type[] types, Action o
var versionIndex = t.Name.IndexOf('#');
return versionIndex < 0
? default!
: $"{name[..versionIndex]} (v{name[(versionIndex + 1)..]})";
: name[..versionIndex];
})
.Where(t => t is not null)
.ToArray();
Expand Down
137 changes: 76 additions & 61 deletions src/Uno.UI.RemoteControl/HotReload/HotReloadStatusView.Entries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,16 @@
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using Uno.UI.RemoteControl.HotReload.Messages;
using static Uno.UI.RemoteControl.HotReload.ClientHotReloadProcessor;

namespace Uno.UI.RemoteControl.HotReload;

internal enum EntrySource
{
DevServer,
Engine,
Server,
Application
}

[Flags]
internal enum EntryIcon
{
// Status
Loading = 0x1,
Success = 0x2,
Warning = 0x4,
Error = 0x8,

// Source
Connection = 0x1 << 8,
HotReload = 0x2 << 8,
}

internal record DevServerEntry() : HotReloadLogEntry(EntrySource.DevServer, -1, DateTimeOffset.Now);

internal record EngineEntry() : HotReloadLogEntry(EntrySource.Engine, -1, DateTimeOffset.Now);


internal record ServerEntry : HotReloadLogEntry
{
public ServerEntry(HotReloadServerOperationData srvOp)
Expand All @@ -47,25 +25,22 @@ public ServerEntry(HotReloadServerOperationData srvOp)

public void Update(HotReloadServerOperationData srvOp)
{
string[] files = srvOp.FilePaths.Select(Path.GetFileName).ToArray()!;

IsSuccess = srvOp.Result switch
{
null => null,
HotReloadServerResult.Success or HotReloadServerResult.NoChanges => true,
_ => false
};
Description = srvOp.Result switch
Title = srvOp.Result switch
{
null => $"Processing changes{Join(files, "files")}.",
HotReloadServerResult.NoChanges => $"No changes detected by the server{Join(files, "files")}.",
HotReloadServerResult.Success => $"IDE successfully detected and compiled changes{Join(files, "files")}.",
HotReloadServerResult.RudeEdit => $"IDE detected changes{Join(files, "files")} but is not able to apply them.",
HotReloadServerResult.Failed => $"IDE detected changes{Join(files, "files")} but is not able to compile them.",
HotReloadServerResult.Aborted => $"Hot-reload has been cancelled (usually because some other changes has been detected).",
HotReloadServerResult.InternalError => "Hot-reload failed for due to an internal error.",
_ => $"Unknown IDE operation result: {srvOp.Result}."
HotReloadServerResult.NoChanges => "No changes detected.",
HotReloadServerResult.RudeEdit => "Rude edit detected, restart required.",
HotReloadServerResult.Failed => "Compilation errors.",
HotReloadServerResult.Aborted => "Operation cancelled.",
HotReloadServerResult.InternalError => "An error occured.",
_ => null
};
Description = Join(srvOp.FilePaths.Select(Path.GetFileName).ToArray()!);
Duration = srvOp.EndTime is not null ? srvOp.EndTime - srvOp.StartTime : null;

RaiseChanged();
Expand All @@ -82,29 +57,49 @@ public ApplicationEntry(HotReloadClientOperation localOp)

internal void Update(HotReloadClientOperation localOp)
{
var types = localOp.CuratedTypes;

IsSuccess = localOp.Result switch
{
null => null,
HotReloadClientResult.Success => true,
_ => false
};
Description = localOp.Result switch
Title = localOp.Result switch
{
null => $"Processing changes{Join(types, "types")} (total of {localOp.Types.Length} types updated).",
HotReloadClientResult.Success => $"Application received changes{Join(types, "types")} and updated the view (total of {localOp.Types.Length} types updated).",
HotReloadClientResult.Failed => $"Application received changes{Join(types, "types")} (total of {localOp.Types.Length} types updated) but failed to update the view ({localOp.Exceptions.FirstOrDefault()?.Message}).",
HotReloadClientResult.Ignored when localOp.Types is null or { Length: 0 } => $"Application received changes{Join(types, "types")} but view was not been updated because {localOp.IgnoreReason}.",
HotReloadClientResult.Ignored => $"Application received changes{Join(types, "types")} (total of {localOp.Types.Length} types updated) but view was not been updated because {localOp.IgnoreReason}.",
_ => $"Unknown application operation result: {localOp.Result}."
null => "Processing...",
HotReloadClientResult.Success => "Update successful.",
HotReloadClientResult.Failed => "An error occured.",
_ => null
};
Description = Join(localOp.CuratedTypes, localOp.Types.Length);
Duration = localOp.EndTime is not null ? localOp.EndTime - localOp.StartTime : null;

RaiseChanged();
}
}

public enum EntrySource
{
DevServer,
Engine,
Server,
Application
}

[Flags]
public enum EntryIcon
{
// Kind
Loading = 0x1,
Success = 0x2,
Warning = 0x3,
Error = 0x4,

// Source
Connection = 0x1 << 8,
HotReload = 0x2 << 8,
}


[Microsoft.UI.Xaml.Data.Bindable]
internal record HotReloadLogEntry(EntrySource Source, long Id, DateTimeOffset Timestamp) : INotifyPropertyChanged
{
Expand All @@ -113,25 +108,24 @@ internal record HotReloadLogEntry(EntrySource Source, long Id, DateTimeOffset Ti

public bool? IsSuccess { get; set; }
public TimeSpan? Duration { get; set; }
public string? Description { get; set; }

// Quick patch as we don't have MVUX
public string Title => $"{Source}";
public string? Title { get; set; }
public string? Description { get; set; }

public string TimeInfo => string.IsNullOrEmpty(GetDuration())
public string TimeInfo => Duration is null
? $"{Timestamp.LocalDateTime:HH:mm:ss}"
: $"{GetDuration()} - {Timestamp.LocalDateTime:HH:mm:ss}";

public EntryIcon Icon => (Source, IsSuccess) switch
{
(EntrySource.DevServer or EntrySource.Engine, null) => EntryIcon.Connection | EntryIcon.Warning, // Connection orange indicator
(EntrySource.DevServer or EntrySource.Engine, true) => EntryIcon.Connection | EntryIcon.Success, // Connection green indicator
(EntrySource.DevServer or EntrySource.Engine, false) => EntryIcon.Connection | EntryIcon.Error, // Connection red indicator
(EntrySource.DevServer or EntrySource.Engine, null) => EntryIcon.Connection | EntryIcon.Warning, // Screen orange indicator
(EntrySource.DevServer or EntrySource.Engine, true) => EntryIcon.Connection | EntryIcon.Success, // Screen green indicator
(EntrySource.DevServer or EntrySource.Engine, false) => EntryIcon.Connection | EntryIcon.Error, // Screen red indicator

// EntrySource.Application or EntrySource.Server
(_, null) => EntryIcon.HotReload | EntryIcon.Loading, // Loading wheel
(_, true) => EntryIcon.HotReload | EntryIcon.Success, // Fire with green indicator
(_, false) => EntryIcon.HotReload | EntryIcon.Error, // Fire with red indicator
(_, false) => EntryIcon.HotReload | EntryIcon.Loading, // Fir with red indicator
};

public string GetSource()
Expand All @@ -151,17 +145,38 @@ private string GetDuration()
=> Duration switch
{
null => string.Empty,
{ TotalMilliseconds: < 1000 } ms => $"{ms.TotalMilliseconds:F0} ms",
{ TotalSeconds: < 3 } s => $"{s.TotalSeconds:N0} s",
{ } d => $"{d:g}"
{ TotalMilliseconds: < 1000 } ms => $" - {ms.TotalMilliseconds:F0} ms",
{ } s => $" - {s.TotalSeconds:N0} s"
};

protected static string Join(string[] items, string itemType)
=> items switch
protected static string Join(string[] items, int? total = null, int max = 5)
{
const int maxLength = 70;

var sb = new StringBuilder(maxLength + 12 /* and xx more*/);
int i;
for (i = 0; i < Math.Min(items.Length, max); i++)
{
{ Length: 0 } => "",
{ Length: 1 } => $" in {items[0]}",
{ Length: <= 3 } => $" in {string.Join(",", items[..^1])} and {items[^1]}",
_ => $" in {string.Join(",", items[..3])} and {items.Length - 3} other {itemType}"
};
var item = items[i];
if (sb.Length + 2 /*, */ + item.Length < maxLength)
{
if (i is not 0) sb.Append(", ");
sb.Append(item);
}
else
{
break;
}
}

var remaining = total - i;
if (remaining > 0)
{
sb.Append(" and ");
sb.Append(remaining);
sb.Append(" more");
}

return sb.ToString();
}
}
Loading

0 comments on commit 8fc3672

Please sign in to comment.