update
This commit is contained in:
parent
aa2146e383
commit
aea55d52f1
|
|
@ -1,63 +1,133 @@
|
||||||
<EditForm Model="@Local" OnValidSubmit="OnSubmit">
|
@implements IDisposable
|
||||||
|
|
||||||
|
<div class="d-flex w-100 h-100 flex-column">
|
||||||
|
<EditForm EditContext="EditContext">
|
||||||
<DataAnnotationsValidator />
|
<DataAnnotationsValidator />
|
||||||
<ValidationSummary />
|
|
||||||
<div class="row g-2 mb-2">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label">Serial Number</label>
|
|
||||||
<InputText class="form-control" @bind-Value="Local.SerialNumber" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label">Manufacturer</label>
|
|
||||||
<InputText class="form-control" @bind-Value="Local.VDA5050Manufacturer" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row g-2 mb-2">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label">Host</label>
|
|
||||||
<InputText class="form-control" @bind-Value="Local.VDA5050HostServer" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<label class="form-label">Port</label>
|
|
||||||
<InputNumber class="form-control" @bind-Value="Local.VDA5050Port" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<label class="form-label">Publish Repeat</label>
|
|
||||||
<InputNumber class="form-control" @bind-Value="Local.VDA5050PublishRepeat" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row g-2 mb-2">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label">Username</label>
|
|
||||||
<InputText class="form-control" @bind-Value="Local.VDA5050UserName" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label">Password</label>
|
|
||||||
<InputText class="form-control" @bind-Value="Local.VDA5050Password" type="password" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<label class="form-label">Version</label>
|
<label class="form-label" for="serialNumber">Serial Number</label>
|
||||||
<InputText class="form-control" @bind-Value="Local.VDA5050Version" />
|
<InputText id="serialNumber" class="form-control" @bind-Value="Model.SerialNumber" />
|
||||||
|
<ValidationMessage For="@(() => Model.SerialNumber)" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-2 mb-2">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label" for="manufacturer">Manufacturer</label>
|
||||||
|
<InputText id="manufacturer" class="form-control" @bind-Value="Model.VDA5050Manufacturer" disabled="true" />
|
||||||
|
<ValidationMessage For="@(() => Model.VDA5050Manufacturer)" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label" for="version">Version</label>
|
||||||
|
<InputText id="version" class="form-control" @bind-Value="Model.VDA5050Version" disabled="true" />
|
||||||
|
<ValidationMessage For="@(() => Model.VDA5050Version)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-2 mb-2">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label" for="host">Host</label>
|
||||||
|
<InputText id="host" class="form-control" @bind-Value="Model.VDA5050HostServer" />
|
||||||
|
<ValidationMessage For="@(() => Model.VDA5050HostServer)" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="form-label" for="port">Port</label>
|
||||||
|
<InputNumber id="port" class="form-control" @bind-Value="Model.VDA5050Port" />
|
||||||
|
<ValidationMessage For="@(() => Model.VDA5050Port)" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="form-label" for="publishRepeat">Publish Repeat</label>
|
||||||
|
<InputNumber id="publishRepeat" class="form-control" @bind-Value="Model.VDA5050PublishRepeat" />
|
||||||
|
<ValidationMessage For="@(() => Model.VDA5050PublishRepeat)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-2 mb-2">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label" for="username">Username</label>
|
||||||
|
<InputText id="username" class="form-control" @bind-Value="Model.VDA5050UserName" />
|
||||||
|
<ValidationMessage For="@(() => Model.VDA5050UserName)" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label" for="password">Password</label>
|
||||||
|
<div class="password-input-wrapper">
|
||||||
|
<InputText id="password" class="form-control password-input" @bind-Value="Model.VDA5050Password" inputmode="text" type="@PasswordInputType" autocomplete="new-password" spellcheck="false" />
|
||||||
|
<button class="password-toggle-btn" type="button" @onclick="TogglePasswordVisibility" aria-label="Toggle password visibility">
|
||||||
|
<i class="@PasswordIconClass" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<ValidationMessage For="@(() => Model.VDA5050Password)" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-check mb-2">
|
<div class="form-check mb-2">
|
||||||
<InputCheckbox class="form-check-input" @bind-Value="Local.VDA5050EnablePassword" />
|
<InputCheckbox id="enablePassword" class="form-check-input" @bind-Value="Model.VDA5050EnablePassword" />
|
||||||
<label class="form-check-label">Enable Password</label>
|
<label class="form-check-label" for="enablePassword">Enable Password</label>
|
||||||
|
<ValidationMessage For="@(() => Model.VDA5050EnablePassword)" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-check mb-2">
|
<div class="form-check mb-2">
|
||||||
<InputCheckbox class="form-check-input" @bind-Value="Local.VDA5050EnableTls" />
|
<InputCheckbox id="enableTls" class="form-check-input" @bind-Value="Model.VDA5050EnableTls" />
|
||||||
<label class="form-check-label">Enable TLS</label>
|
<label class="form-check-label" for="enableTls">Enable TLS</label>
|
||||||
|
<ValidationMessage For="@(() => Model.VDA5050EnableTls)" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-0 mb-2">
|
||||||
|
<label class="form-label" for="caFile">CA File</label>
|
||||||
|
<InputFile class="form-control" id="caFile" OnChange="e => OnFileSelected(e, FileSlot.Ca)" accept=".crt,.pem,.cer,.pfx,.key,.jks" />
|
||||||
|
@if (!string.IsNullOrEmpty(CaFileName))
|
||||||
|
{
|
||||||
|
<div class="small text-muted mt-1 mb-1">@CaFileName (@FormatSize(CaFileSize))</div>
|
||||||
|
}
|
||||||
|
@if (!string.IsNullOrEmpty(CaFileError))
|
||||||
|
{
|
||||||
|
<div class="text-danger small mt-1 mb-1">@CaFileError</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-0 mb-2">
|
||||||
|
<label class="form-label" for="clientCertFile">Client Certificate File</label>
|
||||||
|
<InputFile class="form-control" id="clientCertFile" OnChange="e => OnFileSelected(e, FileSlot.Cert)" accept=".crt,.pem,.cer,.pfx,.key,.jks" />
|
||||||
|
@if (!string.IsNullOrEmpty(CertFileName))
|
||||||
|
{
|
||||||
|
<div class="small text-muted mt-1 mb-1">@CertFileName (@FormatSize(CertFileSize))</div>
|
||||||
|
}
|
||||||
|
@if (!string.IsNullOrEmpty(CertFileError))
|
||||||
|
{
|
||||||
|
<div class="text-danger small mt-1 mb-1">@CertFileError</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-0 mb-2">
|
||||||
|
<label class="form-label" for="clientKeyFile">Client Key File</label>
|
||||||
|
<InputFile class="form-control" id="clientKeyFile" OnChange="e => OnFileSelected(e, FileSlot.Key)" accept=".crt,.pem,.cer,.pfx,.key,.jks" />
|
||||||
|
@if (!string.IsNullOrEmpty(KeyFileName))
|
||||||
|
{
|
||||||
|
<div class="small text-muted mt-1 mb-1">@KeyFileName (@FormatSize(KeyFileSize))</div>
|
||||||
|
}
|
||||||
|
@if (!string.IsNullOrEmpty(KeyFileError))
|
||||||
|
{
|
||||||
|
<div class="text-danger small mt-1 mb-1">@KeyFileError</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<label class="form-label">Description</label>
|
<label class="form-label" for="description">Description</label>
|
||||||
<InputTextArea class="form-control" @bind-Value="Local.Description" />
|
<InputTextArea id="description m-1" class="form-control" @bind-Value="Model.Description" />
|
||||||
|
<ValidationMessage For="@(() => Model.Description)" />
|
||||||
</div>
|
</div>
|
||||||
</EditForm>
|
</EditForm>
|
||||||
|
<div class="flex-grow-1" />
|
||||||
|
<div>
|
||||||
|
@if (Model.CreatedAt != default || Model.UpdatedAt != default)
|
||||||
|
{
|
||||||
|
<div class="d-flex justify-content-end mt-2">
|
||||||
|
<small class="text-muted">Created: @Model.CreatedAt.ToString("dd/MM/yyyy HH:mm:ss")</small>
|
||||||
|
<small class="text-muted ms-3">Updated: @Model.UpdatedAt.ToString("dd/MM/yyyy HH:mm:ss")</small>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
[Parameter]
|
[Parameter]
|
||||||
|
|
@ -66,16 +136,136 @@
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public EventCallback<RobotVDA5050ConfigDto> ModelChanged { get; set; }
|
public EventCallback<RobotVDA5050ConfigDto> ModelChanged { get; set; }
|
||||||
|
|
||||||
private RobotVDA5050ConfigDto Local = new();
|
private EditContext? EditContext;
|
||||||
|
private bool showPassword;
|
||||||
|
private string PasswordInputType => showPassword ? "text" : "password";
|
||||||
|
private string PasswordIconClass => showPassword ? "mdi mdi-eye-off" : "mdi mdi-eye";
|
||||||
|
|
||||||
|
private enum FileSlot { Ca, Cert, Key }
|
||||||
|
|
||||||
|
private string? CaFileName;
|
||||||
|
private long CaFileSize;
|
||||||
|
private string? CaFileError;
|
||||||
|
private byte[]? CaFileData;
|
||||||
|
|
||||||
|
private string? CertFileName;
|
||||||
|
private long CertFileSize;
|
||||||
|
private string? CertFileError;
|
||||||
|
private byte[]? CertFileData;
|
||||||
|
|
||||||
|
private string? KeyFileName;
|
||||||
|
private long KeyFileSize;
|
||||||
|
private string? KeyFileError;
|
||||||
|
private byte[]? KeyFileData;
|
||||||
|
|
||||||
|
private const long MaxFileSize = 10 * 1024 * 1024; // 10 MB
|
||||||
|
|
||||||
|
private async Task OnFileSelected(InputFileChangeEventArgs e, FileSlot slot)
|
||||||
|
{
|
||||||
|
var file = e.File;
|
||||||
|
if (file is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (file.Size > MaxFileSize)
|
||||||
|
{
|
||||||
|
SetFileError(slot, $"File too large (max {FormatSize(MaxFileSize)})");
|
||||||
|
SetFileInfo(slot, null, 0, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var stream = file.OpenReadStream(MaxFileSize);
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
await stream.CopyToAsync(ms);
|
||||||
|
var data = ms.ToArray();
|
||||||
|
|
||||||
|
SetFileData(slot, data, file.Name, file.Size);
|
||||||
|
ClearFileError(slot);
|
||||||
|
|
||||||
|
// Optionally propagate change to parent via ModelChanged if required
|
||||||
|
// _ = ModelChanged.InvokeAsync(Model);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
SetFileError(slot, "Failed to read file");
|
||||||
|
Console.Error.WriteLine(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetFileData(FileSlot slot, byte[] data, string name, long size)
|
||||||
|
{
|
||||||
|
switch (slot)
|
||||||
|
{
|
||||||
|
case FileSlot.Ca:
|
||||||
|
CaFileData = data; CaFileName = name; CaFileSize = size; break;
|
||||||
|
case FileSlot.Cert:
|
||||||
|
CertFileData = data; CertFileName = name; CertFileSize = size; break;
|
||||||
|
case FileSlot.Key:
|
||||||
|
KeyFileData = data; KeyFileName = name; KeyFileSize = size; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetFileError(FileSlot slot, string? error)
|
||||||
|
{
|
||||||
|
switch (slot)
|
||||||
|
{
|
||||||
|
case FileSlot.Ca: CaFileError = error; break;
|
||||||
|
case FileSlot.Cert: CertFileError = error; break;
|
||||||
|
case FileSlot.Key: KeyFileError = error; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearFileError(FileSlot slot) => SetFileError(slot, null);
|
||||||
|
|
||||||
|
private void SetFileInfo(FileSlot slot, string? name, long size, byte[]? data)
|
||||||
|
{
|
||||||
|
switch (slot)
|
||||||
|
{
|
||||||
|
case FileSlot.Ca: CaFileName = name; CaFileSize = size; CaFileData = data; break;
|
||||||
|
case FileSlot.Cert: CertFileName = name; CertFileSize = size; CertFileData = data; break;
|
||||||
|
case FileSlot.Key: KeyFileName = name; KeyFileSize = size; KeyFileData = data; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FormatSize(long size)
|
||||||
|
{
|
||||||
|
if (size <= 0) return "0 B";
|
||||||
|
if (size < 1024) return $"{size} B";
|
||||||
|
double kb = size / 1024.0;
|
||||||
|
if (kb < 1024) return $"{kb:F1} KB";
|
||||||
|
double mb = kb / 1024.0;
|
||||||
|
return $"{mb:F2} MB";
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
Local = Model is not null ? Model with { } : new RobotVDA5050ConfigDto();
|
if (EditContext is null || !EditContext.Model!.Equals(Model))
|
||||||
|
{
|
||||||
|
if (EditContext is not null) EditContext.OnFieldChanged -= EditContext_OnFieldChanged;
|
||||||
|
EditContext = new EditContext(Model);
|
||||||
|
EditContext.OnFieldChanged += EditContext_OnFieldChanged;
|
||||||
|
}
|
||||||
|
CertFileName = string.Empty;
|
||||||
|
CertFileError = string.Empty;
|
||||||
|
KeyFileName = string.Empty;
|
||||||
|
KeyFileError = string.Empty;
|
||||||
|
CaFileName = string.Empty;
|
||||||
|
CaFileError = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OnSubmit()
|
private void TogglePasswordVisibility()
|
||||||
{
|
{
|
||||||
Model = Local;
|
showPassword = !showPassword;
|
||||||
await ModelChanged.InvokeAsync(Model);
|
}
|
||||||
|
|
||||||
|
private void EditContext_OnFieldChanged(object? sender, FieldChangedEventArgs e)
|
||||||
|
{
|
||||||
|
_ = ModelChanged.InvokeAsync(Model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (EditContext is not null) EditContext.OnFieldChanged -= EditContext_OnFieldChanged;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
/* wrapper positions the toggle inside the input */
|
||||||
|
.password-input-wrapper {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add right padding so text doesn't overlap the icon */
|
||||||
|
.password-input {
|
||||||
|
padding-right: 2.25rem; /* adjust as needed for icon size */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* icon button sits absolutely inside the input at the right */
|
||||||
|
.password-toggle-btn {
|
||||||
|
position: absolute;
|
||||||
|
right: 0.5rem;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
padding: 0;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
color: inherit;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* keep the native focus behavior but provide visible ring for keyboard users */
|
||||||
|
.password-toggle-btn:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-toggle-btn:focus-visible {
|
||||||
|
box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.15);
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tune icon size */
|
||||||
|
.password-toggle-btn .mdi {
|
||||||
|
font-size: 1.15rem;
|
||||||
|
pointer-events: none; /* let clicks hit the button, not the icon */
|
||||||
|
}
|
||||||
|
|
@ -2,18 +2,20 @@
|
||||||
@rendermode InteractiveWebAssemblyNoPrerender
|
@rendermode InteractiveWebAssemblyNoPrerender
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
|
|
||||||
@using RobotApp.Common.Shares.Dtos
|
|
||||||
@using RobotApp.Common.Shares.Enums
|
|
||||||
@inject HttpClient Http
|
@inject HttpClient Http
|
||||||
|
@inject ISnackbar Snackbar
|
||||||
|
|
||||||
|
@using System.Net.Http.Json
|
||||||
|
@using RobotApp.Common.Shares.Dtos
|
||||||
|
|
||||||
<PageTitle>Robot Configuration</PageTitle>
|
<PageTitle>Robot Configuration</PageTitle>
|
||||||
|
|
||||||
<div class="d-flex w-100 h-100 p-2 overflow-hidden flex-column">
|
<div class="d-flex w-100 h-100 p-2 overflow-hidden flex-column position-relative">
|
||||||
<div class="rcm-toolbar">
|
<div class="rcm-toolbar">
|
||||||
<div class="rcm-toolbar-left">
|
<div class="rcm-toolbar-left">
|
||||||
<label class="rcm-label" for="configType">Config Type</label>
|
<label class="rcm-label" for="configType">Config Type</label>
|
||||||
<div class="rcm-select-wrapper">
|
<div class="rcm-select-wrapper">
|
||||||
<select id="configType" class="form-select rcm-select" @bind="SelectedType">
|
<select id="configType" class="form-select rcm-select" value="@SelectedType" @onchange="OnTypeChanged">
|
||||||
@foreach (var type in Enum.GetValues<RobotConfigType>())
|
@foreach (var type in Enum.GetValues<RobotConfigType>())
|
||||||
{
|
{
|
||||||
<option value="@type">@type</option>
|
<option value="@type">@type</option>
|
||||||
|
|
@ -29,15 +31,15 @@
|
||||||
|
|
||||||
<div class="rcm-toolbar-right">
|
<div class="rcm-toolbar-right">
|
||||||
<div class="rcm-action-group">
|
<div class="rcm-action-group">
|
||||||
<button type="button" class="btn rcm-icon-btn" data-tooltip="Add config" aria-label="Add">
|
<button type="button" class="btn rcm-icon-btn" data-tooltip="Add config" aria-label="Add" @onclick="OpenAddConfig">
|
||||||
<i class="mdi mdi-plus" aria-hidden="true"></i>
|
<i class="mdi mdi-plus" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button type="button" class="btn rcm-icon-btn" data-tooltip="Update config" aria-label="Update">
|
<button type="button" class="btn rcm-icon-btn" data-tooltip="Update config" aria-label="Update" @onclick="SaveConfig">
|
||||||
<i class="mdi mdi-content-save" aria-hidden="true"></i>
|
<i class="mdi mdi-content-save" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button type="button" class="btn rcm-icon-btn rcm-danger" data-tooltip="Delete config" aria-label="Delete">
|
<button type="button" class="btn rcm-icon-btn rcm-danger" data-tooltip="Delete config" aria-label="Delete" @onclick="DeleteConfig">
|
||||||
<i class="mdi mdi-delete" aria-hidden="true"></i>
|
<i class="mdi mdi-delete" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -49,19 +51,19 @@
|
||||||
@switch (SelectedType)
|
@switch (SelectedType)
|
||||||
{
|
{
|
||||||
case RobotConfigType.VDA5050:
|
case RobotConfigType.VDA5050:
|
||||||
@RenderList(VdaConfigs, () => SelectVda)
|
@RenderList(VdaConfigs, SelectVda, v => v.ConfigName, v => v.IsActive)
|
||||||
break;
|
break;
|
||||||
case RobotConfigType.Safety:
|
case RobotConfigType.Safety:
|
||||||
@RenderList(SafetyConfigs, () => SelectSafety)
|
@RenderList(SafetyConfigs, SelectSafety, s => s.ConfigName, s => s.IsActive)
|
||||||
break;
|
break;
|
||||||
case RobotConfigType.Simulation:
|
case RobotConfigType.Simulation:
|
||||||
@RenderList(SimulationConfigs, () => SelectSimulation)
|
@RenderList(SimulationConfigs, SelectSimulation, s => s.ConfigName, s => s.IsActive)
|
||||||
break;
|
break;
|
||||||
case RobotConfigType.PLC:
|
case RobotConfigType.PLC:
|
||||||
@RenderList(PlcConfigs, () => SelectPlc)
|
@RenderList(PlcConfigs, SelectPlc, p => p.ConfigName, p => p.IsActive)
|
||||||
break;
|
break;
|
||||||
case RobotConfigType.Core:
|
case RobotConfigType.Core:
|
||||||
@RenderList(CoreConfigs, () => SelectCore)
|
@RenderList(CoreConfigs, SelectCore, c => c.ConfigName, c => c.IsActive)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
<div class="p-2">No configs.</div>
|
<div class="p-2">No configs.</div>
|
||||||
|
|
@ -100,14 +102,93 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if (IsLoading)
|
||||||
|
{
|
||||||
|
<div class="rcm-overlay" role="status" aria-live="polite" aria-busy="true">
|
||||||
|
<div class="rcm-overlay-content" aria-hidden="false">
|
||||||
|
<div class="spinner-border text-light" role="status" aria-hidden="true"></div>
|
||||||
|
<div class="rcm-overlay-message ms-2">Loading…</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (IsAddingNew)
|
||||||
|
{
|
||||||
|
<div class="rcm-modal-overlay" role="dialog" aria-modal="true">
|
||||||
|
<div class="rcm-modal">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<strong>Create @SelectedType Config</strong>
|
||||||
|
<button class="btn btn-sm btn-link text-muted" @onclick="CloseAddDialog" aria-label="Close">✕</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<EditForm Model="addForm" OnValidSubmit="SaveNewConfigAsync">
|
||||||
|
<DataAnnotationsValidator />
|
||||||
|
<ValidationSummary />
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="form-label">Config name</label>
|
||||||
|
<InputText class="form-control" @bind-Value="addForm.ConfigName" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="form-label">Description</label>
|
||||||
|
<InputText class="form-control" @bind-Value="addForm.Description" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="form-label">Copy parameters from existing (@SelectedType)</label>
|
||||||
|
<select class="form-select" @bind="SelectedTemplateIdString">
|
||||||
|
@foreach (var t in GetTemplatesForSelectedType())
|
||||||
|
{
|
||||||
|
<option value="@t.Id">@t.Name</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
<div class="form-text">If you choose an existing config, its parameter fields will be copied into the new config; you can still change name/description.</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex justify-content-end gap-2 mt-3">
|
||||||
|
<button type="button" class="btn btn-outline-secondary" @onclick="CloseAddDialog">Cancel</button>
|
||||||
|
<button type="submit" class="btn btn-primary">Create</button>
|
||||||
|
</div>
|
||||||
|
</EditForm>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (ShowDeleteConfirm)
|
||||||
|
{
|
||||||
|
<div class="rcm-modal-overlay" role="dialog" aria-modal="true">
|
||||||
|
<div class="rcm-modal">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<strong>Confirm Delete</strong>
|
||||||
|
<button class="btn btn-sm btn-link text-muted" @onclick="CancelDelete" aria-label="Close">✕</button>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>Are you sure you want to delete configuration "<strong>@DeletePendingName</strong>"?</p>
|
||||||
|
<div class="d-flex justify-content-end gap-2 mt-3">
|
||||||
|
<button class="btn btn-outline-secondary" @onclick="CancelDelete">Cancel</button>
|
||||||
|
<button class="btn btn-danger" @onclick="ConfirmDeleteAsync">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<RobotVDA5050ConfigDto> VdaConfigs { get; } = [];
|
private List<RobotVDA5050ConfigDto> VdaConfigs { get; set; } = new();
|
||||||
private List<RobotSafetyConfigDto> SafetyConfigs { get; } = [];
|
private List<RobotSafetyConfigDto> SafetyConfigs { get; set; } = new();
|
||||||
private List<RobotSimulationConfigDto> SimulationConfigs { get; } = [];
|
private List<RobotSimulationConfigDto> SimulationConfigs { get; set; } = new();
|
||||||
private List<RobotPlcConfigDto> PlcConfigs { get; } = [];
|
private List<RobotPlcConfigDto> PlcConfigs { get; set; } = new();
|
||||||
private List<RobotConfigDto> CoreConfigs { get; } = [];
|
private List<RobotConfigDto> CoreConfigs { get; set; } = new();
|
||||||
|
|
||||||
private RobotVDA5050ConfigDto? SelectedVda { get; set; }
|
private RobotVDA5050ConfigDto? SelectedVda { get; set; }
|
||||||
private RobotSafetyConfigDto? SelectedSafety { get; set; }
|
private RobotSafetyConfigDto? SelectedSafety { get; set; }
|
||||||
|
|
@ -115,13 +196,96 @@
|
||||||
private RobotPlcConfigDto? SelectedPlc { get; set; }
|
private RobotPlcConfigDto? SelectedPlc { get; set; }
|
||||||
private RobotConfigDto? SelectedCore { get; set; }
|
private RobotConfigDto? SelectedCore { get; set; }
|
||||||
|
|
||||||
private RobotConfigType SelectedType { get; set; } = RobotConfigType.VDA5050;
|
private CreateRobotVDA5050ConfigDto CreateVda = new();
|
||||||
|
private CreateRobotConfigDto CreateSafety = new();
|
||||||
|
private CreateRobotSafetyConfigDto CreateSimulation = new();
|
||||||
|
private CreateRobotSimulationConfigDto CreatePlc = new();
|
||||||
|
private CreateRobotPlcConfigDto CreateCore = new();
|
||||||
|
|
||||||
private int SelectedIndex { get; set; } = -1;
|
private RobotConfigType SelectedType = RobotConfigType.VDA5050;
|
||||||
|
|
||||||
|
private int SelectedIndex = -1;
|
||||||
private bool HasSelection => SelectedIndex >= 0;
|
private bool HasSelection => SelectedIndex >= 0;
|
||||||
|
private bool IsLoading = false;
|
||||||
|
private bool IsAddingNew = false;
|
||||||
|
|
||||||
RenderFragment RenderList<T>(List<T> list, Func<Action<int>> selectFactory) where T : class
|
private bool ShowDeleteConfirm = false;
|
||||||
|
private Guid? DeletePendingId;
|
||||||
|
private string DeletePendingName = string.Empty;
|
||||||
|
|
||||||
|
private class AddFormModel
|
||||||
|
{
|
||||||
|
public string ConfigName { get; set; } = string.Empty;
|
||||||
|
public string Description { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
private AddFormModel addForm = new();
|
||||||
|
|
||||||
|
private string SelectedTemplateIdString = string.Empty;
|
||||||
|
|
||||||
|
private IEnumerable<(Guid Id, string Name, bool Active)> GetTemplatesForSelectedType()
|
||||||
|
{
|
||||||
|
return SelectedType switch
|
||||||
|
{
|
||||||
|
RobotConfigType.VDA5050 => VdaConfigs.Select(x => (x.Id, x.ConfigName ?? string.Empty, x.IsActive)),
|
||||||
|
RobotConfigType.Safety => SafetyConfigs.Select(x => (x.Id, x.ConfigName ?? string.Empty, x.IsActive)),
|
||||||
|
RobotConfigType.Simulation => SimulationConfigs.Select(x => (x.Id, x.ConfigName ?? string.Empty, x.IsActive)),
|
||||||
|
RobotConfigType.PLC => PlcConfigs.Select(x => (x.Id, x.ConfigName ?? string.Empty, x.IsActive)),
|
||||||
|
RobotConfigType.Core => CoreConfigs.Select(x => (x.Id, x.ConfigName ?? string.Empty, x.IsActive)),
|
||||||
|
_ => [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
await base.OnAfterRenderAsync(firstRender);
|
||||||
|
if (!firstRender) return;
|
||||||
|
await LoadForTypeAsync(SelectedType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnTypeChanged(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
if (e?.Value is null) return;
|
||||||
|
if (!Enum.TryParse<RobotConfigType>(e.Value.ToString(), out var newType)) return;
|
||||||
|
if (newType == SelectedType) return;
|
||||||
|
|
||||||
|
SelectedType = newType;
|
||||||
|
await LoadForTypeAsync(newType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadForTypeAsync(RobotConfigType type)
|
||||||
|
{
|
||||||
|
IsLoading = true;
|
||||||
|
StateHasChanged();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case RobotConfigType.VDA5050:
|
||||||
|
await LoadVDA5050Configs();
|
||||||
|
break;
|
||||||
|
case RobotConfigType.Safety:
|
||||||
|
await LoadRobotSafetyConfigs();
|
||||||
|
break;
|
||||||
|
case RobotConfigType.Simulation:
|
||||||
|
await LoadRobotSimulationConfigs();
|
||||||
|
break;
|
||||||
|
case RobotConfigType.PLC:
|
||||||
|
await LoadRobotPlcConfigs();
|
||||||
|
break;
|
||||||
|
case RobotConfigType.Core:
|
||||||
|
await LoadRobotConfigs();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsLoading = false;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderFragment RenderList<T>(List<T> list, Action<int> onSelect, Func<T, string> nameSelector, Func<T, bool>? isActiveSelector = null) where T : class
|
||||||
{
|
{
|
||||||
return builder =>
|
return builder =>
|
||||||
{
|
{
|
||||||
|
|
@ -141,24 +305,40 @@
|
||||||
{
|
{
|
||||||
var item = list[i];
|
var item = list[i];
|
||||||
var idx = i;
|
var idx = i;
|
||||||
builder.OpenElement(10 + i * 5, "li");
|
builder.OpenElement(10 + i * 6, "li");
|
||||||
builder.AddAttribute(11 + i * 5, "class", $"list-group-item {(SelectedIndex==idx ? "active" : "")}");
|
builder.AddAttribute(11 + i * 6, "class", $"list-group-item {(SelectedIndex == idx ? "active" : "")}");
|
||||||
builder.AddAttribute(12 + i * 5, "style", "cursor:pointer;padding:0.75rem 1rem;");
|
builder.AddAttribute(12 + i * 6, "style", "cursor:pointer;padding:0.75rem 1rem;");
|
||||||
builder.AddAttribute(13 + i * 5, "onclick", EventCallback.Factory.Create(this, () => selectFactory()(idx)));
|
builder.AddAttribute(13 + i * 6, "onclick", EventCallback.Factory.Create(this, () => onSelect(idx)));
|
||||||
|
|
||||||
// Only show ConfigName
|
string name;
|
||||||
var nameProp = item.GetType().GetProperty("ConfigName");
|
try
|
||||||
var name = nameProp?.GetValue(item)?.ToString() ?? "Unnamed";
|
{
|
||||||
builder.AddContent(14 + i * 5, name);
|
name = nameSelector(item) ?? "Unnamed";
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
name = "Unnamed";
|
||||||
|
}
|
||||||
|
builder.AddContent(14 + i * 6, name);
|
||||||
|
|
||||||
|
bool isActive = false;
|
||||||
|
if (isActiveSelector is not null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
isActive = isActiveSelector(item);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
isActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Show active badge at end if IsActive == true
|
|
||||||
var isActiveProp = item.GetType().GetProperty("IsActive");
|
|
||||||
var isActive = isActiveProp?.GetValue(item) is bool b && b;
|
|
||||||
if (isActive)
|
if (isActive)
|
||||||
{
|
{
|
||||||
builder.OpenElement(15 + i * 5, "span");
|
builder.OpenElement(15 + i * 6, "span");
|
||||||
builder.AddAttribute(16 + i * 5, "class", "badge bg-success ms-2 float-end");
|
builder.AddAttribute(16 + i * 6, "class", "badge bg-success ms-2 float-end");
|
||||||
builder.AddContent(17 + i * 5, "Active");
|
builder.AddContent(17 + i * 6, "Active");
|
||||||
builder.CloseElement();
|
builder.CloseElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -204,5 +384,47 @@
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private void OpenAddConfig()
|
||||||
|
{
|
||||||
|
addForm = new AddFormModel();
|
||||||
|
var model = GetTemplatesForSelectedType();
|
||||||
|
var modelActive = model.Where(x => x.Active).ToList();
|
||||||
|
SelectedTemplateIdString = modelActive.Count > 0 ? modelActive.First().Id.ToString() : model.Any() ? model.First().Id.ToString() : string.Empty;
|
||||||
|
IsAddingNew = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CloseAddDialog()
|
||||||
|
{
|
||||||
|
IsAddingNew = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeleteConfig()
|
||||||
|
{
|
||||||
|
var tuple = SelectedType switch
|
||||||
|
{
|
||||||
|
RobotConfigType.VDA5050 => (Id: SelectedVda?.Id, Name: SelectedVda?.ConfigName),
|
||||||
|
RobotConfigType.Safety => (Id: SelectedSafety?.Id, Name: SelectedSafety?.ConfigName),
|
||||||
|
RobotConfigType.Simulation => (Id: SelectedSimulation?.Id, Name: SelectedSimulation?.ConfigName),
|
||||||
|
RobotConfigType.PLC => (Id: SelectedPlc?.Id, Name: SelectedPlc?.ConfigName),
|
||||||
|
RobotConfigType.Core => (Id: SelectedCore?.Id, Name: SelectedCore?.ConfigName),
|
||||||
|
_ => (Id: (Guid?)null, Name: (string?)null)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tuple.Id is null || tuple.Id == Guid.Empty)
|
||||||
|
{
|
||||||
|
Snackbar.Add("No config selected to delete.", Severity.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeletePendingId = tuple.Id;
|
||||||
|
DeletePendingName = tuple.Name ?? string.Empty;
|
||||||
|
ShowDeleteConfirm = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CancelDelete()
|
||||||
|
{
|
||||||
|
ShowDeleteConfirm = false;
|
||||||
|
DeletePendingId = null;
|
||||||
|
DeletePendingName = string.Empty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
521
RobotApp.Client/Pages/RobotConfigManager.razor.cs
Normal file
521
RobotApp.Client/Pages/RobotConfigManager.razor.cs
Normal file
|
|
@ -0,0 +1,521 @@
|
||||||
|
using MudBlazor;
|
||||||
|
using RobotApp.Common.Shares;
|
||||||
|
using RobotApp.Common.Shares.Dtos;
|
||||||
|
using RobotApp.Common.Shares.Enums;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
using System.Xml.Schema;
|
||||||
|
|
||||||
|
namespace RobotApp.Client.Pages;
|
||||||
|
|
||||||
|
public partial class RobotConfigManager
|
||||||
|
{
|
||||||
|
private async Task LoadVDA5050Configs()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var res = await Http.GetFromJsonAsync<MessageResult<RobotVDA5050ConfigDto[]>>("api/RobotConfigs/vda5050");
|
||||||
|
if (res is null) Snackbar.Add("Failed to load VDA5050 configs", Severity.Warning);
|
||||||
|
else if (!res.IsSuccess) Snackbar.Add(res.Message ?? "Failed to load VDA5050 configs", Severity.Warning);
|
||||||
|
else if (res.Data is not null)
|
||||||
|
{
|
||||||
|
VdaConfigs.Clear();
|
||||||
|
VdaConfigs.AddRange(res.Data);
|
||||||
|
|
||||||
|
var activeIdx = VdaConfigs.FindIndex(x => x.IsActive);
|
||||||
|
if (activeIdx >= 0)
|
||||||
|
{
|
||||||
|
SelectedIndex = activeIdx;
|
||||||
|
SelectedVda = VdaConfigs[activeIdx] with { };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SelectedIndex = -1;
|
||||||
|
SelectedVda = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Snackbar.Add("No VDA5050 configs found", Severity.Info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Snackbar.Add($"Error loading PLC configs: {ex.Message}", Severity.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadRobotConfigs()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var res = await Http.GetFromJsonAsync<MessageResult<RobotConfigDto[]>>("api/RobotConfigs/robot");
|
||||||
|
if (res is null) Snackbar.Add("Failed to load VDA5050 configs", Severity.Warning);
|
||||||
|
else if (!res.IsSuccess) Snackbar.Add(res.Message ?? "Failed to load VDA5050 configs", Severity.Warning);
|
||||||
|
else if (res.Data is not null)
|
||||||
|
{
|
||||||
|
CoreConfigs.Clear();
|
||||||
|
CoreConfigs.AddRange(res.Data);
|
||||||
|
|
||||||
|
var activeIdx = CoreConfigs.FindIndex(x => x.IsActive);
|
||||||
|
if (activeIdx >= 0)
|
||||||
|
{
|
||||||
|
SelectedIndex = activeIdx;
|
||||||
|
SelectedCore = CoreConfigs[activeIdx] with { };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SelectedIndex = -1;
|
||||||
|
SelectedCore = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Snackbar.Add($"Error loading PLC configs: {ex.Message}", Severity.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadRobotSafetyConfigs()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var res = await Http.GetFromJsonAsync<MessageResult<RobotSafetyConfigDto[]>>("api/RobotConfigs/safety");
|
||||||
|
if (res is null) Snackbar.Add("Failed to load VDA5050 configs", Severity.Warning);
|
||||||
|
else if (!res.IsSuccess) Snackbar.Add(res.Message ?? "Failed to load VDA5050 configs", Severity.Warning);
|
||||||
|
else if (res.Data is not null)
|
||||||
|
{
|
||||||
|
SafetyConfigs.Clear();
|
||||||
|
SafetyConfigs.AddRange(res.Data);
|
||||||
|
|
||||||
|
var activeIdx = SafetyConfigs.FindIndex(x => x.IsActive);
|
||||||
|
if (activeIdx >= 0)
|
||||||
|
{
|
||||||
|
SelectedIndex = activeIdx;
|
||||||
|
SelectedSafety = SafetyConfigs[activeIdx] with { };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SelectedIndex = -1;
|
||||||
|
SelectedSafety = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Snackbar.Add($"Error loading PLC configs: {ex.Message}", Severity.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadRobotSimulationConfigs()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var res = await Http.GetFromJsonAsync<MessageResult<RobotSimulationConfigDto[]>>("api/RobotConfigs/simulation");
|
||||||
|
if (res is null) Snackbar.Add("Failed to load VDA5050 configs", Severity.Warning);
|
||||||
|
else if (!res.IsSuccess) Snackbar.Add(res.Message ?? "Failed to load VDA5050 configs", Severity.Warning);
|
||||||
|
else if (res.Data is not null)
|
||||||
|
{
|
||||||
|
SimulationConfigs.Clear();
|
||||||
|
SimulationConfigs.AddRange(res.Data);
|
||||||
|
|
||||||
|
var activeIdx = SimulationConfigs.FindIndex(x => x.IsActive);
|
||||||
|
if (activeIdx >= 0)
|
||||||
|
{
|
||||||
|
SelectedIndex = activeIdx;
|
||||||
|
SelectedSimulation = SimulationConfigs[activeIdx] with { };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SelectedIndex = -1;
|
||||||
|
SelectedSimulation = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Snackbar.Add($"Error loading PLC configs: {ex.Message}", Severity.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadRobotPlcConfigs()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var res = await Http.GetFromJsonAsync<MessageResult<RobotPlcConfigDto[]>>("api/RobotConfigs/plc");
|
||||||
|
if (res is null) Snackbar.Add("Failed to load VDA5050 configs", Severity.Warning);
|
||||||
|
else if (!res.IsSuccess) Snackbar.Add(res.Message ?? "Failed to load VDA5050 configs", Severity.Warning);
|
||||||
|
else if (res.Data is not null)
|
||||||
|
{
|
||||||
|
PlcConfigs.Clear();
|
||||||
|
PlcConfigs.AddRange(res.Data);
|
||||||
|
var activeIdx = PlcConfigs.FindIndex(x => x.IsActive);
|
||||||
|
if (activeIdx >= 0)
|
||||||
|
{
|
||||||
|
SelectedIndex = activeIdx;
|
||||||
|
SelectedPlc = PlcConfigs[activeIdx] with { };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SelectedIndex = -1;
|
||||||
|
SelectedPlc = null;
|
||||||
|
}
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Snackbar.Add($"Error loading PLC configs: {ex.Message}", Severity.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveNewConfigAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HttpResponseMessage? res = null;
|
||||||
|
_ = Guid.TryParse(SelectedTemplateIdString, out Guid templateId);
|
||||||
|
|
||||||
|
switch (SelectedType)
|
||||||
|
{
|
||||||
|
case RobotConfigType.VDA5050:
|
||||||
|
{
|
||||||
|
var template = VdaConfigs.FirstOrDefault(x => x.Id == templateId);
|
||||||
|
if (template is null) return;
|
||||||
|
var payload = new
|
||||||
|
{
|
||||||
|
addForm.ConfigName,
|
||||||
|
addForm.Description,
|
||||||
|
template.SerialNumber,
|
||||||
|
template.VDA5050HostServer,
|
||||||
|
template.VDA5050Port,
|
||||||
|
template.VDA5050UserName,
|
||||||
|
template.VDA5050Password,
|
||||||
|
template.VDA5050Manufacturer,
|
||||||
|
template.VDA5050Version,
|
||||||
|
template.VDA5050PublishRepeat,
|
||||||
|
template.VDA5050EnablePassword,
|
||||||
|
template.VDA5050EnableTls
|
||||||
|
};
|
||||||
|
|
||||||
|
res = await Http.PostAsJsonAsync("api/RobotConfigs/vda5050", payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RobotConfigType.PLC:
|
||||||
|
{
|
||||||
|
var template = PlcConfigs.FirstOrDefault(x => x.Id == templateId);
|
||||||
|
if (template is null) return;
|
||||||
|
var payload = new
|
||||||
|
{
|
||||||
|
addForm.ConfigName,
|
||||||
|
addForm.Description,
|
||||||
|
template.PLCAddress,
|
||||||
|
template.PLCPort,
|
||||||
|
template.PLCUnitId
|
||||||
|
};
|
||||||
|
|
||||||
|
res = await Http.PostAsJsonAsync("api/RobotConfigs/plc", payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RobotConfigType.Safety:
|
||||||
|
{
|
||||||
|
var template = SafetyConfigs.FirstOrDefault(x => x.Id == templateId);
|
||||||
|
if (template is null) return;
|
||||||
|
var payload = new
|
||||||
|
{
|
||||||
|
addForm.ConfigName,
|
||||||
|
addForm.Description,
|
||||||
|
template.SafetySpeedVerySlow,
|
||||||
|
template.SafetySpeedSlow,
|
||||||
|
template.SafetySpeedNormal,
|
||||||
|
template.SafetySpeedMedium,
|
||||||
|
template.SafetySpeedOptimal,
|
||||||
|
template.SafetySpeedFast,
|
||||||
|
template.SafetySpeedVeryFast
|
||||||
|
};
|
||||||
|
|
||||||
|
res = await Http.PostAsJsonAsync("api/RobotConfigs/safety", payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RobotConfigType.Simulation:
|
||||||
|
{
|
||||||
|
var template = SimulationConfigs.FirstOrDefault(x => x.Id == templateId);
|
||||||
|
if (template is null) return;
|
||||||
|
var payload = new
|
||||||
|
{
|
||||||
|
addForm.ConfigName,
|
||||||
|
addForm.Description,
|
||||||
|
template.EnableSimulation,
|
||||||
|
template.SimulationMaxVelocity,
|
||||||
|
template.SimulationMaxAngularVelocity,
|
||||||
|
template.SimulationAcceleration,
|
||||||
|
template.SimulationDeceleration
|
||||||
|
};
|
||||||
|
|
||||||
|
res = await Http.PostAsJsonAsync("api/RobotConfigs/simulation", payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RobotConfigType.Core:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
var template = CoreConfigs.FirstOrDefault(x => x.Id == templateId);
|
||||||
|
if (template is null) return;
|
||||||
|
var payload = new
|
||||||
|
{
|
||||||
|
addForm.ConfigName,
|
||||||
|
addForm.Description,
|
||||||
|
template.NavigationType,
|
||||||
|
template.RadiusWheel,
|
||||||
|
template.Width,
|
||||||
|
template.Length,
|
||||||
|
template.Height
|
||||||
|
};
|
||||||
|
|
||||||
|
res = await Http.PostAsJsonAsync("api/RobotConfigs/robot", payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res is not null && res.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
Snackbar.Add("Config created", Severity.Success);
|
||||||
|
IsAddingNew = false;
|
||||||
|
await LoadForTypeAsync(SelectedType);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var message = res is null ? "No response" : await res.Content.ReadAsStringAsync();
|
||||||
|
Snackbar.Add($"Create failed: {message}", Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Snackbar.Add($"Error creating config: {ex.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveConfig()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Guid? id = SelectedType switch
|
||||||
|
{
|
||||||
|
RobotConfigType.VDA5050 => SelectedVda?.Id,
|
||||||
|
RobotConfigType.Safety => SelectedSafety?.Id,
|
||||||
|
RobotConfigType.Simulation => SelectedSimulation?.Id,
|
||||||
|
RobotConfigType.PLC => SelectedPlc?.Id,
|
||||||
|
RobotConfigType.Core => SelectedCore?.Id,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
|
||||||
|
if (id == null || id == Guid.Empty)
|
||||||
|
{
|
||||||
|
Snackbar.Add("No config selected to save.", Severity.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageResult? result = null;
|
||||||
|
|
||||||
|
switch (SelectedType)
|
||||||
|
{
|
||||||
|
case RobotConfigType.VDA5050:
|
||||||
|
{
|
||||||
|
if (SelectedVda is null) { Snackbar.Add("No VDA5050 config selected.", Severity.Warning); return; }
|
||||||
|
var updateDto = new
|
||||||
|
{
|
||||||
|
SelectedVda.SerialNumber,
|
||||||
|
SelectedVda.VDA5050HostServer,
|
||||||
|
SelectedVda.VDA5050Port,
|
||||||
|
SelectedVda.VDA5050UserName,
|
||||||
|
SelectedVda.VDA5050Password,
|
||||||
|
SelectedVda.VDA5050Manufacturer,
|
||||||
|
SelectedVda.VDA5050Version,
|
||||||
|
SelectedVda.VDA5050PublishRepeat,
|
||||||
|
SelectedVda.VDA5050EnablePassword,
|
||||||
|
SelectedVda.VDA5050EnableTls,
|
||||||
|
SelectedVda.Description
|
||||||
|
};
|
||||||
|
result = await (await Http.PutAsJsonAsync($"api/RobotConfigs/vda5050/{id}", updateDto)).Content.ReadFromJsonAsync<MessageResult>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RobotConfigType.PLC:
|
||||||
|
{
|
||||||
|
if (SelectedPlc is null) { Snackbar.Add("No PLC config selected.", Severity.Warning); return; }
|
||||||
|
var updateDto = new
|
||||||
|
{
|
||||||
|
SelectedPlc.Description,
|
||||||
|
SelectedPlc.PLCAddress,
|
||||||
|
SelectedPlc.PLCPort,
|
||||||
|
SelectedPlc.PLCUnitId
|
||||||
|
};
|
||||||
|
|
||||||
|
result = await (await Http.PutAsJsonAsync($"api/RobotConfigs/plc/{id}", updateDto)).Content.ReadFromJsonAsync<MessageResult>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RobotConfigType.Safety:
|
||||||
|
{
|
||||||
|
if (SelectedSafety is null) { Snackbar.Add("No Safety config selected.", Severity.Warning); return; }
|
||||||
|
var updateDto = new
|
||||||
|
{
|
||||||
|
SelectedSafety.SafetySpeedVerySlow,
|
||||||
|
SelectedSafety.SafetySpeedSlow,
|
||||||
|
SelectedSafety.SafetySpeedNormal,
|
||||||
|
SelectedSafety.SafetySpeedMedium,
|
||||||
|
SelectedSafety.SafetySpeedOptimal,
|
||||||
|
SelectedSafety.SafetySpeedFast,
|
||||||
|
SelectedSafety.SafetySpeedVeryFast,
|
||||||
|
SelectedSafety.Description
|
||||||
|
};
|
||||||
|
|
||||||
|
result = await (await Http.PutAsJsonAsync($"api/RobotConfigs/safety/{id}", updateDto)).Content.ReadFromJsonAsync<MessageResult>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RobotConfigType.Simulation:
|
||||||
|
{
|
||||||
|
if (SelectedSimulation is null) { Snackbar.Add("No Simulation config selected.", Severity.Warning); return; }
|
||||||
|
var updateDto = new
|
||||||
|
{
|
||||||
|
SelectedSimulation.EnableSimulation,
|
||||||
|
SelectedSimulation.SimulationMaxVelocity,
|
||||||
|
SelectedSimulation.SimulationMaxAngularVelocity,
|
||||||
|
SelectedSimulation.SimulationAcceleration,
|
||||||
|
SelectedSimulation.SimulationDeceleration,
|
||||||
|
SelectedSimulation.Description
|
||||||
|
};
|
||||||
|
|
||||||
|
result = await (await Http.PutAsJsonAsync($"api/RobotConfigs/simulation/{id}", updateDto)).Content.ReadFromJsonAsync<MessageResult>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RobotConfigType.Core:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if (SelectedCore is null) { Snackbar.Add("No Core config selected.", Severity.Warning); return; }
|
||||||
|
var updateDto = new
|
||||||
|
{
|
||||||
|
SelectedCore.NavigationType,
|
||||||
|
SelectedCore.RadiusWheel,
|
||||||
|
SelectedCore.Width,
|
||||||
|
SelectedCore.Length,
|
||||||
|
SelectedCore.Height,
|
||||||
|
SelectedCore.Description
|
||||||
|
};
|
||||||
|
|
||||||
|
result = await (await Http.PutAsJsonAsync($"api/RobotConfigs/robot/{id}", updateDto)).Content.ReadFromJsonAsync<MessageResult>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result is null) Snackbar.Add("Failed to update config", Severity.Warning);
|
||||||
|
else if (!result.IsSuccess) Snackbar.Add(result.Message ?? "Failed to update config", Severity.Warning);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Snackbar.Add("Config saved", Severity.Success);
|
||||||
|
|
||||||
|
await LoadForTypeAsync(SelectedType);
|
||||||
|
|
||||||
|
switch (SelectedType)
|
||||||
|
{
|
||||||
|
case RobotConfigType.VDA5050:
|
||||||
|
var vIdx = VdaConfigs.FindIndex(x => x.Id == id);
|
||||||
|
if (vIdx >= 0) { SelectedIndex = vIdx; SelectedVda = VdaConfigs[vIdx] with { }; }
|
||||||
|
break;
|
||||||
|
case RobotConfigType.Safety:
|
||||||
|
var sIdx = SafetyConfigs.FindIndex(x => x.Id == id);
|
||||||
|
if (sIdx >= 0) { SelectedIndex = sIdx; SelectedSafety = SafetyConfigs[sIdx] with { }; }
|
||||||
|
break;
|
||||||
|
case RobotConfigType.Simulation:
|
||||||
|
var simIdx = SimulationConfigs.FindIndex(x => x.Id == id);
|
||||||
|
if (simIdx >= 0) { SelectedIndex = simIdx; SelectedSimulation = SimulationConfigs[simIdx] with { }; }
|
||||||
|
break;
|
||||||
|
case RobotConfigType.PLC:
|
||||||
|
var pIdx = PlcConfigs.FindIndex(x => x.Id == id);
|
||||||
|
if (pIdx >= 0) { SelectedIndex = pIdx; SelectedPlc = PlcConfigs[pIdx] with { }; }
|
||||||
|
break;
|
||||||
|
case RobotConfigType.Core:
|
||||||
|
var cIdx = CoreConfigs.FindIndex(x => x.Id == id);
|
||||||
|
if (cIdx >= 0) { SelectedIndex = cIdx; SelectedCore = CoreConfigs[cIdx] with { }; }
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Snackbar.Add($"Error saving config: {ex.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ConfirmDeleteAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (DeletePendingId is null || DeletePendingId == Guid.Empty)
|
||||||
|
{
|
||||||
|
Snackbar.Add("No config selected to delete.", Severity.Warning);
|
||||||
|
CancelDelete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = DeletePendingId.Value;
|
||||||
|
string path = SelectedType switch
|
||||||
|
{
|
||||||
|
RobotConfigType.VDA5050 => $"api/RobotConfigs/vda5050/{id}",
|
||||||
|
RobotConfigType.Safety => $"api/RobotConfigs/safety/{id}",
|
||||||
|
RobotConfigType.Simulation => $"api/RobotConfigs/simulation/{id}",
|
||||||
|
RobotConfigType.PLC => $"api/RobotConfigs/plc/{id}",
|
||||||
|
RobotConfigType.Core => $"api/RobotConfigs/robot/{id}",
|
||||||
|
_ => throw new InvalidOperationException("Unsupported config type")
|
||||||
|
};
|
||||||
|
|
||||||
|
IsLoading = true;
|
||||||
|
StateHasChanged();
|
||||||
|
|
||||||
|
var httpRes = await Http.DeleteFromJsonAsync<MessageResult>(path);
|
||||||
|
|
||||||
|
if (httpRes is null) Snackbar.Add("Failed to delete config", Severity.Warning);
|
||||||
|
else if (!httpRes.IsSuccess) Snackbar.Add(httpRes.Message ?? "Failed to delete config", Severity.Warning);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Snackbar.Add("Config deleted", Severity.Success);
|
||||||
|
|
||||||
|
SelectedIndex = -1;
|
||||||
|
switch (SelectedType)
|
||||||
|
{
|
||||||
|
case RobotConfigType.VDA5050: SelectedVda = null; break;
|
||||||
|
case RobotConfigType.Safety: SelectedSafety = null; break;
|
||||||
|
case RobotConfigType.Simulation: SelectedSimulation = null; break;
|
||||||
|
case RobotConfigType.PLC: SelectedPlc = null; break;
|
||||||
|
case RobotConfigType.Core: SelectedCore = null; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
await LoadForTypeAsync(SelectedType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Snackbar.Add($"Error deleting config: {ex.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsLoading = false;
|
||||||
|
CancelDelete();
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
background: linear-gradient(180deg, rgba(30,30,30,0.95), rgba(20,20,20,0.95));
|
background: var(--mud-palette-surface, #ffffff);
|
||||||
color: #e6e6e6;
|
color: #e6e6e6;
|
||||||
padding: 0.75rem 1rem;
|
padding: 0.75rem 1rem;
|
||||||
border-radius: 0.375rem;
|
border-radius: 0.375rem;
|
||||||
|
|
@ -373,3 +373,148 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Overlay that blocks the whole viewport while loading */
|
||||||
|
.rcm-overlay {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0; /* top:0; right:0; bottom:0; left:0; */
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: rgba(7, 10, 13, 0.55);
|
||||||
|
z-index: 1050; /* above most UI layers */
|
||||||
|
pointer-events: auto; /* capture mouse interactions */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inner content: spinner + optional message */
|
||||||
|
.rcm-overlay-content {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.6rem;
|
||||||
|
background: rgba(20, 20, 20, 0.85);
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 8px 24px rgba(0,0,0,0.45);
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 500;
|
||||||
|
transform: translateY(-6px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* message text */
|
||||||
|
.rcm-overlay-message {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: #eef3ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ensure spinner is visible on dark overlay */
|
||||||
|
.rcm-overlay .spinner-border {
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
border-width: 0.18rem;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modal overlay (create dialog) */
|
||||||
|
.rcm-modal-overlay {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: rgba(7, 10, 13, 0.45);
|
||||||
|
z-index: 1065;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modal container */
|
||||||
|
.rcm-modal {
|
||||||
|
width: 820px;
|
||||||
|
max-width: calc(100% - 40px);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 12px 40px rgba(0,0,0,0.5);
|
||||||
|
background: var(--mud-palette-surface, #0f1720);
|
||||||
|
color: #e6e6e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure card inside modal uses default spacing already present */
|
||||||
|
.rcm-modal .card {
|
||||||
|
background: #0f1720;
|
||||||
|
border: 1px solid rgba(255,255,255,0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header styling */
|
||||||
|
.rcm-modal .card-header {
|
||||||
|
padding: 0.6rem 0.9rem;
|
||||||
|
background: rgba(255,255,255,0.02);
|
||||||
|
border-bottom: 1px solid rgba(255,255,255,0.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modal message / spinner adjustments (already defined for overlay) */
|
||||||
|
.rcm-overlay .spinner-border {
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
border-width: 0.18rem;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep responsive layout for modal form inputs */
|
||||||
|
.rcm-modal .card-body {
|
||||||
|
padding: 0.8rem;
|
||||||
|
color: #e6e6e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Contrast adjustments for modal form elements --- */
|
||||||
|
/* Improve readability by increasing text contrast and adjusting input backgrounds */
|
||||||
|
.rcm-modal {
|
||||||
|
color: #eaf4ff; /* default text inside modal */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* labels, headers and small notes */
|
||||||
|
.rcm-modal .form-label,
|
||||||
|
.rcm-modal label,
|
||||||
|
.rcm-modal .card-header strong,
|
||||||
|
.rcm-modal .card-header,
|
||||||
|
.rcm-modal .form-text,
|
||||||
|
.rcm-modal .validation-message,
|
||||||
|
.rcm-modal .text-muted {
|
||||||
|
color: #cfe6ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* form controls */
|
||||||
|
.rcm-modal .form-control,
|
||||||
|
.rcm-modal .form-select,
|
||||||
|
.rcm-modal input[type="text"],
|
||||||
|
.rcm-modal input[type="number"],
|
||||||
|
.rcm-modal textarea {
|
||||||
|
/*background: rgba(255,255,255,0.03);*/ /* subtle contrast with modal bg */
|
||||||
|
/*color: #ffffff;*/
|
||||||
|
border: 1px solid rgba(255,255,255,0.08);
|
||||||
|
box-shadow: none;
|
||||||
|
caret-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* placeholder text */
|
||||||
|
.rcm-modal .form-control::placeholder,
|
||||||
|
.rcm-modal input::placeholder,
|
||||||
|
.rcm-modal textarea::placeholder {
|
||||||
|
color: rgba(255,255,255,0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* validation / summary messages */
|
||||||
|
.rcm-modal .validation-message,
|
||||||
|
.rcm-modal .validation-summary-valid,
|
||||||
|
.rcm-modal .validation-summary-errors,
|
||||||
|
.rcm-modal .field-validation-error {
|
||||||
|
color: #ffd2d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* modal buttons */
|
||||||
|
.rcm-modal .btn-link {
|
||||||
|
color: #cfcfcf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* keep modal small text readable */
|
||||||
|
.rcm-modal .card-body {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
@ -26,17 +26,16 @@ public record UpdateRobotConfigDto
|
||||||
public double Width { get; set; }
|
public double Width { get; set; }
|
||||||
public double Length { get; set; }
|
public double Length { get; set; }
|
||||||
public double Height { get; set; }
|
public double Height { get; set; }
|
||||||
public string ConfigName { get; set; }
|
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public record CreateRobotConfigDto
|
public record CreateRobotConfigDto
|
||||||
{
|
{
|
||||||
|
public string ConfigName { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
public NavigationType NavigationType { get; set; }
|
public NavigationType NavigationType { get; set; }
|
||||||
public double RadiusWheel { get; set; }
|
public double RadiusWheel { get; set; }
|
||||||
public double Width { get; set; }
|
public double Width { get; set; }
|
||||||
public double Length { get; set; }
|
public double Length { get; set; }
|
||||||
public double Height { get; set; }
|
public double Height { get; set; }
|
||||||
public string ConfigName { get; set; }
|
|
||||||
public string Description { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ public record RobotPlcConfigDto
|
||||||
|
|
||||||
public record UpdateRobotPlcConfigDto
|
public record UpdateRobotPlcConfigDto
|
||||||
{
|
{
|
||||||
public string ConfigName { get; set; }
|
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public string PLCAddress { get; set; }
|
public string PLCAddress { get; set; }
|
||||||
public int PLCPort { get; set; }
|
public int PLCPort { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ public record UpdateRobotSafetyConfigDto
|
||||||
public double SafetySpeedOptimal { get; set; }
|
public double SafetySpeedOptimal { get; set; }
|
||||||
public double SafetySpeedFast { get; set; }
|
public double SafetySpeedFast { get; set; }
|
||||||
public double SafetySpeedVeryFast { get; set; }
|
public double SafetySpeedVeryFast { get; set; }
|
||||||
public string ConfigName { get; set; }
|
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ public record UpdateRobotSimulationConfigDto
|
||||||
public double SimulationMaxAngularVelocity { get; set; }
|
public double SimulationMaxAngularVelocity { get; set; }
|
||||||
public double SimulationAcceleration { get; set; }
|
public double SimulationAcceleration { get; set; }
|
||||||
public double SimulationDeceleration { get; set; }
|
public double SimulationDeceleration { get; set; }
|
||||||
public string ConfigName { get; set; }
|
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,19 @@
|
||||||
namespace RobotApp.Common.Shares.Dtos;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace RobotApp.Common.Shares.Dtos;
|
||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
public record RobotVDA5050ConfigDto
|
public record RobotVDA5050ConfigDto
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
[Required]
|
||||||
public string SerialNumber { get; set; }
|
public string SerialNumber { get; set; }
|
||||||
|
[Required]
|
||||||
public string VDA5050HostServer { get; set; }
|
public string VDA5050HostServer { get; set; }
|
||||||
|
[Required]
|
||||||
public int VDA5050Port { get; set; }
|
public int VDA5050Port { get; set; }
|
||||||
|
[Required]
|
||||||
public string VDA5050UserName { get; set; }
|
public string VDA5050UserName { get; set; }
|
||||||
public string VDA5050Password { get; set; }
|
public string VDA5050Password { get; set; }
|
||||||
public string VDA5050Manufacturer { get; set; }
|
public string VDA5050Manufacturer { get; set; }
|
||||||
|
|
@ -15,6 +21,9 @@ public record RobotVDA5050ConfigDto
|
||||||
public int VDA5050PublishRepeat { get; set; }
|
public int VDA5050PublishRepeat { get; set; }
|
||||||
public bool VDA5050EnablePassword { get; set; }
|
public bool VDA5050EnablePassword { get; set; }
|
||||||
public bool VDA5050EnableTls { get; set; }
|
public bool VDA5050EnableTls { get; set; }
|
||||||
|
public string VDA5050CA { get; set; }
|
||||||
|
public string VDA5050Cer { get; set; }
|
||||||
|
public string VDA5050_Key { get; set; }
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public DateTime UpdatedAt { get; set; }
|
public DateTime UpdatedAt { get; set; }
|
||||||
public bool IsActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
|
|
@ -34,7 +43,9 @@ public record UpdateRobotVDA5050ConfigDto
|
||||||
public int VDA5050PublishRepeat { get; set; }
|
public int VDA5050PublishRepeat { get; set; }
|
||||||
public bool VDA5050EnablePassword { get; set; }
|
public bool VDA5050EnablePassword { get; set; }
|
||||||
public bool VDA5050EnableTls { get; set; }
|
public bool VDA5050EnableTls { get; set; }
|
||||||
public string ConfigName { get; set; }
|
public string VDA5050CA { get; set; }
|
||||||
|
public string VDA5050Cer { get; set; }
|
||||||
|
public string VDA5050_Key { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,6 +61,9 @@ public record CreateRobotVDA5050ConfigDto
|
||||||
public int VDA5050PublishRepeat { get; set; }
|
public int VDA5050PublishRepeat { get; set; }
|
||||||
public bool VDA5050EnablePassword { get; set; }
|
public bool VDA5050EnablePassword { get; set; }
|
||||||
public bool VDA5050EnableTls { get; set; }
|
public bool VDA5050EnableTls { get; set; }
|
||||||
|
public string VDA5050CA { get; set; }
|
||||||
|
public string VDA5050Cer { get; set; }
|
||||||
|
public string VDA5050_Key { get; set; }
|
||||||
public string ConfigName { get; set; }
|
public string ConfigName { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http.HttpResults;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using RobotApp.Common.Shares;
|
using RobotApp.Common.Shares;
|
||||||
|
|
@ -49,18 +50,13 @@ public class RobotConfigsController(Services.Logger<RobotConfigsController> Logg
|
||||||
|
|
||||||
[HttpPut]
|
[HttpPut]
|
||||||
[Route("plc/{id:guid}")]
|
[Route("plc/{id:guid}")]
|
||||||
public async Task<MessageResult<RobotPlcConfigDto>> UpdatePLCConfig(Guid id, [FromBody] UpdateRobotPlcConfigDto updateDto)
|
public async Task<MessageResult> UpdatePLCConfig(Guid id, [FromBody] UpdateRobotPlcConfigDto updateDto)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var config = await AppDb.RobotPlcConfigs.FindAsync(id);
|
var config = await AppDb.RobotPlcConfigs.FindAsync(id);
|
||||||
if (config is null) return new(false, "PLC configuration not found.");
|
if (config is null) return new(false, "PLC configuration not found.");
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(updateDto.ConfigName)) return new(false, "ConfigName cannot be null or empty.");
|
|
||||||
if (await AppDb.RobotPlcConfigs.AnyAsync(cf => cf.Id != id && cf.ConfigName == updateDto.ConfigName))
|
|
||||||
return new(false, "A PLC configuration with the same name already exists.");
|
|
||||||
|
|
||||||
config.ConfigName = updateDto.ConfigName ?? config.ConfigName;
|
|
||||||
config.Description = updateDto.Description ?? config.Description;
|
config.Description = updateDto.Description ?? config.Description;
|
||||||
config.PLCAddress = updateDto.PLCAddress ?? config.PLCAddress;
|
config.PLCAddress = updateDto.PLCAddress ?? config.PLCAddress;
|
||||||
config.PLCPort = updateDto.PLCPort;
|
config.PLCPort = updateDto.PLCPort;
|
||||||
|
|
@ -70,21 +66,7 @@ public class RobotConfigsController(Services.Logger<RobotConfigsController> Logg
|
||||||
await AppDb.SaveChangesAsync();
|
await AppDb.SaveChangesAsync();
|
||||||
|
|
||||||
if (config.IsActive) await RobotConfiguration.LoadRobotPlcConfigAsync();
|
if (config.IsActive) await RobotConfiguration.LoadRobotPlcConfigAsync();
|
||||||
return new(true, "PLC configuration updated successfully.")
|
return new(true, "PLC configuration updated successfully.");
|
||||||
{
|
|
||||||
Data = new RobotPlcConfigDto
|
|
||||||
{
|
|
||||||
Id = config.Id,
|
|
||||||
ConfigName = config.ConfigName,
|
|
||||||
Description = config.Description,
|
|
||||||
PLCAddress = config.PLCAddress,
|
|
||||||
PLCPort = config.PLCPort,
|
|
||||||
PLCUnitId = config.PLCUnitId,
|
|
||||||
CreatedAt = config.CreatedAt,
|
|
||||||
UpdatedAt = config.UpdatedAt,
|
|
||||||
IsActive = config.IsActive,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -150,6 +132,7 @@ public class RobotConfigsController(Services.Logger<RobotConfigsController> Logg
|
||||||
var config = await AppDb.RobotPlcConfigs.FindAsync(id);
|
var config = await AppDb.RobotPlcConfigs.FindAsync(id);
|
||||||
if (config is null) return new(false, "PLC configuration not found.");
|
if (config is null) return new(false, "PLC configuration not found.");
|
||||||
if (config.IsActive) return new(false, "Cannot delete an active PLC configuration.");
|
if (config.IsActive) return new(false, "Cannot delete an active PLC configuration.");
|
||||||
|
if (config.ConfigName == "Default") return new(false, "Cannot delete the default PLC configuration.");
|
||||||
|
|
||||||
AppDb.RobotPlcConfigs.Remove(config);
|
AppDb.RobotPlcConfigs.Remove(config);
|
||||||
await AppDb.SaveChangesAsync();
|
await AppDb.SaveChangesAsync();
|
||||||
|
|
@ -211,6 +194,9 @@ public class RobotConfigsController(Services.Logger<RobotConfigsController> Logg
|
||||||
VDA5050PublishRepeat = config.VDA5050PublishRepeat,
|
VDA5050PublishRepeat = config.VDA5050PublishRepeat,
|
||||||
VDA5050EnablePassword = config.VDA5050EnablePassword,
|
VDA5050EnablePassword = config.VDA5050EnablePassword,
|
||||||
VDA5050EnableTls = config.VDA5050EnableTls,
|
VDA5050EnableTls = config.VDA5050EnableTls,
|
||||||
|
VDA5050CA = config.VDA5050CA,
|
||||||
|
VDA5050Cer = config.VDA5050Cer,
|
||||||
|
VDA5050_Key = config.VDA5050_Key,
|
||||||
CreatedAt = config.CreatedAt,
|
CreatedAt = config.CreatedAt,
|
||||||
UpdatedAt = config.UpdatedAt,
|
UpdatedAt = config.UpdatedAt,
|
||||||
IsActive = config.IsActive,
|
IsActive = config.IsActive,
|
||||||
|
|
@ -229,17 +215,13 @@ public class RobotConfigsController(Services.Logger<RobotConfigsController> Logg
|
||||||
|
|
||||||
[HttpPut]
|
[HttpPut]
|
||||||
[Route("vda5050/{id:guid}")]
|
[Route("vda5050/{id:guid}")]
|
||||||
public async Task<MessageResult<RobotVDA5050ConfigDto>> UpdateVDA5050Config(Guid id, [FromBody] UpdateRobotVDA5050ConfigDto updateDto)
|
public async Task<MessageResult> UpdateVDA5050Config(Guid id, [FromBody] UpdateRobotVDA5050ConfigDto updateDto)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var config = await AppDb.RobotVDA5050Configs.FindAsync(id);
|
var config = await AppDb.RobotVDA5050Configs.FindAsync(id);
|
||||||
if (config is null) return new(false, "VDA5050 configuration not found.");
|
if (config is null) return new(false, "VDA5050 configuration not found.");
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(updateDto.ConfigName)) return new(false, "ConfigName cannot be null or empty.");
|
|
||||||
if (await AppDb.RobotVDA5050Configs.AnyAsync(cf => cf.Id != id && cf.ConfigName == updateDto.ConfigName))
|
|
||||||
return new(false, "A VDA5050 configuration with the same name already exists.");
|
|
||||||
|
|
||||||
config.SerialNumber = updateDto.SerialNumber ?? config.SerialNumber;
|
config.SerialNumber = updateDto.SerialNumber ?? config.SerialNumber;
|
||||||
config.VDA5050HostServer = updateDto.VDA5050HostServer ?? config.VDA5050HostServer;
|
config.VDA5050HostServer = updateDto.VDA5050HostServer ?? config.VDA5050HostServer;
|
||||||
config.VDA5050Port = updateDto.VDA5050Port;
|
config.VDA5050Port = updateDto.VDA5050Port;
|
||||||
|
|
@ -250,35 +232,16 @@ public class RobotConfigsController(Services.Logger<RobotConfigsController> Logg
|
||||||
config.VDA5050PublishRepeat = updateDto.VDA5050PublishRepeat;
|
config.VDA5050PublishRepeat = updateDto.VDA5050PublishRepeat;
|
||||||
config.VDA5050EnablePassword = updateDto.VDA5050EnablePassword;
|
config.VDA5050EnablePassword = updateDto.VDA5050EnablePassword;
|
||||||
config.VDA5050EnableTls = updateDto.VDA5050EnableTls;
|
config.VDA5050EnableTls = updateDto.VDA5050EnableTls;
|
||||||
config.ConfigName = updateDto.ConfigName ?? config.ConfigName;
|
config.VDA5050CA = updateDto.VDA5050CA;
|
||||||
|
config.VDA5050Cer = updateDto.VDA5050Cer;
|
||||||
|
config.VDA5050_Key = updateDto.VDA5050_Key;
|
||||||
config.Description = updateDto.Description ?? config.Description;
|
config.Description = updateDto.Description ?? config.Description;
|
||||||
config.UpdatedAt = DateTime.Now;
|
config.UpdatedAt = DateTime.Now;
|
||||||
|
|
||||||
await AppDb.SaveChangesAsync();
|
await AppDb.SaveChangesAsync();
|
||||||
|
|
||||||
if (config.IsActive) await RobotConfiguration.LoadVDA5050ConfigAsync();
|
if (config.IsActive) await RobotConfiguration.LoadVDA5050ConfigAsync();
|
||||||
return new(true, "VDA5050 configuration updated successfully.")
|
return new(true, "VDA5050 configuration updated successfully.");
|
||||||
{
|
|
||||||
Data = new RobotVDA5050ConfigDto
|
|
||||||
{
|
|
||||||
Id = config.Id,
|
|
||||||
SerialNumber = config.SerialNumber,
|
|
||||||
VDA5050HostServer = config.VDA5050HostServer,
|
|
||||||
VDA5050Port = config.VDA5050Port,
|
|
||||||
VDA5050UserName = config.VDA5050UserName,
|
|
||||||
VDA5050Password = config.VDA5050Password,
|
|
||||||
VDA5050Manufacturer = config.VDA5050Manufacturer,
|
|
||||||
VDA5050Version = config.VDA5050Version,
|
|
||||||
VDA5050PublishRepeat = config.VDA5050PublishRepeat,
|
|
||||||
VDA5050EnablePassword = config.VDA5050EnablePassword,
|
|
||||||
VDA5050EnableTls = config.VDA5050EnableTls,
|
|
||||||
CreatedAt = config.CreatedAt,
|
|
||||||
UpdatedAt = config.UpdatedAt,
|
|
||||||
IsActive = config.IsActive,
|
|
||||||
ConfigName = config.ConfigName,
|
|
||||||
Description = config.Description
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -311,6 +274,9 @@ public class RobotConfigsController(Services.Logger<RobotConfigsController> Logg
|
||||||
VDA5050PublishRepeat = createDto.VDA5050PublishRepeat,
|
VDA5050PublishRepeat = createDto.VDA5050PublishRepeat,
|
||||||
VDA5050EnablePassword = createDto.VDA5050EnablePassword,
|
VDA5050EnablePassword = createDto.VDA5050EnablePassword,
|
||||||
VDA5050EnableTls = createDto.VDA5050EnableTls,
|
VDA5050EnableTls = createDto.VDA5050EnableTls,
|
||||||
|
VDA5050CA = createDto.VDA5050CA,
|
||||||
|
VDA5050Cer = createDto.VDA5050Cer,
|
||||||
|
VDA5050_Key = createDto.VDA5050_Key,
|
||||||
CreatedAt = DateTime.Now,
|
CreatedAt = DateTime.Now,
|
||||||
UpdatedAt = DateTime.Now,
|
UpdatedAt = DateTime.Now,
|
||||||
IsActive = false
|
IsActive = false
|
||||||
|
|
@ -336,6 +302,9 @@ public class RobotConfigsController(Services.Logger<RobotConfigsController> Logg
|
||||||
VDA5050PublishRepeat = config.VDA5050PublishRepeat,
|
VDA5050PublishRepeat = config.VDA5050PublishRepeat,
|
||||||
VDA5050EnablePassword = config.VDA5050EnablePassword,
|
VDA5050EnablePassword = config.VDA5050EnablePassword,
|
||||||
VDA5050EnableTls = config.VDA5050EnableTls,
|
VDA5050EnableTls = config.VDA5050EnableTls,
|
||||||
|
VDA5050CA = config.VDA5050CA,
|
||||||
|
VDA5050Cer = config.VDA5050Cer,
|
||||||
|
VDA5050_Key = config.VDA5050_Key,
|
||||||
CreatedAt = config.CreatedAt,
|
CreatedAt = config.CreatedAt,
|
||||||
UpdatedAt = config.UpdatedAt,
|
UpdatedAt = config.UpdatedAt,
|
||||||
IsActive = config.IsActive,
|
IsActive = config.IsActive,
|
||||||
|
|
@ -358,6 +327,7 @@ public class RobotConfigsController(Services.Logger<RobotConfigsController> Logg
|
||||||
var config = await AppDb.RobotVDA5050Configs.FindAsync(id);
|
var config = await AppDb.RobotVDA5050Configs.FindAsync(id);
|
||||||
if (config is null) return new(false, "VDA5050 configuration not found.");
|
if (config is null) return new(false, "VDA5050 configuration not found.");
|
||||||
if (config.IsActive) return new(false, "Cannot delete an active VDA5050 configuration.");
|
if (config.IsActive) return new(false, "Cannot delete an active VDA5050 configuration.");
|
||||||
|
if (config.ConfigName == "Default") return new(false, "Cannot delete the default PLC configuration.");
|
||||||
|
|
||||||
AppDb.RobotVDA5050Configs.Remove(config);
|
AppDb.RobotVDA5050Configs.Remove(config);
|
||||||
await AppDb.SaveChangesAsync();
|
await AppDb.SaveChangesAsync();
|
||||||
|
|
@ -432,46 +402,25 @@ public class RobotConfigsController(Services.Logger<RobotConfigsController> Logg
|
||||||
|
|
||||||
[HttpPut]
|
[HttpPut]
|
||||||
[Route("robot/{id:guid}")]
|
[Route("robot/{id:guid}")]
|
||||||
public async Task<MessageResult<RobotConfigDto>> UpdateRobotConfig(Guid id, [FromBody] UpdateRobotConfigDto updateDto)
|
public async Task<MessageResult> UpdateRobotConfig(Guid id, [FromBody] UpdateRobotConfigDto updateDto)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var config = await AppDb.RobotConfigs.FindAsync(id);
|
var config = await AppDb.RobotConfigs.FindAsync(id);
|
||||||
if (config is null) return new(false, "Robot configuration not found.");
|
if (config is null) return new(false, "Robot configuration not found.");
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(updateDto.ConfigName)) return new(false, "ConfigName cannot be null or empty.");
|
|
||||||
if (await AppDb.RobotConfigs.AnyAsync(cf => cf.Id != id && cf.ConfigName == updateDto.ConfigName))
|
|
||||||
return new(false, "A Robot configuration with the same name already exists.");
|
|
||||||
|
|
||||||
config.NavigationType = updateDto.NavigationType;
|
config.NavigationType = updateDto.NavigationType;
|
||||||
config.RadiusWheel = updateDto.RadiusWheel;
|
config.RadiusWheel = updateDto.RadiusWheel;
|
||||||
config.Width = updateDto.Width;
|
config.Width = updateDto.Width;
|
||||||
config.Length = updateDto.Length;
|
config.Length = updateDto.Length;
|
||||||
config.Height = updateDto.Height;
|
config.Height = updateDto.Height;
|
||||||
config.ConfigName = updateDto.ConfigName ?? config.ConfigName;
|
|
||||||
config.Description = updateDto.Description ?? config.Description;
|
config.Description = updateDto.Description ?? config.Description;
|
||||||
config.UpdatedAt = DateTime.Now;
|
config.UpdatedAt = DateTime.Now;
|
||||||
|
|
||||||
await AppDb.SaveChangesAsync();
|
await AppDb.SaveChangesAsync();
|
||||||
|
|
||||||
if (config.IsActive) await RobotConfiguration.LoadRobotConfigAsync();
|
if (config.IsActive) await RobotConfiguration.LoadRobotConfigAsync();
|
||||||
return new(true, "Robot configuration updated successfully.")
|
return new(true, "Robot configuration updated successfully.");
|
||||||
{
|
|
||||||
Data = new RobotConfigDto
|
|
||||||
{
|
|
||||||
Id = config.Id,
|
|
||||||
NavigationType = config.NavigationType,
|
|
||||||
RadiusWheel = config.RadiusWheel,
|
|
||||||
Width = config.Width,
|
|
||||||
Length = config.Length,
|
|
||||||
Height = config.Height,
|
|
||||||
CreatedAt = config.CreatedAt,
|
|
||||||
UpdatedAt = config.UpdatedAt,
|
|
||||||
IsActive = config.IsActive,
|
|
||||||
ConfigName = config.ConfigName,
|
|
||||||
Description = config.Description
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -541,6 +490,7 @@ public class RobotConfigsController(Services.Logger<RobotConfigsController> Logg
|
||||||
var config = await AppDb.RobotConfigs.FindAsync(id);
|
var config = await AppDb.RobotConfigs.FindAsync(id);
|
||||||
if (config is null) return new(false, "Robot configuration not found.");
|
if (config is null) return new(false, "Robot configuration not found.");
|
||||||
if (config.IsActive) return new(false, "Cannot delete an active Robot configuration.");
|
if (config.IsActive) return new(false, "Cannot delete an active Robot configuration.");
|
||||||
|
if (config.ConfigName == "Default") return new(false, "Cannot delete the default PLC configuration.");
|
||||||
|
|
||||||
AppDb.RobotConfigs.Remove(config);
|
AppDb.RobotConfigs.Remove(config);
|
||||||
await AppDb.SaveChangesAsync();
|
await AppDb.SaveChangesAsync();
|
||||||
|
|
@ -615,46 +565,25 @@ public class RobotConfigsController(Services.Logger<RobotConfigsController> Logg
|
||||||
|
|
||||||
[HttpPut]
|
[HttpPut]
|
||||||
[Route("simulation/{id:guid}")]
|
[Route("simulation/{id:guid}")]
|
||||||
public async Task<MessageResult<RobotSimulationConfigDto>> UpdateSimulationConfig(Guid id, [FromBody] UpdateRobotSimulationConfigDto updateDto)
|
public async Task<MessageResult> UpdateSimulationConfig(Guid id, [FromBody] UpdateRobotSimulationConfigDto updateDto)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var config = await AppDb.RobotSimulationConfigs.FindAsync(id);
|
var config = await AppDb.RobotSimulationConfigs.FindAsync(id);
|
||||||
if (config is null) return new(false, "Simulation configuration not found.");
|
if (config is null) return new(false, "Simulation configuration not found.");
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(updateDto.ConfigName)) return new(false, "ConfigName cannot be null or empty.");
|
|
||||||
if (await AppDb.RobotSimulationConfigs.AnyAsync(cf => cf.Id != id && cf.ConfigName == updateDto.ConfigName))
|
|
||||||
return new(false, "A Simulation configuration with the same name already exists.");
|
|
||||||
|
|
||||||
config.EnableSimulation = updateDto.EnableSimulation;
|
config.EnableSimulation = updateDto.EnableSimulation;
|
||||||
config.SimulationMaxVelocity = updateDto.SimulationMaxVelocity;
|
config.SimulationMaxVelocity = updateDto.SimulationMaxVelocity;
|
||||||
config.SimulationMaxAngularVelocity = updateDto.SimulationMaxAngularVelocity;
|
config.SimulationMaxAngularVelocity = updateDto.SimulationMaxAngularVelocity;
|
||||||
config.SimulationAcceleration = updateDto.SimulationAcceleration;
|
config.SimulationAcceleration = updateDto.SimulationAcceleration;
|
||||||
config.SimulationDeceleration = updateDto.SimulationDeceleration;
|
config.SimulationDeceleration = updateDto.SimulationDeceleration;
|
||||||
config.ConfigName = updateDto.ConfigName ?? config.ConfigName;
|
|
||||||
config.Description = updateDto.Description ?? config.Description;
|
config.Description = updateDto.Description ?? config.Description;
|
||||||
config.UpdatedAt = DateTime.Now;
|
config.UpdatedAt = DateTime.Now;
|
||||||
|
|
||||||
await AppDb.SaveChangesAsync();
|
await AppDb.SaveChangesAsync();
|
||||||
|
|
||||||
if (config.IsActive) await RobotConfiguration.LoadRobotSimulationConfigAsync();
|
if (config.IsActive) await RobotConfiguration.LoadRobotSimulationConfigAsync();
|
||||||
return new(true, "Simulation configuration updated successfully.")
|
return new(true, "Simulation configuration updated successfully.");
|
||||||
{
|
|
||||||
Data = new RobotSimulationConfigDto
|
|
||||||
{
|
|
||||||
Id = config.Id,
|
|
||||||
EnableSimulation = config.EnableSimulation,
|
|
||||||
SimulationMaxVelocity = config.SimulationMaxVelocity,
|
|
||||||
SimulationMaxAngularVelocity = config.SimulationMaxAngularVelocity,
|
|
||||||
SimulationAcceleration = config.SimulationAcceleration,
|
|
||||||
SimulationDeceleration = config.SimulationDeceleration,
|
|
||||||
CreatedAt = config.CreatedAt,
|
|
||||||
UpdatedAt = config.UpdatedAt,
|
|
||||||
IsActive = config.IsActive,
|
|
||||||
ConfigName = config.ConfigName,
|
|
||||||
Description = config.Description
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -724,6 +653,7 @@ public class RobotConfigsController(Services.Logger<RobotConfigsController> Logg
|
||||||
var config = await AppDb.RobotSimulationConfigs.FindAsync(id);
|
var config = await AppDb.RobotSimulationConfigs.FindAsync(id);
|
||||||
if (config is null) return new(false, "Simulation configuration not found.");
|
if (config is null) return new(false, "Simulation configuration not found.");
|
||||||
if (config.IsActive) return new(false, "Cannot delete an active Simulation configuration.");
|
if (config.IsActive) return new(false, "Cannot delete an active Simulation configuration.");
|
||||||
|
if (config.ConfigName == "Default") return new(false, "Cannot delete the default PLC configuration.");
|
||||||
|
|
||||||
AppDb.RobotSimulationConfigs.Remove(config);
|
AppDb.RobotSimulationConfigs.Remove(config);
|
||||||
await AppDb.SaveChangesAsync();
|
await AppDb.SaveChangesAsync();
|
||||||
|
|
@ -799,17 +729,13 @@ public class RobotConfigsController(Services.Logger<RobotConfigsController> Logg
|
||||||
|
|
||||||
[HttpPut]
|
[HttpPut]
|
||||||
[Route("safety/{id:guid}")]
|
[Route("safety/{id:guid}")]
|
||||||
public async Task<MessageResult<RobotSafetyConfigDto>> UpdateSafetyConfig(Guid id, [FromBody] UpdateRobotSafetyConfigDto updateDto)
|
public async Task<MessageResult> UpdateSafetyConfig(Guid id, [FromBody] UpdateRobotSafetyConfigDto updateDto)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var config = await AppDb.RobotSafetyConfigs.FindAsync(id);
|
var config = await AppDb.RobotSafetyConfigs.FindAsync(id);
|
||||||
if (config is null) return new(false, "Safety configuration not found.");
|
if (config is null) return new(false, "Safety configuration not found.");
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(updateDto.ConfigName)) return new(false, "ConfigName cannot be null or empty.");
|
|
||||||
if (await AppDb.RobotSafetyConfigs.AnyAsync(cf => cf.Id != id && cf.ConfigName == updateDto.ConfigName))
|
|
||||||
return new(false, "A Safety configuration with the same name already exists.");
|
|
||||||
|
|
||||||
config.SafetySpeedVerySlow = updateDto.SafetySpeedVerySlow;
|
config.SafetySpeedVerySlow = updateDto.SafetySpeedVerySlow;
|
||||||
config.SafetySpeedSlow = updateDto.SafetySpeedSlow;
|
config.SafetySpeedSlow = updateDto.SafetySpeedSlow;
|
||||||
config.SafetySpeedNormal = updateDto.SafetySpeedNormal;
|
config.SafetySpeedNormal = updateDto.SafetySpeedNormal;
|
||||||
|
|
@ -817,32 +743,13 @@ public class RobotConfigsController(Services.Logger<RobotConfigsController> Logg
|
||||||
config.SafetySpeedOptimal = updateDto.SafetySpeedOptimal;
|
config.SafetySpeedOptimal = updateDto.SafetySpeedOptimal;
|
||||||
config.SafetySpeedFast = updateDto.SafetySpeedFast;
|
config.SafetySpeedFast = updateDto.SafetySpeedFast;
|
||||||
config.SafetySpeedVeryFast = updateDto.SafetySpeedVeryFast;
|
config.SafetySpeedVeryFast = updateDto.SafetySpeedVeryFast;
|
||||||
config.ConfigName = updateDto.ConfigName ?? config.ConfigName;
|
|
||||||
config.Description = updateDto.Description ?? config.Description;
|
config.Description = updateDto.Description ?? config.Description;
|
||||||
config.UpdatedAt = DateTime.Now;
|
config.UpdatedAt = DateTime.Now;
|
||||||
|
|
||||||
await AppDb.SaveChangesAsync();
|
await AppDb.SaveChangesAsync();
|
||||||
|
|
||||||
if (config.IsActive) await RobotConfiguration.LoadRobotSafetyConfigAsync();
|
if (config.IsActive) await RobotConfiguration.LoadRobotSafetyConfigAsync();
|
||||||
return new(true, "Safety configuration updated successfully.")
|
return new(true, "Safety configuration updated successfully.");
|
||||||
{
|
|
||||||
Data = new RobotSafetyConfigDto
|
|
||||||
{
|
|
||||||
Id = config.Id,
|
|
||||||
SafetySpeedVerySlow = config.SafetySpeedVerySlow,
|
|
||||||
SafetySpeedSlow = config.SafetySpeedSlow,
|
|
||||||
SafetySpeedNormal = config.SafetySpeedNormal,
|
|
||||||
SafetySpeedMedium = config.SafetySpeedMedium,
|
|
||||||
SafetySpeedOptimal = config.SafetySpeedOptimal,
|
|
||||||
SafetySpeedFast = config.SafetySpeedFast,
|
|
||||||
SafetySpeedVeryFast = config.SafetySpeedVeryFast,
|
|
||||||
CreatedAt = config.CreatedAt,
|
|
||||||
UpdatedAt = config.UpdatedAt,
|
|
||||||
IsActive = config.IsActive,
|
|
||||||
ConfigName = config.ConfigName,
|
|
||||||
Description = config.Description
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -916,6 +823,7 @@ public class RobotConfigsController(Services.Logger<RobotConfigsController> Logg
|
||||||
var config = await AppDb.RobotSafetyConfigs.FindAsync(id);
|
var config = await AppDb.RobotSafetyConfigs.FindAsync(id);
|
||||||
if (config is null) return new(false, "Safety configuration not found.");
|
if (config is null) return new(false, "Safety configuration not found.");
|
||||||
if (config.IsActive) return new(false, "Cannot delete an active Safety configuration.");
|
if (config.IsActive) return new(false, "Cannot delete an active Safety configuration.");
|
||||||
|
if (config.ConfigName == "Default") return new(false, "Cannot delete the default PLC configuration.");
|
||||||
|
|
||||||
AppDb.RobotSafetyConfigs.Remove(config);
|
AppDb.RobotSafetyConfigs.Remove(config);
|
||||||
await AppDb.SaveChangesAsync();
|
await AppDb.SaveChangesAsync();
|
||||||
|
|
|
||||||
577
RobotApp/Data/Migrations/20251031073231_UpdateVDA5050Config.Designer.cs
generated
Normal file
577
RobotApp/Data/Migrations/20251031073231_UpdateVDA5050Config.Designer.cs
generated
Normal file
|
|
@ -0,0 +1,577 @@
|
||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using RobotApp.Data;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace RobotApp.Data.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
|
[Migration("20251031073231_UpdateVDA5050Config")]
|
||||||
|
partial class UpdateVDA5050Config
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "9.0.9");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoleClaims", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserClaims", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("LoginProvider")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderKey")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderDisplayName")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("LoginProvider", "ProviderKey");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserLogins", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "RoleId");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserRoles", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("LoginProvider")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "LoginProvider", "Name");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserTokens", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RobotApp.Data.ApplicationRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("RoleNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoles", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RobotApp.Data.ApplicationUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("AccessFailedCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("EmailConfirmed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("LockoutEnabled")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedEmail")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedUserName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("PhoneNumber")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("PhoneNumberConfirmed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("SecurityStamp")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("TwoFactorEnabled")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedEmail")
|
||||||
|
.HasDatabaseName("EmailIndex");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedUserName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("UserNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUsers", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RobotApp.Data.RobotConfig", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("Id");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigName")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("nvarchar(64)")
|
||||||
|
.HasColumnName("ConfigName");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime2")
|
||||||
|
.HasColumnName("CreatedAt");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("ntext")
|
||||||
|
.HasColumnName("Description");
|
||||||
|
|
||||||
|
b.Property<double>("Height")
|
||||||
|
.HasColumnType("float")
|
||||||
|
.HasColumnName("Height");
|
||||||
|
|
||||||
|
b.Property<bool>("IsActive")
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasColumnName("IsActive");
|
||||||
|
|
||||||
|
b.Property<double>("Length")
|
||||||
|
.HasColumnType("float")
|
||||||
|
.HasColumnName("Length");
|
||||||
|
|
||||||
|
b.Property<int>("NavigationType")
|
||||||
|
.HasColumnType("int")
|
||||||
|
.HasColumnName("NavigationType");
|
||||||
|
|
||||||
|
b.Property<double>("RadiusWheel")
|
||||||
|
.HasColumnType("float")
|
||||||
|
.HasColumnName("RadiusWheel");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedAt")
|
||||||
|
.HasColumnType("datetime2")
|
||||||
|
.HasColumnName("UpdatedAt");
|
||||||
|
|
||||||
|
b.Property<double>("Width")
|
||||||
|
.HasColumnType("float")
|
||||||
|
.HasColumnName("Width");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("RobotConfig");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RobotApp.Data.RobotPlcConfig", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("Id");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigName")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("nvarchar(64)")
|
||||||
|
.HasColumnName("ConfigName");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime2")
|
||||||
|
.HasColumnName("CreatedAt");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("ntext")
|
||||||
|
.HasColumnName("Description");
|
||||||
|
|
||||||
|
b.Property<bool>("IsActive")
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasColumnName("IsActive");
|
||||||
|
|
||||||
|
b.Property<string>("PLCAddress")
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("nvarchar(64)")
|
||||||
|
.HasColumnName("PLCAddress");
|
||||||
|
|
||||||
|
b.Property<int>("PLCPort")
|
||||||
|
.HasColumnType("int")
|
||||||
|
.HasColumnName("PLCPort");
|
||||||
|
|
||||||
|
b.Property<byte>("PLCUnitId")
|
||||||
|
.HasColumnType("tinyint")
|
||||||
|
.HasColumnName("PLCUnitId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedAt")
|
||||||
|
.HasColumnType("datetime2")
|
||||||
|
.HasColumnName("UpdatedAt");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("RobotPlcConfig");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RobotApp.Data.RobotSafetyConfig", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("Id");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigName")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("nvarchar(64)")
|
||||||
|
.HasColumnName("ConfigName");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime2")
|
||||||
|
.HasColumnName("CreatedAt");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("ntext")
|
||||||
|
.HasColumnName("Description");
|
||||||
|
|
||||||
|
b.Property<bool>("IsActive")
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasColumnName("IsActive");
|
||||||
|
|
||||||
|
b.Property<double>("SafetySpeedFast")
|
||||||
|
.HasColumnType("float")
|
||||||
|
.HasColumnName("SafetySpeedFast");
|
||||||
|
|
||||||
|
b.Property<double>("SafetySpeedMedium")
|
||||||
|
.HasColumnType("float")
|
||||||
|
.HasColumnName("SafetySpeedMedium");
|
||||||
|
|
||||||
|
b.Property<double>("SafetySpeedNormal")
|
||||||
|
.HasColumnType("float")
|
||||||
|
.HasColumnName("SafetySpeedNormal");
|
||||||
|
|
||||||
|
b.Property<double>("SafetySpeedOptimal")
|
||||||
|
.HasColumnType("float")
|
||||||
|
.HasColumnName("SafetySpeedOptimal");
|
||||||
|
|
||||||
|
b.Property<double>("SafetySpeedSlow")
|
||||||
|
.HasColumnType("float")
|
||||||
|
.HasColumnName("SafetySpeedSlow");
|
||||||
|
|
||||||
|
b.Property<double>("SafetySpeedVeryFast")
|
||||||
|
.HasColumnType("float")
|
||||||
|
.HasColumnName("SafetySpeedVeryFast");
|
||||||
|
|
||||||
|
b.Property<double>("SafetySpeedVerySlow")
|
||||||
|
.HasColumnType("float")
|
||||||
|
.HasColumnName("SafetySpeedVerySlow");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedAt")
|
||||||
|
.HasColumnType("datetime2")
|
||||||
|
.HasColumnName("UpdatedAt");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("RobotSafetyConfig");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RobotApp.Data.RobotSimulationConfig", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("Id");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigName")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("nvarchar(64)")
|
||||||
|
.HasColumnName("ConfigName");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime2")
|
||||||
|
.HasColumnName("CreatedAt");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("ntext")
|
||||||
|
.HasColumnName("Description");
|
||||||
|
|
||||||
|
b.Property<bool>("EnableSimulation")
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasColumnName("EnableSimulation");
|
||||||
|
|
||||||
|
b.Property<bool>("IsActive")
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasColumnName("IsActive");
|
||||||
|
|
||||||
|
b.Property<double>("SimulationAcceleration")
|
||||||
|
.HasColumnType("float")
|
||||||
|
.HasColumnName("SimulationAcceleration");
|
||||||
|
|
||||||
|
b.Property<double>("SimulationDeceleration")
|
||||||
|
.HasColumnType("float")
|
||||||
|
.HasColumnName("SimulationDeceleration");
|
||||||
|
|
||||||
|
b.Property<double>("SimulationMaxAngularVelocity")
|
||||||
|
.HasColumnType("float")
|
||||||
|
.HasColumnName("SimulationMaxAngularVelocity");
|
||||||
|
|
||||||
|
b.Property<double>("SimulationMaxVelocity")
|
||||||
|
.HasColumnType("float")
|
||||||
|
.HasColumnName("SimulationMaxVelocity");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedAt")
|
||||||
|
.HasColumnType("datetime2")
|
||||||
|
.HasColumnName("UpdatedAt");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("RobotSimulationConfig");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("RobotApp.Data.RobotVDA5050Config", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("Id");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigName")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("nvarchar(64)")
|
||||||
|
.HasColumnName("ConfigName");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime2")
|
||||||
|
.HasColumnName("CreatedAt");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("ntext")
|
||||||
|
.HasColumnName("Description");
|
||||||
|
|
||||||
|
b.Property<bool>("IsActive")
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasColumnName("IsActive");
|
||||||
|
|
||||||
|
b.Property<string>("SerialNumber")
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("nvarchar(64)")
|
||||||
|
.HasColumnName("SerialNumber");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedAt")
|
||||||
|
.HasColumnType("datetime2")
|
||||||
|
.HasColumnName("UpdatedAt");
|
||||||
|
|
||||||
|
b.Property<string>("VDA5050CA")
|
||||||
|
.HasColumnType("nvarchar(64)")
|
||||||
|
.HasColumnName("VDA5050_CA");
|
||||||
|
|
||||||
|
b.Property<string>("VDA5050Cer")
|
||||||
|
.HasColumnType("nvarchar(64)")
|
||||||
|
.HasColumnName("VDA5050_Cer");
|
||||||
|
|
||||||
|
b.Property<bool>("VDA5050EnablePassword")
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasColumnName("VDA5050_EnablePassword");
|
||||||
|
|
||||||
|
b.Property<bool>("VDA5050EnableTls")
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasColumnName("VDA5050_EnableTls");
|
||||||
|
|
||||||
|
b.Property<string>("VDA5050HostServer")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("nvarchar(64)")
|
||||||
|
.HasColumnName("VDA5050_HostServer");
|
||||||
|
|
||||||
|
b.Property<string>("VDA5050Manufacturer")
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("nvarchar(64)")
|
||||||
|
.HasColumnName("VDA5050_Manufacturer");
|
||||||
|
|
||||||
|
b.Property<string>("VDA5050Password")
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("nvarchar(64)")
|
||||||
|
.HasColumnName("VDA5050_Password");
|
||||||
|
|
||||||
|
b.Property<int>("VDA5050Port")
|
||||||
|
.HasColumnType("int")
|
||||||
|
.HasColumnName("VDA5050_Port");
|
||||||
|
|
||||||
|
b.Property<int>("VDA5050PublishRepeat")
|
||||||
|
.HasColumnType("int")
|
||||||
|
.HasColumnName("VDA5050_PublishRepeat");
|
||||||
|
|
||||||
|
b.Property<string>("VDA5050UserName")
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("nvarchar(64)")
|
||||||
|
.HasColumnName("VDA5050_UserName");
|
||||||
|
|
||||||
|
b.Property<string>("VDA5050Version")
|
||||||
|
.HasMaxLength(20)
|
||||||
|
.HasColumnType("nvarchar(64)")
|
||||||
|
.HasColumnName("VDA5050_Version");
|
||||||
|
|
||||||
|
b.Property<string>("VDA5050_Key")
|
||||||
|
.HasColumnType("nvarchar(64)")
|
||||||
|
.HasColumnName("VDA5050_Key");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("RobotVDA5050Config");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("RobotApp.Data.ApplicationRole", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("RobotApp.Data.ApplicationUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("RobotApp.Data.ApplicationUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("RobotApp.Data.ApplicationRole", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("RobotApp.Data.ApplicationUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("RobotApp.Data.ApplicationUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace RobotApp.Data.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class UpdateVDA5050Config : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "VDA5050_CA",
|
||||||
|
table: "RobotVDA5050Config",
|
||||||
|
type: "nvarchar(64)",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "VDA5050_Cer",
|
||||||
|
table: "RobotVDA5050Config",
|
||||||
|
type: "nvarchar(64)",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "VDA5050_Key",
|
||||||
|
table: "RobotVDA5050Config",
|
||||||
|
type: "nvarchar(64)",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "VDA5050_CA",
|
||||||
|
table: "RobotVDA5050Config");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "VDA5050_Cer",
|
||||||
|
table: "RobotVDA5050Config");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "VDA5050_Key",
|
||||||
|
table: "RobotVDA5050Config");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -460,6 +460,14 @@ namespace RobotApp.Migrations
|
||||||
.HasColumnType("datetime2")
|
.HasColumnType("datetime2")
|
||||||
.HasColumnName("UpdatedAt");
|
.HasColumnName("UpdatedAt");
|
||||||
|
|
||||||
|
b.Property<string>("VDA5050CA")
|
||||||
|
.HasColumnType("nvarchar(64)")
|
||||||
|
.HasColumnName("VDA5050_CA");
|
||||||
|
|
||||||
|
b.Property<string>("VDA5050Cer")
|
||||||
|
.HasColumnType("nvarchar(64)")
|
||||||
|
.HasColumnName("VDA5050_Cer");
|
||||||
|
|
||||||
b.Property<bool>("VDA5050EnablePassword")
|
b.Property<bool>("VDA5050EnablePassword")
|
||||||
.HasColumnType("bit")
|
.HasColumnType("bit")
|
||||||
.HasColumnName("VDA5050_EnablePassword");
|
.HasColumnName("VDA5050_EnablePassword");
|
||||||
|
|
@ -501,6 +509,10 @@ namespace RobotApp.Migrations
|
||||||
.HasColumnType("nvarchar(64)")
|
.HasColumnType("nvarchar(64)")
|
||||||
.HasColumnName("VDA5050_Version");
|
.HasColumnName("VDA5050_Version");
|
||||||
|
|
||||||
|
b.Property<string>("VDA5050_Key")
|
||||||
|
.HasColumnType("nvarchar(64)")
|
||||||
|
.HasColumnName("VDA5050_Key");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("RobotVDA5050Config");
|
b.ToTable("RobotVDA5050Config");
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,15 @@ public class RobotVDA5050Config
|
||||||
[Column("VDA5050_EnableTls", TypeName = "bit")]
|
[Column("VDA5050_EnableTls", TypeName = "bit")]
|
||||||
public bool VDA5050EnableTls { get; set; }
|
public bool VDA5050EnableTls { get; set; }
|
||||||
|
|
||||||
|
[Column("VDA5050_CA", TypeName = "nvarchar(64)")]
|
||||||
|
public string VDA5050CA { get; set; }
|
||||||
|
|
||||||
|
[Column("VDA5050_Cer", TypeName = "nvarchar(64)")]
|
||||||
|
public string VDA5050Cer { get; set; }
|
||||||
|
|
||||||
|
[Column("VDA5050_Key", TypeName = "nvarchar(64)")]
|
||||||
|
public string VDA5050_Key { get; set; }
|
||||||
|
|
||||||
[Column("CreatedAt", TypeName = "datetime2")]
|
[Column("CreatedAt", TypeName = "datetime2")]
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
Loading…
Reference in New Issue
Block a user