217 lines
7.7 KiB
Plaintext
217 lines
7.7 KiB
Plaintext
@using RobotNet.VDA5050
|
|
@using RobotNet.VDA5050.Type
|
|
@using System.Net.Http.Json
|
|
@using RobotNet10.FleetManager.Shared.Models
|
|
@using RobotNet10.Shared
|
|
@inject HttpClient HttpClient
|
|
@inject ISnackbar Snackbar
|
|
|
|
<MudPaper Class="pa-4" Elevation="0">
|
|
<MudText Typo="Typo.h6" Class="mb-4">Manual Actions</MudText>
|
|
|
|
<MudStack Spacing="3">
|
|
<!-- Action Type Selector -->
|
|
<MudSelect @bind-Value="selectedActionType"
|
|
Label="Action Type"
|
|
Variant="Variant.Outlined"
|
|
T="ActionType">
|
|
@foreach (ActionType actionType in Enum.GetValues<ActionType>())
|
|
{
|
|
<MudSelectItem Value="@actionType">@actionType.ToString()</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
|
|
<!-- Blocking Type Selector -->
|
|
<MudSelect @bind-Value="selectedBlockingType"
|
|
Label="Blocking Type"
|
|
Variant="Variant.Outlined"
|
|
T="BlockingType">
|
|
@foreach (BlockingType blockingType in Enum.GetValues<BlockingType>())
|
|
{
|
|
<MudSelectItem Value="@blockingType">@blockingType.ToString()</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
|
|
<!-- Action Parameters -->
|
|
<MudText Typo="Typo.subtitle2">Action Parameters</MudText>
|
|
@foreach (var param in actionParameters)
|
|
{
|
|
<MudGrid>
|
|
<MudItem xs="5">
|
|
<MudTextField @bind-Value="param.Key"
|
|
Label="Key"
|
|
Variant="Variant.Outlined"
|
|
Margin="Margin.Dense" />
|
|
</MudItem>
|
|
<MudItem xs="5">
|
|
<MudTextField @bind-Value="param.Value"
|
|
Label="Value"
|
|
Variant="Variant.Outlined"
|
|
Margin="Margin.Dense" />
|
|
</MudItem>
|
|
<MudItem xs="2">
|
|
<MudIconButton Icon="@Icons.Material.Filled.Delete"
|
|
Color="Color.Error"
|
|
Size="Size.Small"
|
|
OnClick="@(() => RemoveParameter(param))" />
|
|
</MudItem>
|
|
</MudGrid>
|
|
}
|
|
|
|
<MudButton StartIcon="@Icons.Material.Filled.Add"
|
|
Variant="Variant.Outlined"
|
|
Color="Color.Primary"
|
|
OnClick="AddParameter">
|
|
Add Parameter
|
|
</MudButton>
|
|
|
|
<!-- Send Action Button -->
|
|
<MudButton Variant="Variant.Filled"
|
|
Color="Color.Primary"
|
|
StartIcon="@Icons.Material.Filled.Send"
|
|
OnClick="SendAction"
|
|
Disabled="@isSending"
|
|
FullWidth="true">
|
|
@if (isSending)
|
|
{
|
|
<MudProgressCircular Class="mr-2" Size="Size.Small" Indeterminate="true" />
|
|
<span>Sending...</span>
|
|
}
|
|
else
|
|
{
|
|
<span>Send Action</span>
|
|
}
|
|
</MudButton>
|
|
|
|
<!-- Action History -->
|
|
<MudDivider />
|
|
<MudText Typo="Typo.subtitle2">Recent Actions</MudText>
|
|
@if (actionHistory.Count > 0)
|
|
{
|
|
<MudStack Spacing="1" Style="height: 200px; overflow-y: auto">
|
|
@foreach (var action in actionHistory.Take(10))
|
|
{
|
|
<MudPaper Class="pa-2" Elevation="0">
|
|
<MudText Typo="Typo.body2">
|
|
<strong>@action.ActionType</strong> - @action.Timestamp.ToString("g")
|
|
</MudText>
|
|
</MudPaper>
|
|
}
|
|
</MudStack>
|
|
}
|
|
else
|
|
{
|
|
<MudText Typo="Typo.body2" Align="Align.Center">No actions sent yet</MudText>
|
|
}
|
|
</MudStack>
|
|
</MudPaper>
|
|
|
|
@code {
|
|
[Parameter]
|
|
public string RobotId { get; set; } = string.Empty;
|
|
|
|
private ActionType selectedActionType = ActionType.STATE_REQUEST;
|
|
private BlockingType selectedBlockingType = BlockingType.HARD;
|
|
private List<RobotNet.VDA5050.InstantAction.ActionParameter> actionParameters = new();
|
|
private List<SentAction> actionHistory = new();
|
|
private bool isSending = false;
|
|
|
|
|
|
private class SentAction
|
|
{
|
|
public ActionType ActionType { get; set; }
|
|
public DateTime Timestamp { get; set; }
|
|
}
|
|
|
|
private void AddParameter()
|
|
{
|
|
actionParameters.Add(new RobotNet.VDA5050.InstantAction.ActionParameter());
|
|
}
|
|
|
|
private void RemoveParameter(RobotNet.VDA5050.InstantAction.ActionParameter param)
|
|
{
|
|
actionParameters.Remove(param);
|
|
}
|
|
|
|
private async Task SendAction()
|
|
{
|
|
if (string.IsNullOrWhiteSpace(RobotId))
|
|
{
|
|
Snackbar.Add("Robot ID is required", Severity.Warning);
|
|
return;
|
|
}
|
|
|
|
isSending = true;
|
|
StateHasChanged();
|
|
|
|
try
|
|
{
|
|
// Build action request
|
|
var actionRequest = new RobotInstantActionModel
|
|
{
|
|
RobotId = RobotId,
|
|
Action = new RobotNet.VDA5050.InstantAction.Action
|
|
{
|
|
ActionId = Guid.NewGuid().ToString(),
|
|
BlockingType = selectedBlockingType,
|
|
ActionType = selectedActionType.ToJsonString(),
|
|
ActionParameters = [.. actionParameters.Where(p => !string.IsNullOrWhiteSpace(p.Key))],
|
|
}
|
|
};
|
|
|
|
// Call API endpoint (TODO: Create this endpoint in Phase 10)
|
|
var response = await HttpClient.PostAsJsonAsync($"/api/robotManager/InstantActions", actionRequest);
|
|
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var result = await response.Content.ReadFromJsonAsync<MessageResult>();
|
|
if(result is null)
|
|
{
|
|
Snackbar.Add($"Sending action is failed", Severity.Warning);
|
|
}
|
|
else if (!result.IsSuccess)
|
|
{
|
|
Snackbar.Add($"{result.Message}", Severity.Warning);
|
|
}
|
|
else
|
|
{
|
|
Snackbar.Add($"Action '{selectedActionType}' sent successfully", Severity.Success);
|
|
|
|
// Add to history
|
|
actionHistory.Insert(0, new SentAction
|
|
{
|
|
ActionType = selectedActionType,
|
|
Timestamp = DateTime.UtcNow
|
|
});
|
|
|
|
// Clear parameters
|
|
actionParameters.Clear();
|
|
}
|
|
}
|
|
else if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
{
|
|
Snackbar.Add($"Robot with ID '{RobotId}' not found", Severity.Error);
|
|
}
|
|
else if (response.StatusCode == System.Net.HttpStatusCode.BadRequest)
|
|
{
|
|
var error = await response.Content.ReadAsStringAsync();
|
|
Snackbar.Add($"Invalid action request: {error}", Severity.Warning);
|
|
}
|
|
else
|
|
{
|
|
var error = await response.Content.ReadAsStringAsync();
|
|
Snackbar.Add($"Error sending action: {error}", Severity.Error);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Snackbar.Add($"Error sending action: {ex.Message}", Severity.Error);
|
|
}
|
|
finally
|
|
{
|
|
isSending = false;
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
}
|