Files
I150/srcs/RobotNet10/FleetManager/RobotNet10.FleetManager.Client/Components/RobotManager/Dialogs/CreateRobotDialog.razor
2026-07-03 16:37:12 +07:00

249 lines
8.2 KiB
Plaintext

@using RobotNet10.FleetManager.Shared.DTOs.Robot
@using RobotNet10.FleetManager.Shared.DTOs.RobotModel
@using RobotNet10.FleetManager.Client.Services
@using RobotNet10.MapEditor.Services.API
@using RobotNet10.MapEditor.Shared.DTOs.Layout
@inject ISnackbar Snackbar
@inject MapManagerApiService MapApiService
<MudDialog>
<TitleContent>
<MudText Typo="Typo.h6">
<MudIcon Icon="@Icons.Material.Filled.Add" Color="Color.Primary" Class="mr-2" />
Create Robot
</MudText>
</TitleContent>
<DialogContent>
<MudStack Spacing="3">
<MudTextField @bind-Value="request.RobotId"
Label="Robot ID *"
Variant="Variant.Outlined"
ErrorText="@GetValidationError("RobotId")"
HelperText="Unique identifier for the robot" />
<MudTextField @bind-Value="request.Name"
Label="Name *"
Variant="Variant.Outlined"
ErrorText="@GetValidationError("Name")" />
<MudSelect @bind-Value="request.ModelId"
Label="Robot Model *"
Variant="Variant.Outlined"
T="Guid"
ErrorText="@GetValidationError("ModelId")">
@if (isLoadingModels)
{
<MudProgressCircular Size="Size.Small" Indeterminate="true" />
}
else
{
@foreach (var model in robotModels)
{
<MudSelectItem Value="@model.Id">@model.ModelName</MudSelectItem>
}
}
</MudSelect>
<MudSelect @bind-Value="request.MapId"
Label="Map (Optional)"
Variant="Variant.Outlined"
Clearable="true"
T="Guid?"
Disabled="@isLoadingMaps"
ErrorText="@GetValidationError("MapId")">
@if (isLoadingMaps)
{
<MudSelectItem Value="@((Guid?)null)" Disabled="true">Loading maps...</MudSelectItem>
}
else if (mapLevels != null && mapLevels.Any())
{
<MudSelectItem Value="@((Guid?)null)">No Map</MudSelectItem>
@foreach (var mapLevel in mapLevels)
{
<MudSelectItem Value="@((Guid?)mapLevel.LevelId)">@mapLevel.DisplayName</MudSelectItem>
}
}
else
{
<MudSelectItem Value="@((Guid?)null)" Disabled="true">No maps available</MudSelectItem>
}
</MudSelect>
</MudStack>
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">Cancel</MudButton>
<MudButton Color="Color.Primary"
Variant="Variant.Filled"
OnClick="Submit"
Disabled="@isCreating">
@if (isCreating)
{
<MudProgressCircular Class="mr-2" Size="Size.Small" Indeterminate="true" />
<span>Creating...</span>
}
else
{
<span>Create</span>
}
</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] private IMudDialogInstance? MudDialog { get; set; }
[Parameter] public RobotApiService RobotApiService { get; set; } = null!;
[Parameter] public RobotModelApiService RobotModelApiService { get; set; } = null!;
private CreateRobotRequest request = new();
private List<RobotModelDto> robotModels = new();
private List<MapLevelInfo> mapLevels = new();
private Dictionary<string, string> validationErrors = new();
private bool isCreating = false;
private bool isLoadingModels = true;
private bool isLoadingMaps = false;
protected override async Task OnInitializedAsync()
{
await Task.WhenAll(
LoadRobotModelsAsync(),
LoadMapsAsync()
);
}
private async Task LoadRobotModelsAsync()
{
isLoadingModels = true;
try
{
robotModels = await RobotModelApiService.GetAllAsync();
}
catch (Exception ex)
{
Snackbar.Add($"Error loading robot models: {ex.Message}", Severity.Error);
}
finally
{
isLoadingModels = false;
StateHasChanged();
}
}
private async Task LoadMapsAsync()
{
isLoadingMaps = true;
StateHasChanged();
try
{
// Load all layouts (with nested versions and levels)
var layouts = await MapApiService.SearchLayoutsAsync();
if (layouts is null) return;
// Get all levels from all layouts (not just active layouts)
mapLevels = new List<MapLevelInfo>();
foreach (var layout in layouts.Where(l => l.Versions != null))
{
if (layout.Versions is null) continue;
foreach (var version in layout.Versions.Where(v => v.Levels != null))
{
if (version.Levels is null) continue;
foreach (var level in version.Levels.OrderBy(l => l.LevelOrder))
{
mapLevels.Add(new MapLevelInfo
{
LevelId = level.Id,
DisplayName = $"{layout.LayoutName} - {version.Version} - {level.LayoutLevelId}"
});
}
}
}
}
catch (Exception ex)
{
Snackbar.Add($"Error loading maps: {ex.Message}", Severity.Warning);
mapLevels = new List<MapLevelInfo>();
}
finally
{
isLoadingMaps = false;
StateHasChanged();
}
}
private bool Validate()
{
validationErrors.Clear();
if (string.IsNullOrWhiteSpace(request.RobotId))
{
validationErrors["RobotId"] = "Robot ID is required";
}
else if (request.RobotId.Length > 64)
{
validationErrors["RobotId"] = "Robot ID must be 64 characters or less";
}
if (string.IsNullOrWhiteSpace(request.Name))
{
validationErrors["Name"] = "Name is required";
}
else if (request.Name.Length > 256)
{
validationErrors["Name"] = "Name must be 256 characters or less";
}
if (request.ModelId == Guid.Empty)
{
validationErrors["ModelId"] = "Robot Model is required";
}
return validationErrors.Count == 0;
}
private string? GetValidationError(string fieldName)
{
return validationErrors.TryGetValue(fieldName, out var error) ? error : null;
}
private void Cancel()
{
MudDialog?.Cancel();
}
private async Task Submit()
{
if (!Validate())
{
Snackbar.Add("Please fix validation errors", Severity.Warning);
StateHasChanged();
return;
}
isCreating = true;
StateHasChanged();
try
{
var created = await RobotApiService.CreateAsync(request);
Snackbar.Add($"Robot '{request.Name}' created successfully", Severity.Success);
MudDialog?.Close(DialogResult.Ok(created));
}
catch (Exception ex)
{
Snackbar.Add($"Error creating robot: {ex.Message}", Severity.Error);
}
finally
{
isCreating = false;
StateHasChanged();
}
}
// Helper class for map level display
private class MapLevelInfo
{
public Guid LevelId { get; set; }
public string DisplayName { get; set; } = string.Empty;
}
}