Initial commit

This commit is contained in:
2026-07-13 09:25:40 +07:00
parent c08ff54676
commit bccfb156d7
1938 changed files with 641646 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
@using MudBlazor
<MudDialog>
<TitleContent>
<MudText Typo="Typo.h6">Cancel Mission</MudText>
</TitleContent>
<DialogContent>
<MudText Typo="Typo.body1" Class="mb-3">
Are you sure you want to cancel mission <strong>@MissionName</strong>?
</MudText>
<MudTextField @bind-Value="_reason"
Label="Reason (optional)"
Placeholder="Enter reason for cancellation..."
Variant="Variant.Outlined"
Lines="3"
Counter="200"
MaxLength="200" />
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">Cancel</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Error" OnClick="Confirm">Cancel Mission</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] IMudDialogInstance Dialog { get; set; } = null!;
[Parameter] public string MissionName { get; set; } = "";
private string _reason = "";
private void Cancel() => Dialog.Cancel();
private void Confirm() => Dialog.Close(DialogResult.Ok(_reason?.Trim() ?? ""));
}

View File

@@ -0,0 +1,27 @@
@using MudBlazor
<MudDialog>
<TitleContent>
<MudText Typo="Typo.h6">@Title</MudText>
</TitleContent>
<DialogContent>
<MudText>@Message</MudText>
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">Cancel</MudButton>
<MudButton Variant="Variant.Filled" Color="@ConfirmColor" OnClick="Confirm">@ConfirmText</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] IMudDialogInstance Dialog { get; set; } = null!;
[Parameter] public string Title { get; set; } = "Confirm";
[Parameter] public string Message { get; set; } = "Are you sure?";
[Parameter] public string ConfirmText { get; set; } = "Confirm";
[Parameter] public Color ConfirmColor { get; set; } = Color.Primary;
private void Cancel() => Dialog.Cancel();
private void Confirm() => Dialog.Close(DialogResult.Ok(true));
}

View File

@@ -0,0 +1,62 @@
@using MudBlazor
<MudDialog>
<TitleContent>
<MudText Typo="Typo.h6">Create Backup</MudText>
</TitleContent>
<DialogContent>
<MudTextField @bind-Value="BackupName"
Label="Backup Name"
Placeholder="Enter backup name"
Required="true"
RequiredError="Backup name is required"
HelperText="Leave empty to use default timestamp name"
Variant="Variant.Outlined"
FullWidth="true"
@onkeydown="HandleKeyDown" />
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">Cancel</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="Submit">Create</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] IMudDialogInstance Dialog { get; set; } = null!;
private string BackupName { get; set; } = string.Empty;
protected override void OnInitialized()
{
// Default name based on current date/time: yyyy-MM-dd_HHmm
BackupName = DateTime.Now.ToString("yyyy-MM-dd_HHmm");
}
private void Cancel() => Dialog.Cancel();
private void Submit()
{
var name = BackupName?.Trim() ?? string.Empty;
// If empty, use default timestamp
if (string.IsNullOrWhiteSpace(name))
{
name = DateTime.Now.ToString("yyyy-MM-dd_HHmm");
}
Dialog.Close(DialogResult.Ok(name));
}
private void HandleKeyDown(KeyboardEventArgs e)
{
if (e.Key == "Enter")
{
Submit();
}
else if (e.Key == "Escape")
{
Cancel();
}
}
}

View File

@@ -0,0 +1,60 @@
@using MudBlazor
<MudDialog>
<TitleContent>
<MudText Typo="Typo.h6">Create New File</MudText>
</TitleContent>
<DialogContent>
<MudTextField @bind-Value="FileName"
Label="File Name"
Placeholder="Enter file name (e.g., MyFile.cs)"
Required="true"
RequiredError="File name is required"
HelperText="File must have .cs extension"
Variant="Variant.Outlined"
FullWidth="true"
@onkeydown="HandleKeyDown" />
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">Cancel</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="Submit">Create</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] IMudDialogInstance Dialog { get; set; } = null!;
private string FileName { get; set; } = string.Empty;
private void Cancel() => Dialog.Cancel();
private void Submit()
{
if (string.IsNullOrWhiteSpace(FileName))
{
return;
}
// Ensure .cs extension
var name = FileName.Trim();
if (!name.EndsWith(".cs", StringComparison.OrdinalIgnoreCase))
{
name += ".cs";
}
Dialog.Close(DialogResult.Ok(name));
}
private void HandleKeyDown(KeyboardEventArgs e)
{
if (e.Key == "Enter")
{
Submit();
}
else if (e.Key == "Escape")
{
Cancel();
}
}
}

View File

@@ -0,0 +1,52 @@
@using MudBlazor
<MudDialog>
<TitleContent>
<MudText Typo="Typo.h6">Create New Folder</MudText>
</TitleContent>
<DialogContent>
<MudTextField @bind-Value="FolderName"
Label="Folder Name"
Placeholder="Enter folder name"
Required="true"
RequiredError="Folder name is required"
Variant="Variant.Outlined"
FullWidth="true"
@onkeydown="HandleKeyDown" />
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">Cancel</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="Submit">Create</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] IMudDialogInstance Dialog { get; set; } = null!;
private string FolderName { get; set; } = string.Empty;
private void Cancel() => Dialog.Cancel();
private void Submit()
{
if (string.IsNullOrWhiteSpace(FolderName))
{
return;
}
Dialog.Close(DialogResult.Ok(FolderName.Trim()));
}
private void HandleKeyDown(KeyboardEventArgs e)
{
if (e.Key == "Enter")
{
Submit();
}
else if (e.Key == "Escape")
{
Cancel();
}
}
}

View File

@@ -0,0 +1,138 @@
@using MudBlazor
@using RobotNet10.ScriptEngine.Shared
<MudDialog>
<TitleContent>
<MudText Typo="Typo.h6">Edit Variable: @VariableName</MudText>
</TitleContent>
<DialogContent>
<MudText Typo="Typo.body2" Class="mb-3">Type: <strong>@TypeName</strong></MudText>
<MudTextField @bind-Value="NewValue"
Label="Value"
Placeholder="Enter new value"
Required="true"
RequiredError="Value is required"
HelperText="@HelperText"
Variant="Variant.Outlined"
FullWidth="true"
Error="@(!string.IsNullOrEmpty(ErrorMessage))"
ErrorText="@ErrorMessage"
@onkeydown="HandleKeyDown"
@bind-Value:after="ValidateValue" />
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">Cancel</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="Submit" Disabled="@(!IsValid)">Save</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] IMudDialogInstance Dialog { get; set; } = null!;
[Parameter] public string VariableName { get; set; } = string.Empty;
[Parameter] public string TypeName { get; set; } = string.Empty;
[Parameter] public string CurrentValue { get; set; } = string.Empty;
private string NewValue { get; set; } = string.Empty;
private string ErrorMessage { get; set; } = string.Empty;
private bool IsValid => string.IsNullOrEmpty(ErrorMessage) && !string.IsNullOrWhiteSpace(NewValue);
protected override void OnInitialized()
{
NewValue = CurrentValue;
ValidateValue();
}
private string HelperText => GetHelperText();
private string GetHelperText()
{
var type = ScriptHelpers.ResolveTypeFromString(TypeName);
if (type == null) return "";
return type switch
{
_ when type == typeof(bool) => "Enter 'true' or 'false'",
_ when type == typeof(int) => "Enter an integer value",
_ when type == typeof(long) => "Enter a long integer value",
_ when type == typeof(float) => "Enter a float value (e.g., 3.14)",
_ when type == typeof(double) => "Enter a double value (e.g., 3.14)",
_ when type == typeof(decimal) => "Enter a decimal value (e.g., 3.14)",
_ when type == typeof(char) => "Enter a single character",
_ when type == typeof(string) => "Enter a string value",
_ when type.IsEnum => $"Enter one of: {string.Join(", ", Enum.GetNames(type))}",
_ => "Enter a valid value"
};
}
private void ValidateValue()
{
ErrorMessage = string.Empty;
if (string.IsNullOrWhiteSpace(NewValue))
{
return; // Will be handled by Required validation
}
var type = ScriptHelpers.ResolveTypeFromString(TypeName);
if (type == null)
{
ErrorMessage = "Unknown type";
return;
}
// Check if type is supported
if (!ScriptHelpers.SupportedTypes.Values.Contains(type) && !type.IsEnum)
{
ErrorMessage = "Type not supported for editing";
return;
}
// Validate value can be converted to the type
try
{
if (type.IsEnum)
{
// Handle enum validation separately since ResolveValueFromString doesn't handle enums correctly
Enum.Parse(type, NewValue.Trim(), ignoreCase: true);
}
else if (!ScriptHelpers.ResolveValueFromString(NewValue.Trim(), type, out _))
{
ErrorMessage = $"Invalid value for type {TypeName}";
}
}
catch (ArgumentException)
{
ErrorMessage = $"Invalid value for type {TypeName}";
}
catch (Exception)
{
ErrorMessage = $"Failed to validate value for type {TypeName}";
}
}
private void Cancel() => Dialog.Cancel();
private void Submit()
{
if (!IsValid)
{
return;
}
Dialog.Close(DialogResult.Ok(NewValue.Trim()));
}
private void HandleKeyDown(KeyboardEventArgs e)
{
if (e.Key == "Enter" && IsValid)
{
Submit();
}
else if (e.Key == "Escape")
{
Cancel();
}
}
}

View File

@@ -0,0 +1,314 @@
@using MudBlazor
@using RobotNet10.ScriptEditor.Models
@using RobotNet10.ScriptEngine.Shared
<MudDialog>
<TitleContent>
<MudText Typo="Typo.h6">Create Mission: @MissionName</MudText>
</TitleContent>
<DialogContent>
@if (Parameters == null || Parameters.Length == 0)
{
<MudText Typo="Typo.body2">This mission has no parameters.</MudText>
}
else
{
@foreach (var param in Parameters)
{
@switch (param.Type)
{
case "System.Boolean":
<MudSwitch T="bool" Color="Color.Primary" @bind-Value="@param.BoolValue" />
break;
case "System.Byte":
<MudNumericField T="byte"
@bind-Value="@param.ByteValue"
Min="@System.Byte.MinValue"
Max="@System.Byte.MaxValue"
Label="@param.Type"
Error="@(!string.IsNullOrEmpty(param.Errors))"
ErrorText="@param.Errors"
ShrinkLabel="true"
Variant="Variant.Outlined"
Margin="Margin.Dense" />
break;
case "System.SByte":
<MudNumericField T="sbyte"
@bind-Value="@param.SByteValue"
Min="@System.SByte.MinValue"
Max="@System.SByte.MaxValue"
Label="@param.Type"
Error="@(!string.IsNullOrEmpty(param.Errors))"
ErrorText="@param.Errors"
ShrinkLabel="true"
Variant="Variant.Outlined"
Margin="Margin.Dense" />
break;
case "System.Int16":
<MudNumericField T="short"
@bind-Value="@param.ShortValue"
Min="@System.Int16.MinValue"
Max="@System.Int16.MaxValue"
Label="@param.Type"
Error="@(!string.IsNullOrEmpty(param.Errors))"
ErrorText="@param.Errors"
ShrinkLabel="true"
Variant="Variant.Outlined"
Margin="Margin.Dense" />
break;
case "System.UInt16":
<MudNumericField T="ushort"
@bind-Value="@param.UShortValue"
Min="@System.UInt16.MinValue"
Max="@System.UInt16.MaxValue"
Label="@param.Type"
Error="@(!string.IsNullOrEmpty(param.Errors))"
ErrorText="@param.Errors"
ShrinkLabel="true"
Variant="Variant.Outlined"
Margin="Margin.Dense" />
break;
case "System.Int32":
<MudNumericField T="int"
@bind-Value="@param.IntValue"
Min="@System.Int32.MinValue"
Max="@System.Int32.MaxValue"
Label="@param.Type"
Error="@(!string.IsNullOrEmpty(param.Errors))"
ErrorText="@param.Errors"
ShrinkLabel="true"
Variant="Variant.Outlined"
Margin="Margin.Dense" />
break;
case "System.UInt32":
<MudNumericField T="uint"
@bind-Value="@param.UIntValue"
Min="@System.UInt32.MinValue"
Max="@System.UInt32.MaxValue"
Label="@param.Type"
Error="@(!string.IsNullOrEmpty(param.Errors))"
ErrorText="@param.Errors"
ShrinkLabel="true"
Variant="Variant.Outlined"
Margin="Margin.Dense" />
break;
case "System.Int64":
<MudNumericField T="long"
@bind-Value="@param.LongValue"
Min="@System.Int64.MinValue"
Max="@System.Int64.MaxValue"
Label="@param.Type"
Error="@(!string.IsNullOrEmpty(param.Errors))"
ErrorText="@param.Errors"
ShrinkLabel="true"
Variant="Variant.Outlined"
Margin="Margin.Dense" />
break;
case "System.UInt64":
<MudNumericField T="ulong"
@bind-Value="@param.ULongValue"
Min="@System.UInt64.MinValue"
Max="@System.UInt64.MaxValue"
Label="@param.Type"
Error="@(!string.IsNullOrEmpty(param.Errors))"
ErrorText="@param.Errors"
ShrinkLabel="true"
Variant="Variant.Outlined"
Margin="Margin.Dense" />
break;
case "System.Single":
<MudNumericField T="float"
@bind-Value="@param.FloatValue"
Min="@System.Single.MinValue"
Max="@System.Single.MaxValue"
Label="@param.Type"
Error="@(!string.IsNullOrEmpty(param.Errors))"
ErrorText="@param.Errors"
ShrinkLabel="true"
Variant="Variant.Outlined"
Margin="Margin.Dense" />
break;
case "System.Double":
<MudNumericField T="double"
@bind-Value="@param.DoubleValue"
Min="@System.Double.MinValue"
Max="@System.Double.MaxValue"
Label="@param.Type"
Error="@(!string.IsNullOrEmpty(param.Errors))"
ErrorText="@param.Errors"
ShrinkLabel="true"
Variant="Variant.Outlined"
Margin="Margin.Dense" />
break;
case "System.Decimal":
<MudNumericField T="double"
@bind-Value="@param.DecimalValue"
Label="@param.Type"
Error="@(!string.IsNullOrEmpty(param.Errors))"
ErrorText="@param.Errors"
ShrinkLabel="true"
Variant="Variant.Outlined"
Margin="Margin.Dense" />
break;
case "System.String":
<MudTextField @bind-Value="@param.StringValue"
Label="@param.Type"
Error="@(!string.IsNullOrEmpty(param.Errors))"
ErrorText="@param.Errors"
ShrinkLabel="true"
Variant="Variant.Outlined"
Margin="Margin.Dense" />
break;
case "System.Char":
<MudTextField @bind-Value="@param.CharValue"
MaxLength="1"
Label="@param.Type"
Error="@(!string.IsNullOrEmpty(param.Errors))"
ErrorText="@param.Errors"
ShrinkLabel="true"
Variant="Variant.Outlined"
Margin="Margin.Dense" />
break;
case "System.Threading.CancellationToken":
<span>
&lt;CancellationToken&gt;
</span>
break;
default:
<MudAlert Severity="Severity.Error" Dense>Unsupport parameter with type @param.Type</MudAlert>
break;
}
}
}
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">Cancel</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="Submit" Disabled="@(!IsValid)">Create</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] IMudDialogInstance Dialog { get; set; } = null!;
[Parameter, EditorRequired]
public ScriptMissionDto Model { get; set; } = default!;
public string MissionName => Model.Name;
private ScriptMissionParameterValueModel[] Parameters = [];
private bool IsValid => Parameters.All(p => string.IsNullOrEmpty(p.Errors));
protected override void OnAfterRender(bool firstRender)
{
base.OnAfterRender(firstRender);
if (firstRender)
{
Parameters = [.. Model.Parameters.Select(p => new ScriptMissionParameterValueModel(p.Name, p.Type, p.Default ?? ""))];
for (int i = 0; i < Parameters.Length; i++)
{
ValidateParameter(i);
}
StateHasChanged();
}
}
private bool HasDefaultValue(int index)
{
if (index < 0 || index >= Parameters.Length) return false;
return !string.IsNullOrEmpty(Parameters[index].Default);
}
private string GetHelperText(string typeName)
{
var type = ScriptHelpers.ResolveTypeFromString(typeName);
if (type == null) return "";
return type switch
{
_ when type == typeof(bool) => "Enter 'true' or 'false'",
_ when type == typeof(int) => "Enter an integer value",
_ when type == typeof(long) => "Enter a long integer value",
_ when type == typeof(float) => "Enter a float value (e.g., 3.14f)",
_ when type == typeof(double) => "Enter a double value (e.g., 3.14)",
_ when type == typeof(decimal) => "Enter a decimal value (e.g., 3.14)",
_ when type == typeof(char) => "Enter a single character",
_ when type == typeof(string) => "Enter a string value",
_ when type.IsEnum => $"Enter one of: {string.Join(", ", Enum.GetNames(type))}",
_ => "Enter a valid value"
};
}
private void ValidateParameter(int index)
{
if (index < 0 || index >= Parameters.Length) return;
if(Parameters[index].Type == "System.Threading.CancellationToken")
{
// No validation needed
return;
}
Parameters[index].Errors = string.Empty;
var param = Parameters[index];
var value = Parameters[index].ToString();
// Allow empty if has default value
if (string.IsNullOrWhiteSpace(value) && !string.IsNullOrEmpty(param.Default))
{
return;
}
if (string.IsNullOrWhiteSpace(value) && string.IsNullOrEmpty(param.Default))
{
Parameters[index].Errors = "Value is required";
return;
}
var type = ScriptHelpers.ResolveTypeFromString(param.Type);
if (type == null)
{
Parameters[index].Errors = "Unknown type";
return;
}
try
{
if (type.IsEnum)
{
Enum.Parse(type, value.Trim(), ignoreCase: true);
}
else if (!ScriptHelpers.ResolveValueFromString(value.Trim(), type, out _))
{
Parameters[index].Errors = $"Invalid value for type {param.Type}";
}
}
catch (ArgumentException)
{
Parameters[index].Errors = $"Invalid value for type {param.Type}";
}
catch (Exception)
{
Parameters[index].Errors = $"Failed to validate value for type {param.Type}";
}
}
private void Cancel() => Dialog.Cancel();
private void Submit()
{
if (!IsValid) return;
var parameters = new Dictionary<string, string>();
for (int i = 0; i < Parameters.Length; i++)
{
var value = Parameters[i].ToString();
// Use default if empty and default exists
if (string.IsNullOrWhiteSpace(value) && !string.IsNullOrEmpty(Parameters[i].Default))
{
value = Parameters[i].Default;
}
parameters[Parameters[i].Name] = value ?? string.Empty;
}
Dialog.Close(DialogResult.Ok(parameters));
}
}

View File

@@ -0,0 +1,126 @@
@using MudBlazor
@using RobotNet10.ScriptEditor.Clients
@using RobotNet10.ScriptEngine.Shared
@using RobotNet10.Shared
@implements IAsyncDisposable
<MudDialog>
<TitleContent>
<MudText Typo="Typo.h6">Mission Log: @MissionName</MudText>
</TitleContent>
<DialogContent>
<MudPaper Elevation="0" Class="pa-4" Style="max-height: 60vh; overflow-y: auto; font-family: 'Courier New', monospace; font-size: 0.875rem;">
@if (string.IsNullOrWhiteSpace(_logText))
{
<MudText Typo="Typo.body2" Color="Color.Default">No logs available</MudText>
}
else
{
<MudText Typo="Typo.body2" Style="white-space: pre-wrap; word-break: break-word;">@_logText</MudText>
}
</MudPaper>
</DialogContent>
<DialogActions>
<MudButton Variant="Variant.Text" OnClick="Close">Close</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] IMudDialogInstance Dialog { get; set; } = null!;
[Parameter] public Guid MissionId { get; set; }
[Parameter] public string MissionName { get; set; } = "";
[Parameter] public ScriptMissionState State { get; set; }
[Parameter] public string? InitialLog { get; set; }
[Inject] private InstanceMissionHubClient InstanceMissionClient { get; set; } = null!;
[Inject] private ConsoleHubClient ConsoleClient { get; set; } = null!;
private string _logText = "";
private bool _isListening = false;
private bool _isStopped => State == ScriptMissionState.Completed ||
State == ScriptMissionState.Canceled ||
State == ScriptMissionState.Error;
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
// Load initial log
if (!string.IsNullOrWhiteSpace(InitialLog))
{
_logText = InitialLog;
}
else
{
try
{
var log = await InstanceMissionClient.GetInstanceMissionLogAsync(MissionId);
if (!string.IsNullOrWhiteSpace(log))
{
_logText = log;
}
}
catch (Exception ex)
{
_logText = $"Error loading log: {ex.Message}";
}
}
// Start listening to realtime logs if mission is not stopped
if (!_isStopped)
{
_isListening = true;
// Subscribe to log events with proper level formatting
ConsoleClient.ErrorReceived += OnErrorReceived;
ConsoleClient.InfoReceived += OnInfoReceived;
ConsoleClient.WarningReceived += OnWarningReceived;
await ConsoleClient.StartAsync();
await ConsoleClient.RegisterMissionAsync(MissionId);
}
}
private void OnErrorReceived(string message)
{
var timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
_logText += $"[ERROR] {timestamp} | {message}{Environment.NewLine}";
InvokeAsync(StateHasChanged);
}
private void OnInfoReceived(string message)
{
var timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
_logText += $"[INFO] {timestamp} | {message}{Environment.NewLine}";
InvokeAsync(StateHasChanged);
}
private void OnWarningReceived(string message)
{
var timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
_logText += $"[WARN] {timestamp} | {message}{Environment.NewLine}";
InvokeAsync(StateHasChanged);
}
private void Close()
{
Dialog.Close();
}
public async ValueTask DisposeAsync()
{
if (_isListening && ConsoleClient.IsConnected)
{
try
{
ConsoleClient.ErrorReceived -= OnErrorReceived;
ConsoleClient.InfoReceived -= OnInfoReceived;
ConsoleClient.WarningReceived -= OnWarningReceived;
await ConsoleClient.UnregisterMissionAsync(MissionId);
await ConsoleClient.StopAsync();
}
catch { /* Ignore */ }
}
}
}

View File

@@ -0,0 +1,30 @@
@using MudBlazor
<MudDialog >
<TitleContent>
<MudText Typo="Typo.h6">Edit Permission Revoked</MudText>
</TitleContent>
<DialogContent>
<MudText Typo="Typo.body1">
Another user has taken edit permission. Your changes may not be saved.
</MudText>
<MudText Typo="Typo.body2" Class="mt-3">
Please reload the page to request edit permission again.
</MudText>
</DialogContent>
<DialogActions>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="HandleReloadPage">Reload Page</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] IMudDialogInstance Dialog { get; set; } = null!;
[Parameter] public Action? OnReload { get; set; }
private void HandleReloadPage()
{
Dialog.Close();
OnReload?.Invoke();
}
}

View File

@@ -0,0 +1,77 @@
@using MudBlazor
<MudDialog>
<TitleContent>
<MudText Typo="Typo.h6">Rename @ItemType</MudText>
</TitleContent>
<DialogContent>
<MudTextField @bind-Value="NewName"
Label="@LabelText"
Placeholder="Enter new name"
Required="true"
RequiredError="Name is required"
HelperText="@HelperText"
Variant="Variant.Outlined"
FullWidth="true"
@onkeydown="HandleKeyDown" />
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">Cancel</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="Submit">Rename</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] IMudDialogInstance Dialog { get; set; } = null!;
[Parameter] public string CurrentName { get; set; } = string.Empty;
[Parameter] public string ItemType { get; set; } = "Item";
[Parameter] public bool RequireCsExtension { get; set; } = false;
private string NewName { get; set; } = string.Empty;
protected override void OnInitialized()
{
NewName = CurrentName;
}
private string LabelText => $"{ItemType} Name";
private string HelperText => RequireCsExtension ? "File must have .cs extension" : "";
private void Cancel() => Dialog.Cancel();
private void Submit()
{
if (string.IsNullOrWhiteSpace(NewName))
{
return;
}
var name = NewName.Trim();
if (RequireCsExtension && !name.EndsWith(".cs", StringComparison.OrdinalIgnoreCase))
{
name += ".cs";
}
if (name == CurrentName)
{
Cancel();
return;
}
Dialog.Close(DialogResult.Ok(name));
}
private void HandleKeyDown(KeyboardEventArgs e)
{
if (e.Key == "Enter")
{
Submit();
}
else if (e.Key == "Escape")
{
Cancel();
}
}
}

View File

@@ -0,0 +1,73 @@
@using MudBlazor
@using RobotNet10.ScriptEngine.Shared
<MudDialog>
<TitleContent>
<MudText Typo="Typo.h6">Restore Backup</MudText>
</TitleContent>
<DialogContent>
@if (Backups == null || Backups.Length == 0)
{
<MudText>No backups available.</MudText>
}
else
{
<MudSelect @bind-Value="SelectedBackup"
Label="Select Backup"
Variant="Variant.Outlined"
FullWidth="true">
@foreach (var backup in Backups)
{
<MudSelectItem Value="@backup.FileName">
@backup.FileName - @backup.CreatedAt.ToString("yyyy-MM-dd HH:mm:ss") (@FormatSize(backup.Size))
</MudSelectItem>
}
</MudSelect>
}
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">Cancel</MudButton>
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
OnClick="Submit"
Disabled="@(Backups == null || Backups.Length == 0 || string.IsNullOrWhiteSpace(SelectedBackup))">
Restore
</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] IMudDialogInstance Dialog { get; set; } = null!;
[Parameter] public ScriptBackupInfo[] Backups { get; set; } = Array.Empty<ScriptBackupInfo>();
private string? SelectedBackup { get; set; }
protected override void OnInitialized()
{
// Select first backup by default (newest)
if (Backups != null && Backups.Length > 0)
{
SelectedBackup = Backups[0].FileName;
}
}
private string FormatSize(long size)
{
if (size < 1024) return $"{size} B";
if (size < 1024 * 1024) return $"{size / 1024.0:F2} KB";
return $"{size / (1024.0 * 1024.0):F2} MB";
}
private void Cancel() => Dialog.Cancel();
private void Submit()
{
if (string.IsNullOrWhiteSpace(SelectedBackup))
{
return;
}
Dialog.Close(DialogResult.Ok(SelectedBackup));
}
}