452 lines
18 KiB
Plaintext
452 lines
18 KiB
Plaintext
@page "/standorte"
|
|
@using Microsoft.EntityFrameworkCore
|
|
@using TrafagSalesExporter.Data
|
|
@using TrafagSalesExporter.Services
|
|
@inject IDbContextFactory<AppDbContext> DbFactory
|
|
@inject IHanaQueryService HanaService
|
|
@inject ISnackbar Snackbar
|
|
@inject IDialogService DialogService
|
|
|
|
<PageTitle>Standorte</PageTitle>
|
|
|
|
<MudText Typo="Typo.h4" Class="mb-4">Standorte</MudText>
|
|
|
|
<MudText Typo="Typo.h5" Class="mb-2">HANA Server</MudText>
|
|
<MudPaper Class="pa-4 mb-6" Elevation="1">
|
|
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Add"
|
|
OnClick="AddServer" Class="mb-3">
|
|
Server hinzufügen
|
|
</MudButton>
|
|
|
|
<MudTable Items="_servers" Dense Hover Striped>
|
|
<HeaderContent>
|
|
<MudTh>Name</MudTh>
|
|
<MudTh>Host</MudTh>
|
|
<MudTh>Port</MudTh>
|
|
<MudTh>Username</MudTh>
|
|
<MudTh>Verbindungsstatus</MudTh>
|
|
<MudTh>Aktionen</MudTh>
|
|
</HeaderContent>
|
|
<RowTemplate>
|
|
<MudTd>@context.Name</MudTd>
|
|
<MudTd>@context.Host</MudTd>
|
|
<MudTd>@context.Port</MudTd>
|
|
<MudTd>@context.Username</MudTd>
|
|
<MudTd>
|
|
@if (_connectionStatus.TryGetValue(context.Id, out var status))
|
|
{
|
|
<MudTooltip Text="@BuildStatusTooltip(status)">
|
|
<MudChip T="string" Color="@(status.Success ? Color.Success : Color.Error)" Variant="Variant.Filled" Size="Size.Small">
|
|
@(status.Success ? "OK" : "Fehler") - @status.Stage
|
|
</MudChip>
|
|
</MudTooltip>
|
|
}
|
|
else
|
|
{
|
|
<MudChip T="string" Color="Color.Default" Variant="Variant.Outlined" Size="Size.Small">Nicht getestet</MudChip>
|
|
}
|
|
</MudTd>
|
|
<MudTd>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Edit" Size="Size.Small"
|
|
OnClick="() => EditServer(context)" />
|
|
<MudIconButton Icon="@Icons.Material.Filled.NetworkCheck" Size="Size.Small" Color="Color.Info"
|
|
OnClick="() => TestServerConnection(context)" />
|
|
<MudIconButton Icon="@Icons.Material.Filled.Delete" Size="Size.Small" Color="Color.Error"
|
|
OnClick="() => DeleteServer(context)" />
|
|
</MudTd>
|
|
</RowTemplate>
|
|
</MudTable>
|
|
</MudPaper>
|
|
|
|
<MudText Typo="Typo.h5" Class="mb-2">Standorte (Sites)</MudText>
|
|
<MudPaper Class="pa-4" Elevation="1">
|
|
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Add"
|
|
OnClick="AddSite" Class="mb-3">
|
|
Neuen Standort hinzufügen
|
|
</MudButton>
|
|
|
|
<MudTable Items="_sites" Dense Hover Striped>
|
|
<HeaderContent>
|
|
<MudTh>Land</MudTh>
|
|
<MudTh>TSC</MudTh>
|
|
<MudTh>Schema</MudTh>
|
|
<MudTh>Quellsystem</MudTh>
|
|
<MudTh>Host</MudTh>
|
|
<MudTh>Aktiv</MudTh>
|
|
<MudTh>Aktionen</MudTh>
|
|
</HeaderContent>
|
|
<RowTemplate>
|
|
<MudTd>@context.Land</MudTd>
|
|
<MudTd>@context.TSC</MudTd>
|
|
<MudTd>@context.Schema</MudTd>
|
|
<MudTd>@context.SourceSystem</MudTd>
|
|
<MudTd>@GetServerNode(context.HanaServer)</MudTd>
|
|
<MudTd>
|
|
@if (context.IsActive)
|
|
{
|
|
<MudIcon Icon="@Icons.Material.Filled.CheckCircle" Color="Color.Success" Size="Size.Small" />
|
|
}
|
|
else
|
|
{
|
|
<MudIcon Icon="@Icons.Material.Filled.Cancel" Color="Color.Default" Size="Size.Small" />
|
|
}
|
|
</MudTd>
|
|
<MudTd>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Edit" Size="Size.Small"
|
|
OnClick="() => EditSite(context)" />
|
|
<MudIconButton Icon="@Icons.Material.Filled.Delete" Size="Size.Small" Color="Color.Error"
|
|
OnClick="() => DeleteSite(context)" />
|
|
</MudTd>
|
|
</RowTemplate>
|
|
</MudTable>
|
|
</MudPaper>
|
|
|
|
<MudDialog @bind-Visible="_serverDialogVisible" Options="_dialogOptions">
|
|
<TitleContent>
|
|
<MudText Typo="Typo.h6">@(_editingServer.Id == 0 ? "Server hinzufügen" : "Server bearbeiten")</MudText>
|
|
</TitleContent>
|
|
<DialogContent>
|
|
<MudTextField @bind-Value="_editingServer.Name" Label="Name" Required />
|
|
<MudTextField @bind-Value="_editingServer.Host" Label="Host" Required
|
|
HelperText="IP oder Hostname (ohne Protokoll)" />
|
|
<MudNumericField @bind-Value="_editingServer.Port" Label="Port"
|
|
HelperText="Typisch 30015 (Tenant), 30013 (SystemDB), 3xx15 für Instanz xx" />
|
|
<MudTextField @bind-Value="_editingServer.Username" Label="Username" />
|
|
<MudTextField @bind-Value="_editingServer.Password" Label="Password" InputType="InputType.Password" />
|
|
<MudTextField @bind-Value="_editingServer.DatabaseName" Label="Database Name (MDC)"
|
|
HelperText="Nur bei Multi-Tenant Setup angeben, sonst leer lassen" />
|
|
<MudSwitch @bind-Value="_editingServer.UseSsl" Label="SSL/TLS verwenden (encrypt=true)" Color="Color.Primary" />
|
|
<MudSwitch @bind-Value="_editingServer.ValidateCertificate" Label="SSL-Zertifikat validieren" Color="Color.Primary"
|
|
Disabled="!_editingServer.UseSsl" />
|
|
<MudTextField @bind-Value="_editingServer.AdditionalParams" Label="Zusätzliche Parameter"
|
|
HelperText="Optional, z.B. sslCryptoProvider=openssl;communicationTimeout=0" />
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<MudButton OnClick="() => _serverDialogVisible = false">Abbrechen</MudButton>
|
|
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="SaveServer">Speichern</MudButton>
|
|
</DialogActions>
|
|
</MudDialog>
|
|
|
|
<MudDialog @bind-Visible="_siteDialogVisible" Options="_dialogOptions">
|
|
<TitleContent>
|
|
<MudText Typo="Typo.h6">@(_editingSite.Id == 0 ? "Standort hinzufügen" : "Standort bearbeiten")</MudText>
|
|
</TitleContent>
|
|
<DialogContent>
|
|
<MudTextField @bind-Value="_editingSite.Schema" Label="Schema" Required />
|
|
<MudTextField @bind-Value="_editingSite.TSC" Label="TSC" Required />
|
|
<MudTextField @bind-Value="_editingSite.Land" Label="Land" Required />
|
|
<MudSelect @bind-Value="_editingSite.SourceSystem" Label="Quellsystem" Required>
|
|
@foreach (var system in _sourceSystems)
|
|
{
|
|
<MudSelectItem Value="system">@system</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
<MudCheckBox @bind-Value="_editingSite.IsActive" Label="Aktiv" />
|
|
|
|
<MudDivider Class="my-4" />
|
|
|
|
<MudText Typo="Typo.h6" Class="mb-2">HANA-Verbindung</MudText>
|
|
<MudTextField @bind-Value="_editingSiteServer.Name" Label="Verbindungsname" Required
|
|
HelperText="Interner Anzeigename für diesen Standort" />
|
|
<MudTextField @bind-Value="_editingSiteServer.Host" Label="Host oder ServerNode" Required
|
|
HelperText="z.B. hana01 oder hana01:30015 oder derselbe HanaServer-Wert wie in Power BI" />
|
|
<MudNumericField @bind-Value="_editingSiteServer.Port" Label="Port"
|
|
HelperText="Wird ignoriert, wenn im Host bereits ein Port enthalten ist" />
|
|
<MudTextField @bind-Value="_editingSiteServer.Username" Label="Username" />
|
|
<MudTextField @bind-Value="_editingSiteServer.Password" Label="Password" InputType="InputType.Password" />
|
|
<MudTextField @bind-Value="_editingSiteServer.DatabaseName" Label="Database Name (MDC)"
|
|
HelperText="Nur bei Multi-Tenant Setup angeben, sonst leer lassen" />
|
|
<MudSwitch @bind-Value="_editingSiteServer.UseSsl" Label="SSL/TLS verwenden (encrypt=true)" Color="Color.Primary" />
|
|
<MudSwitch @bind-Value="_editingSiteServer.ValidateCertificate" Label="SSL-Zertifikat validieren" Color="Color.Primary"
|
|
Disabled="!_editingSiteServer.UseSsl" />
|
|
<MudTextField @bind-Value="_editingSiteServer.AdditionalParams" Label="Zusätzliche Parameter"
|
|
HelperText="Optional, z.B. sslCryptoProvider=openssl;communicationTimeout=0" />
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<MudButton OnClick="() => _siteDialogVisible = false">Abbrechen</MudButton>
|
|
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="SaveSite">Speichern</MudButton>
|
|
</DialogActions>
|
|
</MudDialog>
|
|
|
|
@code {
|
|
private readonly string[] _sourceSystems = ["SAP", "BI1", "SAGE"];
|
|
private readonly Dictionary<int, ConnectionTestResult> _connectionStatus = new();
|
|
private List<HanaServer> _servers = new();
|
|
private List<Site> _sites = new();
|
|
private HanaServer _editingServer = new();
|
|
private Site _editingSite = new();
|
|
private HanaServer _editingSiteServer = new();
|
|
private bool _serverDialogVisible;
|
|
private bool _siteDialogVisible;
|
|
private readonly DialogOptions _dialogOptions = new() { MaxWidth = MaxWidth.Small, FullWidth = true };
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
await LoadDataAsync();
|
|
}
|
|
|
|
private async Task LoadDataAsync()
|
|
{
|
|
using var db = await DbFactory.CreateDbContextAsync();
|
|
_servers = await db.HanaServers.OrderBy(s => s.Name).ToListAsync();
|
|
_sites = await db.Sites.Include(s => s.HanaServer).OrderBy(s => s.Land).ToListAsync();
|
|
}
|
|
|
|
private void AddServer()
|
|
{
|
|
_editingServer = new HanaServer { Port = 30015 };
|
|
_serverDialogVisible = true;
|
|
}
|
|
|
|
private void EditServer(HanaServer server)
|
|
{
|
|
_editingServer = CloneServer(server);
|
|
_serverDialogVisible = true;
|
|
}
|
|
|
|
private async Task SaveServer()
|
|
{
|
|
using var db = await DbFactory.CreateDbContextAsync();
|
|
if (_editingServer.Id == 0)
|
|
{
|
|
db.HanaServers.Add(_editingServer);
|
|
}
|
|
else
|
|
{
|
|
var existing = await db.HanaServers.FindAsync(_editingServer.Id);
|
|
if (existing is not null)
|
|
{
|
|
existing.Name = _editingServer.Name;
|
|
existing.Host = _editingServer.Host;
|
|
existing.Port = _editingServer.Port;
|
|
existing.Username = _editingServer.Username;
|
|
existing.Password = _editingServer.Password;
|
|
existing.DatabaseName = _editingServer.DatabaseName;
|
|
existing.UseSsl = _editingServer.UseSsl;
|
|
existing.ValidateCertificate = _editingServer.ValidateCertificate;
|
|
existing.AdditionalParams = _editingServer.AdditionalParams;
|
|
}
|
|
}
|
|
|
|
await db.SaveChangesAsync();
|
|
_serverDialogVisible = false;
|
|
await LoadDataAsync();
|
|
Snackbar.Add("Server gespeichert", Severity.Success);
|
|
}
|
|
|
|
private async Task DeleteServer(HanaServer server)
|
|
{
|
|
var result = await DialogService.ShowMessageBox(
|
|
"Server löschen",
|
|
$"Server '{server.Name}' wirklich löschen?",
|
|
yesText: "Löschen", cancelText: "Abbrechen");
|
|
|
|
if (result != true) return;
|
|
|
|
using var db = await DbFactory.CreateDbContextAsync();
|
|
var entity = await db.HanaServers.FindAsync(server.Id);
|
|
if (entity is not null)
|
|
{
|
|
db.HanaServers.Remove(entity);
|
|
await db.SaveChangesAsync();
|
|
}
|
|
|
|
await LoadDataAsync();
|
|
Snackbar.Add("Server gelöscht", Severity.Info);
|
|
}
|
|
|
|
private async Task TestServerConnection(HanaServer server)
|
|
{
|
|
var result = await Task.Run(() => HanaService.TestConnectionDetailed(server));
|
|
_connectionStatus[server.Id] = result;
|
|
|
|
if (result.Success)
|
|
{
|
|
Snackbar.Add($"Verbindung zu '{server.Name}' erfolgreich.", Severity.Success);
|
|
}
|
|
else
|
|
{
|
|
Snackbar.Add($"{server.Name}: {result.ExceptionType} - {result.ErrorMessage}", Severity.Error);
|
|
}
|
|
}
|
|
|
|
private static string BuildStatusTooltip(ConnectionTestResult status)
|
|
{
|
|
var stamp = status.TestedAtUtc.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss");
|
|
if (status.Success)
|
|
return $"Letzter Test: {stamp}\nStage: {status.Stage}\n{status.ConnectionStringPreview}";
|
|
|
|
return $"Letzter Test: {stamp}\nStage: {status.Stage}\nFehler: {status.ErrorMessage}\n{status.ConnectionStringPreview}";
|
|
}
|
|
|
|
private void AddSite()
|
|
{
|
|
_editingSite = new Site
|
|
{
|
|
IsActive = true,
|
|
SourceSystem = "SAP",
|
|
HanaServerId = 0
|
|
};
|
|
_editingSiteServer = CreateDefaultSiteServer();
|
|
_siteDialogVisible = true;
|
|
}
|
|
|
|
private void EditSite(Site site)
|
|
{
|
|
_editingSite = new Site
|
|
{
|
|
Id = site.Id,
|
|
HanaServerId = site.HanaServerId,
|
|
Schema = site.Schema,
|
|
TSC = site.TSC,
|
|
Land = site.Land,
|
|
SourceSystem = string.IsNullOrWhiteSpace(site.SourceSystem) ? "SAP" : site.SourceSystem,
|
|
IsActive = site.IsActive
|
|
};
|
|
_editingSiteServer = site.HanaServer is null
|
|
? CreateDefaultSiteServer(site)
|
|
: CloneServer(site.HanaServer);
|
|
_siteDialogVisible = true;
|
|
}
|
|
|
|
private async Task SaveSite()
|
|
{
|
|
using var db = await DbFactory.CreateDbContextAsync();
|
|
var serverId = await SaveOrCreateSiteServerAsync(db);
|
|
|
|
if (_editingSite.Id == 0)
|
|
{
|
|
_editingSite.HanaServerId = serverId;
|
|
db.Sites.Add(_editingSite);
|
|
}
|
|
else
|
|
{
|
|
var existing = await db.Sites.FindAsync(_editingSite.Id);
|
|
if (existing is not null)
|
|
{
|
|
existing.HanaServerId = serverId;
|
|
existing.Schema = _editingSite.Schema;
|
|
existing.TSC = _editingSite.TSC;
|
|
existing.Land = _editingSite.Land;
|
|
existing.SourceSystem = _editingSite.SourceSystem;
|
|
existing.IsActive = _editingSite.IsActive;
|
|
}
|
|
}
|
|
|
|
await db.SaveChangesAsync();
|
|
_siteDialogVisible = false;
|
|
await LoadDataAsync();
|
|
Snackbar.Add("Standort gespeichert", Severity.Success);
|
|
}
|
|
|
|
private async Task DeleteSite(Site site)
|
|
{
|
|
var result = await DialogService.ShowMessageBox(
|
|
"Standort löschen",
|
|
$"Standort '{site.Land}' wirklich löschen?",
|
|
yesText: "Löschen", cancelText: "Abbrechen");
|
|
|
|
if (result != true) return;
|
|
|
|
using var db = await DbFactory.CreateDbContextAsync();
|
|
var entity = await db.Sites.FindAsync(site.Id);
|
|
if (entity is not null)
|
|
{
|
|
db.Sites.Remove(entity);
|
|
await db.SaveChangesAsync();
|
|
}
|
|
|
|
await LoadDataAsync();
|
|
Snackbar.Add("Standort gelöscht", Severity.Info);
|
|
}
|
|
|
|
private static string GetServerNode(HanaServer? server)
|
|
{
|
|
if (server is null || string.IsNullOrWhiteSpace(server.Host))
|
|
return "-";
|
|
|
|
return server.Host.Contains(':', StringComparison.Ordinal) ? server.Host : $"{server.Host}:{server.Port}";
|
|
}
|
|
|
|
private HanaServer CreateDefaultSiteServer(Site? site = null)
|
|
{
|
|
var label = !string.IsNullOrWhiteSpace(site?.Land) ? site!.Land : site?.TSC;
|
|
if (string.IsNullOrWhiteSpace(label))
|
|
label = "Neuer Standort";
|
|
|
|
return new HanaServer
|
|
{
|
|
Name = $"{label} HANA",
|
|
Port = 30015
|
|
};
|
|
}
|
|
|
|
private static HanaServer CloneServer(HanaServer server)
|
|
{
|
|
return new HanaServer
|
|
{
|
|
Id = server.Id,
|
|
Name = server.Name,
|
|
Host = server.Host,
|
|
Port = server.Port,
|
|
Username = server.Username,
|
|
Password = server.Password,
|
|
DatabaseName = server.DatabaseName,
|
|
UseSsl = server.UseSsl,
|
|
ValidateCertificate = server.ValidateCertificate,
|
|
AdditionalParams = server.AdditionalParams
|
|
};
|
|
}
|
|
|
|
private async Task<int> SaveOrCreateSiteServerAsync(AppDbContext db)
|
|
{
|
|
_editingSiteServer.Name = string.IsNullOrWhiteSpace(_editingSiteServer.Name)
|
|
? $"{_editingSite.Land} HANA".Trim()
|
|
: _editingSiteServer.Name.Trim();
|
|
_editingSiteServer.Host = _editingSiteServer.Host.Trim();
|
|
_editingSiteServer.Username = _editingSiteServer.Username.Trim();
|
|
_editingSiteServer.DatabaseName = _editingSiteServer.DatabaseName.Trim();
|
|
_editingSiteServer.AdditionalParams = _editingSiteServer.AdditionalParams.Trim();
|
|
|
|
if (string.IsNullOrWhiteSpace(_editingSiteServer.Host))
|
|
throw new InvalidOperationException("Host oder ServerNode muss gesetzt sein.");
|
|
|
|
if (_editingSite.HanaServerId == 0)
|
|
{
|
|
db.HanaServers.Add(_editingSiteServer);
|
|
await db.SaveChangesAsync();
|
|
return _editingSiteServer.Id;
|
|
}
|
|
|
|
var sharedUseCount = await db.Sites.CountAsync(s => s.HanaServerId == _editingSite.HanaServerId && s.Id != _editingSite.Id);
|
|
if (sharedUseCount > 0)
|
|
{
|
|
var dedicatedServer = CloneServer(_editingSiteServer);
|
|
dedicatedServer.Id = 0;
|
|
db.HanaServers.Add(dedicatedServer);
|
|
await db.SaveChangesAsync();
|
|
return dedicatedServer.Id;
|
|
}
|
|
|
|
var existingServer = await db.HanaServers.FindAsync(_editingSite.HanaServerId);
|
|
if (existingServer is null)
|
|
{
|
|
db.HanaServers.Add(_editingSiteServer);
|
|
await db.SaveChangesAsync();
|
|
return _editingSiteServer.Id;
|
|
}
|
|
|
|
existingServer.Name = _editingSiteServer.Name;
|
|
existingServer.Host = _editingSiteServer.Host;
|
|
existingServer.Port = _editingSiteServer.Port;
|
|
existingServer.Username = _editingSiteServer.Username;
|
|
existingServer.Password = _editingSiteServer.Password;
|
|
existingServer.DatabaseName = _editingSiteServer.DatabaseName;
|
|
existingServer.UseSsl = _editingSiteServer.UseSsl;
|
|
existingServer.ValidateCertificate = _editingSiteServer.ValidateCertificate;
|
|
existingServer.AdditionalParams = _editingSiteServer.AdditionalParams;
|
|
await db.SaveChangesAsync();
|
|
return existingServer.Id;
|
|
}
|
|
}
|