@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 Create Robot @if (isLoadingModels) { } else { @foreach (var model in robotModels) { @model.ModelName } } @if (isLoadingMaps) { Loading maps... } else if (mapLevels != null && mapLevels.Any()) { No Map @foreach (var mapLevel in mapLevels) { @mapLevel.DisplayName } } else { No maps available } Cancel @if (isCreating) { Creating... } else { Create } @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 robotModels = new(); private List mapLevels = new(); private Dictionary 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(); 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(); } 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; } }