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,11 @@
@page "/config-manager"
@rendermode RobotNet10.Components.RenderMode.InteractiveWebAssemblyNoPrerender
<PageTitle>Configuration Manager</PageTitle>
<RobotNet10.CustomConfigurationEditor.Components.ConfigManager.ConfigManagerComponent />
<MudThemeProvider IsDarkMode />
<MudPopoverProvider />
<MudDialogProvider />
<MudSnackbarProvider />

View File

@@ -0,0 +1,16 @@
@page "/layout-editor/{LevelId:guid}"
@rendermode RobotNet10.Components.RenderMode.InteractiveWebAssemblyNoPrerender
<PageTitle>Layout Editor</PageTitle>
<RobotNet10.MapEditor.Components.LayoutEditor.LayoutEditorComponent LevelId="@LevelId" />
<MudThemeProvider IsDarkMode />
<MudPopoverProvider />
<MudDialogProvider />
<MudSnackbarProvider />
@code {
[Parameter]
public Guid LevelId { get; set; }
}

View File

@@ -0,0 +1,11 @@
@page "/layout-manager"
@rendermode InteractiveWebAssemblyNoPrerender
<PageTitle>Layout Manager</PageTitle>
<RobotNet10.MapEditor.Components.LayoutManager.LayoutManagerComponent />
<MudThemeProvider IsDarkMode />
<MudPopoverProvider />
<MudDialogProvider />
<MudSnackbarProvider />

View File

@@ -0,0 +1,225 @@
@page "/logs"
@rendermode InteractiveWebAssemblyNoPrerender
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using System.Text.Json.Serialization
@inject IJSRuntime JSRuntime
@inject HttpClient Http
@inject IConfiguration Configuration
@inject ISnackbar Snackbar
<PageTitle>Logs</PageTitle>
<div class="w-100 h-100 d-flex flex-column">
<div class="d-flex flex-row align-items-center justify-content-between" style="border-bottom: 1px solid silver">
<MudTextField Class="mt-1 ms-2" T="string" Value="FilterLog" Adornment="Adornment.End" ValueChanged="OnSearch" AdornmentIcon="@Icons.Material.Filled.Search"
IconSize="Size.Medium" Variant="Variant.Outlined" Margin="Margin.Dense" AdornmentColor="Color.Secondary" Label="Search"></MudTextField>
<MudSpacer />
<div class="m-1 d-flex flex-row">
<MudDatePicker Class="mx-4" Label="Date" Date="DateLog" DateChanged="OnDateChanged" MaxDate="DateTime.Today" Variant="Variant.Outlined" Color="Color.Primary"
ShowToolbar="false" Margin="Margin.Dense" AdornmentColor="Color.Primary" />
<MudTooltip Text="Export">
<MudFab Class="mt-2" Color="Color.Info" StartIcon="@Icons.Material.Filled.ImportExport" Size="Size.Small" OnClick="ExportLogs" />
</MudTooltip>
<MudTooltip Text="Refresh">
<MudFab Class="mx-4 mt-2" StartIcon="@Icons.Material.Filled.Refresh" Color="Color.Primary" Size="Size.Small" OnClick="LoadLogs" />
</MudTooltip>
</div>
</div>
<div class="flex-grow-1 mt-2 ms-2 position-relative" style="background-color: rgba(0, 0, 0, 0);">
<MudOverlay Visible="IsLoading" DarkBackground="true" Absolute="true">
<MudProgressCircular Color="Color.Info" Indeterminate="true" />
</MudOverlay>
<div class="h-100 w-100 position-relative">
<div class="log-container" @ref="LogContainerRef">
@if (ShowRawLog)
{
<div class="d-flex justify-content-center my-3">
<div><MudButton Variant="Variant.Outlined" Size="Size.Small" OnClick="@(() => ShowRawLog = false)">Normal</MudButton></div>
</div>
<big style="font-size: 14px;">
@foreach (var log in ShowLogs)
{
@log <br />
}
</big>
}
else
{
@if (SearchLogs.Count < ShowLogs.Count)
{
<div class="d-flex justify-content-center my-3">
<div><MudButton Variant="Variant.Outlined" Size="Size.Small" OnClick="@(() => ShowRawLog = true)">Raw log</MudButton></div>
</div>
}
@foreach (var log in SearchLogs)
{
<div class="log">
<span class="log-head @log.BackgroundClass">
@log.Time <span class="log-level">@log.Level</span>
</span>
<span>@log.Message</span>
@if (log.HasException)
{
<br />
<pre class="log-exception">
@log.Exception
</pre>
}
</div>
}
}
</div>
</div>
</div>
</div>
<script>
window.ScrollToBottom = (element) => {
if (element) {
element.scrollTop = element.scrollHeight;
}
};
</script>
<MudThemeProvider IsDarkMode />
<MudPopoverProvider />
<MudDialogProvider />
<MudSnackbarProvider />
@code {
private DateTime DateLog = DateTime.Today;
private bool IsLoading;
private readonly List<string> ShowLogs = new();
private readonly List<LoggerModel> SearchLogs = new();
private ElementReference LogContainerRef { get; set; }
private bool ShowRawLog { get; set; }
private string? FilterLog { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (!firstRender) return;
await LoadLogs();
}
private async Task LoadLogs()
{
try
{
IsLoading = true;
ShowLogs.Clear();
StateHasChanged();
var logs = await Http.GetFromJsonAsync<IEnumerable<string>>($"api/LogsManager?date={DateLog}");
ShowLogs.AddRange(logs ?? []);
IsLoading = false;
StateHasChanged();
await ReloadLogs();
}
catch (AccessTokenNotAvailableException ex)
{
ex.Redirect();
return;
}
}
private async Task ReloadLogs()
{
IsLoading = true;
SearchLogs.Clear();
StateHasChanged();
foreach (var line in ShowLogs.Where(log => string.IsNullOrEmpty(FilterLog) || log.Contains(FilterLog)).TakeLast(2000))
{
try
{
var log = System.Text.Json.JsonSerializer.Deserialize<LoggerModel>(line);
if (log is not null) SearchLogs.Add(log);
}
catch (System.Text.Json.JsonException)
{
continue;
}
}
IsLoading = false;
StateHasChanged();
await JSRuntime.InvokeVoidAsync("ScrollToBottom", LogContainerRef);
}
private async Task OnSearch(string text)
{
FilterLog = text;
await ReloadLogs();
}
private async Task OnDateChanged(DateTime? date)
{
if (date is not null && date.HasValue)
{
DateLog = date.Value;
await LoadLogs();
}
}
private async Task ExportLogs()
{
try
{
var fileContent = await Http.GetFromJsonAsync<IEnumerable<string>>($"api/LogsManager?date={DateLog}");
var formattedContent = string.Join("\n", fileContent ?? []);
var fileName = $"LogsManager_{DateLog.ToShortDateString()}.txt";
await JSRuntime.InvokeVoidAsync("downloadFile", fileName, formattedContent, "text/plain");
}
catch (Exception ex)
{
Snackbar.Add($"Lỗi khi tải file: {ex.Message}", Severity.Warning);
}
}
public class LoggerModel
{
[JsonPropertyName("time")]
public string? Time { get; set; }
[JsonPropertyName("level")]
public string? Level { get; set; }
[JsonPropertyName("message")]
public string? Message { get; set; }
[JsonPropertyName("exception")]
public string? Exception { get; set; }
public string ColorClass => Level switch
{
"WARN" => "text-warning",
"INFO" => "text-info",
"DEBUG" => "text-success",
"ERROR" => "text-danger",
"FATAL" => "text-secondary",
_ => "text-muted",
};
public string BackgroundClass => Level switch
{
"WARN" => "bg-warning text-dark",
"INFO" => "bg-info text-dark",
"DEBUG" => "bg-success text-white",
"ERROR" => "bg-danger text-white",
"FATAL" => "bg-secondary text-white",
_ => "bg-dark text-white",
};
public bool HasException => !string.IsNullOrEmpty(Exception);
}
}

View File

@@ -0,0 +1,38 @@
.log-container {
height: 100%;
width: 100%;
overflow-x: hidden;
overflow-y: auto;
position: absolute;
top: 0px;
left: 0px;
display: flex;
flex-direction: column;
}
.log {
word-wrap: break-word;
line-height: 18px;
margin-bottom: 12px;
}
.log-logger {
color: rgba(0, 0, 0, 0.3);
font-size: 12px;
}
.log-level {
display: inline-block;
width: 60px;
}
.log-head {
border-radius: 3px;
padding: 2px 5px;
}
.log-exception {
line-height: 16px;
margin-left: 30px;
color: crimson;
}

View File

@@ -0,0 +1,11 @@
@page "/missions"
@rendermode InteractiveWebAssemblyNoPrerender
<PageTitle>Mission Manager</PageTitle>
<RobotNet10.ScriptEditor.InstanceMissionManager />
<MudThemeProvider IsDarkMode />
<MudPopoverProvider />
<MudDialogProvider />
<MudSnackbarProvider />

View File

@@ -0,0 +1,281 @@
@page "/robots/{robotId}/detail"
@rendermode RobotNet10.Components.RenderMode.InteractiveWebAssemblyNoPrerender
@implements IAsyncDisposable
<PageTitle>Robot Detail - @robotName</PageTitle>
@using RobotNet10.FleetManager.Client.Services
@using RobotNet10.FleetManager.Client.Components.RobotDetail
@using RobotNet10.FleetManager.Shared.DTOs.Robot
@using RobotNet.VDA5050.State
@using RobotNet.VDA5050.Visualization
@using Microsoft.AspNetCore.SignalR.Client
@inject RobotApiService RobotApiService
@inject RobotStateHubClient HubClient
@inject NavigationManager NavigationManager
@inject ISnackbar Snackbar
<MudContainer MaxWidth="MaxWidth.ExtraExtraLarge" Class="mt-4">
<!-- Header -->
<MudPaper Class="pa-4 mb-4 align-content-center" MinHeight="80px">
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Spacing="3">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
<MudIconButton Icon="@Icons.Material.Filled.ArrowBack" OnClick="NavigateBack" />
<MudText Typo="Typo.h5">Robot Detail: @robotName</MudText>
</MudStack>
<MudButton StartIcon="@Icons.Material.Filled.Refresh"
Variant="Variant.Outlined"
Color="Color.Primary"
OnClick="HandleRefresh"
Disabled="@isRefreshing">
@if (isRefreshing)
{
<MudProgressCircular Class="mr-2" Size="Size.Small" Indeterminate="true" />
}
Refresh
</MudButton>
</MudStack>
</MudPaper>
@if (isLoadingRobot)
{
<MudPaper Class="pa-4" Elevation="1">
<MudStack AlignItems="AlignItems.Center" Spacing="3">
<MudProgressCircular Color="Color.Primary" Indeterminate="true" Size="Size.Large" />
<MudText Typo="Typo.body1">Loading robot information...</MudText>
</MudStack>
</MudPaper>
}
else if (robot == null)
{
<MudPaper Class="pa-4" Elevation="1">
<MudAlert Severity="Severity.Error" Variant="Variant.Filled">
<MudText Typo="Typo.h6">Robot Not Found</MudText>
<MudText Typo="Typo.body2">The robot with ID '@RobotId' could not be found.</MudText>
<MudButton Variant="Variant.Text" Color="Color.Error" OnClick="NavigateBack" Class="mt-2">
<MudIcon Icon="@Icons.Material.Filled.ArrowBack" Class="mr-2" />
Go Back to Robot List
</MudButton>
</MudAlert>
</MudPaper>
}
else
{
<!-- Main Content -->
<MudGrid>
<!-- Left: State Cards with Tabs (60%) -->
<MudItem xs="12" md="7">
<MudPaper Class="pa-2" Elevation="1" Style="height: calc(100vh - 200px); overflow: hidden">
<MudTabs @bind-ActivePanelIndex="ActivePanelIndex" Elevation="0" Rounded="true" Color="Color.Primary">
<!-- Overview Tab -->
<MudTabPanel Text="Overview" Icon="@Icons.Material.Filled.Dashboard">
<MudStack Spacing="3" Class="mt-2" Style="overflow-y: auto; height: calc(100vh - 288px);">
<HeaderInfoCard @ref="HeaderInfoCardRef" />
<MudGrid Spacing="3">
<MudItem xs="12" md="6">
<PositionCard @ref="PositionCardRef" />
</MudItem>
<MudItem xs="12" md="6">
<VelocityCard @ref="VelocityCardRef" />
</MudItem>
</MudGrid>
<MudGrid Spacing="3">
<MudItem xs="12" md="6">
<BatteryCard @ref="BatteryCardRef" />
</MudItem>
<MudItem xs="12" md="6">
<SafetyStateCard @ref="SafetyStateCardRef" />
</MudItem>
</MudGrid>
</MudStack>
</MudTabPanel>
<!-- Navigation Tab -->
<MudTabPanel Text="Navigation" Icon="@Icons.Material.Filled.Navigation">
<MudStack Spacing="3" Class="mt-2" Style="overflow-y: auto; height: calc(100vh - 288px);">
<MapsCard @ref="MapsCardRef" />
<NodeStatesCard @ref="NodeStatesCardRef" />
<EdgeStatesCard @ref="EdgeStatesCardRef" />
</MudStack>
</MudTabPanel>
<!-- Orders & Actions Tab -->
<MudTabPanel Text="Orders & Actions" Icon="@Icons.Material.Filled.ListAlt">
<MudStack Spacing="3" Class="mt-2" Style="overflow-y: auto; height: calc(100vh - 288px);">
<OrderInfoCard @ref="OrderInfoCardRef" />
<ActionStatesCard @ref="ActionStatesCardRef" />
<LoadsCard @ref="LoadsCardRef" />
</MudStack>
</MudTabPanel>
<!-- Errors & Information Tab -->
<MudTabPanel Text="Errors & Info" Icon="@Icons.Material.Filled.Info">
<MudStack Spacing="3" Class="mt-2" Style="overflow-y: auto; height: calc(100vh - 288px);">
<ErrorsCard @ref="ErrorsCardRef" />
<InformationCard @ref="InformationCardRef" />
</MudStack>
</MudTabPanel>
</MudTabs>
</MudPaper>
</MudItem>
<!-- Right: Manual Actions & Orders (40%) -->
<MudItem xs="12" md="5">
<MudStack Spacing="3" Style="max-height: calc(100vh - 200px); overflow-y: auto;">
<MudPaper Class="pa-2" Elevation="2">
<ManualOrderPanel RobotId="@RobotId" MapId="@robot?.MapId" />
</MudPaper>
<MudPaper Class="pa-2" Elevation="2">
<ManualActionsPanel RobotId="@RobotId" />
</MudPaper>
</MudStack>
</MudItem>
</MudGrid>
}
</MudContainer>
<MudThemeProvider IsDarkMode />
<MudPopoverProvider />
<MudDialogProvider />
<MudSnackbarProvider />
@code {
[Parameter]
public string RobotId { get; set; } = string.Empty;
private RobotDto? robot;
private string robotName = "Loading...";
private bool isLoadingRobot = true;
private bool isRefreshing = false;
private HeaderInfoCard HeaderInfoCardRef = default!;
private PositionCard PositionCardRef = default!;
private VelocityCard VelocityCardRef = default!;
private BatteryCard BatteryCardRef = default!;
private SafetyStateCard SafetyStateCardRef = default!;
private MapsCard MapsCardRef = default!;
private NodeStatesCard NodeStatesCardRef = default!;
private EdgeStatesCard EdgeStatesCardRef = default!;
private OrderInfoCard OrderInfoCardRef = default!;
private ActionStatesCard ActionStatesCardRef = default!;
private LoadsCard LoadsCardRef = default!;
private ErrorsCard ErrorsCardRef = default!;
private InformationCard InformationCardRef = default!;
private int ActivePanelIndex = 0;
protected override async Task OnInitializedAsync()
{
await LoadRobotAsync();
await InitializeSignalRAsync();
}
private async Task LoadRobotAsync()
{
isLoadingRobot = true;
try
{
robot = await RobotApiService.GetByRobotIdAsync(RobotId);
if (robot != null)
{
robotName = robot.Name;
}
else
{
Snackbar.Add($"Robot with ID '{RobotId}' not found", Severity.Error);
}
}
catch (Exception ex)
{
Snackbar.Add($"Error loading robot: {ex.Message}", Severity.Error);
}
finally
{
isLoadingRobot = false;
StateHasChanged();
}
}
private async Task InitializeSignalRAsync()
{
try
{
// Register event handlers
HubClient.OnStateUpdate += HandleStateUpdate;
HubClient.OnConnectionError += HandleConnectionError;
// Connect and subscribe
await HubClient.ConnectAsync();
await HubClient.SubscribeToRobotAsync(RobotId);
}
catch (Exception ex)
{
Snackbar.Add($"Error connecting to SignalR: {ex.Message}", Severity.Error);
}
}
private void StateUpdate(StateMsg? state)
{
switch (ActivePanelIndex)
{
case 0:
HeaderInfoCardRef.Update(state);
BatteryCardRef.Update(state?.BatteryState);
SafetyStateCardRef.Update(state);
PositionCardRef.Update(state);
VelocityCardRef.Update(state);
break;
case 1:
MapsCardRef.Update(state);
NodeStatesCardRef.Update(state);
EdgeStatesCardRef.Update(state);
break;
case 2:
OrderInfoCardRef.Update(state);
ActionStatesCardRef.Update(state);
LoadsCardRef.Update(state);
break;
case 3:
ErrorsCardRef.Update(state?.Errors);
InformationCardRef.Update(state?.Information);
break;
}
}
private void HandleStateUpdate(StateMsg state)
{
if (state.SerialNumber != RobotId) return;
StateUpdate(state);
}
private void HandleConnectionError(string error)
{
Snackbar.Add($"SignalR connection error: {error}", Severity.Warning);
}
private async Task HandleRefresh()
{
isRefreshing = true;
StateHasChanged();
await LoadRobotAsync();
isRefreshing = false;
StateHasChanged();
}
private void NavigateBack()
{
NavigationManager.NavigateTo("/robots");
}
public async ValueTask DisposeAsync()
{
if (HubClient != null)
{
HubClient.OnStateUpdate -= HandleStateUpdate;
HubClient.OnConnectionError -= HandleConnectionError;
await HubClient.UnsubscribeFromRobotAsync(RobotId);
}
}
}

View File

@@ -0,0 +1,76 @@
@page "/robots"
@rendermode RobotNet10.Components.RenderMode.InteractiveWebAssemblyNoPrerender
<PageTitle>Robot Management</PageTitle>
@using RobotNet10.FleetManager.Client.Services
@using RobotNet10.FleetManager.Client.Components.RobotManager
@using RobotNet10.FleetManager.Client.Components.RobotManager.Dialogs
@using RobotNet10.FleetManager.Shared.DTOs.Robot
@inject RobotApiService RobotApiService
@inject RobotModelApiService RobotModelApiService
@inject IDialogService DialogService
@inject ISnackbar Snackbar
@inject NavigationManager NavigationManager
<MudContainer MaxWidth="MaxWidth.ExtraExtraLarge" Class="mt-4">
<!-- Header -->
<MudPaper Class="pa-4 mb-4 align-content-center" MinHeight="80px">
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Spacing="3">
<MudText Typo="Typo.h5">Robot Management</MudText>
<MudButton StartIcon="@Icons.Material.Filled.Add"
Variant="Variant.Filled"
Color="Color.Success"
OnClick="HandleCreate">
Add Robot
</MudButton>
</MudStack>
</MudPaper>
<!-- Main Content -->
<RobotTable @ref="TableRef"
RobotApiService="@RobotApiService"
RobotModelApiService="@RobotModelApiService"
OnRobotDeleted="@HandleDeleted"
OnRobotUpdated="@HandleUpdated" />
</MudContainer>
<MudThemeProvider IsDarkMode />
<MudPopoverProvider />
<MudDialogProvider />
<MudSnackbarProvider />
@code {
private RobotTable? TableRef;
private async Task HandleCreate()
{
var parameters = new DialogParameters
{
["RobotApiService"] = RobotApiService,
["RobotModelApiService"] = RobotModelApiService
};
var dialog = await DialogService.ShowAsync<CreateRobotDialog>("Create Robot", parameters,
new DialogOptions { MaxWidth = MaxWidth.Medium, FullWidth = true });
var result = await dialog.Result;
if (result != null && !result.Canceled)
{
await TableRef?.LoadDataAsync()!;
Snackbar.Add("Robot created successfully", Severity.Success);
}
}
private async Task HandleDeleted()
{
await TableRef?.LoadDataAsync()!;
Snackbar.Add("Robot deleted successfully", Severity.Success);
}
private async Task HandleUpdated()
{
await TableRef?.LoadDataAsync()!;
Snackbar.Add("Robot updated successfully", Severity.Success);
}
}

View File

@@ -0,0 +1,114 @@
@page "/robot-models"
@rendermode InteractiveWebAssemblyNoPrerender
<PageTitle>Robot Model Management</PageTitle>
@using RobotNet10.FleetManager.Client.Services
@using RobotNet10.FleetManager.Client.Components.RobotModelManager
@using RobotNet10.FleetManager.Client.Components.RobotModelManager.Dialogs
@using RobotNet10.FleetManager.Shared.DTOs.RobotModel
@inject RobotModelApiService ApiService
@inject IDialogService DialogService
@inject ISnackbar Snackbar
<MudContainer MaxWidth="MaxWidth.ExtraExtraLarge" Class="mt-4">
<!-- Header -->
<MudPaper Class="pa-4 mb-4 align-content-center" MinHeight="80px">
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Spacing="3">
<MudText Typo="Typo.h5">Robot Model Management</MudText>
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
<MudTextField Value="@searchText"
Placeholder="Search robot models..."
Variant="Variant.Outlined"
Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search"
Margin="Margin.Dense"
Style="min-width: 250px;"
Immediate="false"
T="string"
ValueChanged="TextSearchChanged"
Clearable="true" />
<MudButton StartIcon="@Icons.Material.Filled.Add"
Variant="Variant.Filled"
Color="Color.Success"
OnClick="HandleCreate">
Add Robot Model
</MudButton>
</MudStack>
</MudStack>
</MudPaper>
<!-- Main Content -->
<MudGrid>
<!-- Left: List Panel (60%) -->
<MudItem xs="12" md="7">
<RobotModelListPanel @ref="ListPanelRef"
ApiService="@ApiService"
SelectedRobotModelChanged="SelectedRobotModelChanged"
SearchText="@searchText" />
</MudItem>
<!-- Right: Details Panel (40%) -->
<MudItem xs="12" md="5">
<MudPaper Class="pa-3" Elevation="1" Style="height: calc(100vh - 169px); overflow-y: auto;">
@if (selectedRobotModel != null)
{
<RobotModelDetailsPanel RobotModel="@selectedRobotModel" />
}
else
{
<MudText Typo="Typo.body1" Align="Align.Center" Class="mt-8">
Select a robot model to view details
</MudText>
}
</MudPaper>
</MudItem>
</MudGrid>
</MudContainer>
<MudThemeProvider IsDarkMode />
<MudPopoverProvider />
<MudDialogProvider />
<MudSnackbarProvider />
@code {
private string searchText = string.Empty;
private RobotModelDto? selectedRobotModel;
private RobotModelListPanel? ListPanelRef;
private async Task TextSearchChanged(string text)
{
searchText = text;
if (ListPanelRef != null)
{
await ListPanelRef.SearchAsync(text);
}
}
private async Task HandleCreate()
{
var parameters = new DialogParameters
{
["ApiService"] = ApiService
};
var dialog = await DialogService.ShowAsync<CreateRobotModelDialog>("Create Robot Model", parameters,
new DialogOptions { MaxWidth = MaxWidth.Medium, FullWidth = true });
var result = await dialog.Result;
if (result != null && !result.Canceled)
{
await ListPanelRef?.LoadDataAsync()!;
Snackbar.Add("Robot model created successfully", Severity.Success);
}
}
private void SelectedRobotModelChanged(RobotModelDto? model)
{
selectedRobotModel = model;
StateHasChanged();
}
}

View File

@@ -0,0 +1,12 @@
@page "/robots/monitor"
@rendermode RobotNet10.Components.RenderMode.InteractiveWebAssemblyNoPrerender
@using RobotNet10.FleetManager.Client.Components.RobotMonitor
<PageTitle>Robot Monitor</PageTitle>
<RobotMonitorComponent />
<MudThemeProvider IsDarkMode />
<MudPopoverProvider />
<MudDialogProvider />
<MudSnackbarProvider />

View File

@@ -0,0 +1,12 @@
@page "/programming"
@rendermode InteractiveWebAssemblyNoPrerender
<PageTitle>Script Editor</PageTitle>
<RobotNet10.ScriptEditor.ScriptEditor />
<MudThemeProvider IsDarkMode />
<MudPopoverProvider />
<MudDialogProvider />
<MudSnackbarProvider />

View File

@@ -0,0 +1,17 @@
@page "/station-manager/{LevelId:guid}"
@rendermode RobotNet10.Components.RenderMode.InteractiveWebAssemblyNoPrerender
<PageTitle>Station Manager</PageTitle>
<RobotNet10.MapEditor.Components.StationManager.StationManagerComponent LayoutLevelId="LevelId" />
<MudThemeProvider IsDarkMode />
<MudPopoverProvider />
<MudDialogProvider />
<MudSnackbarProvider />
@code
{
[Parameter]
public Guid LevelId { get; set; }
}

View File

@@ -0,0 +1,18 @@
@page "/vehicletypes/edit/{Id:guid}"
@rendermode RobotNet10.Components.RenderMode.InteractiveWebAssemblyNoPrerender
<PageTitle>Vehicle Editor</PageTitle>
<RobotNet10.MapEditor.Components.VehicleTypeManager.VehicleTypeEditComponent Id="@Id" />
<MudThemeProvider IsDarkMode />
<MudPopoverProvider />
<MudDialogProvider />
<MudSnackbarProvider />
@code {
[Parameter]
public Guid Id { get; set; }
}

View File

@@ -0,0 +1,12 @@
@page "/vehicle-manager"
@rendermode RobotNet10.Components.RenderMode.InteractiveWebAssemblyNoPrerender
<PageTitle>Vehicle Manager</PageTitle>
<RobotNet10.MapEditor.Components.VehicleTypeManager.VehicleTypeManagerComponent />
<MudThemeProvider IsDarkMode />
<MudPopoverProvider />
<MudDialogProvider />
<MudSnackbarProvider />

View File

@@ -0,0 +1,3 @@
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]