Paralleles WebGUI mit Kestrel, Token-Sicherung und SSE-Logs implementiert
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 188 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Plattformneutral: dieselbe Anwendung laeuft unter Windows und Linux. Loest schrittweise
|
||||
@@ -11,6 +11,19 @@
|
||||
<AssemblyName>PolyTrader.App.Avalonia</AssemblyName>
|
||||
<RootNamespace>PolyTrader.App.Avalonia</RootNamespace>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<!-- Symbol der ausfuehrbaren Datei unter Windows (Explorer, Taskleiste, Alt-Tab). Wirkt nur
|
||||
beim Bauen fuer win-*: Der Apphost ist dort eine PE-Datei, in die das Symbol eingebettet
|
||||
wird. Fuer linux-x64 entsteht eine ELF-Datei ohne Symbolabschnitt - dort traegt allein
|
||||
das Fenstersymbol aus den drei Window-Dateien, das der Fenstermanager als _NET_WM_ICON
|
||||
liest.
|
||||
|
||||
ZWEI DATEIEN, EIN BILD - und das ist kein Versehen: Assets/icon.ico fuer diese Zeile,
|
||||
Assets/icon.png fuer die Fenster. Avalonia laedt ein Fenstersymbol ueber Skia, und Skia
|
||||
dekodiert kein ICO. Mit Icon="...icon.ico" startet die Anwendung anstandslos, das Fenster
|
||||
bleibt aber ohne Symbol: X11 setzt dann gar kein _NET_WM_ICON, und im Log steht nichts.
|
||||
Am 01.09.2026 auf der Linux-VM genau so gemessen (xprop: "no such atom"). Wer die PNG
|
||||
ersetzt, erzeugt sie neu aus der ICO - beide gehoeren zusammen. -->
|
||||
<ApplicationIcon>Assets\icon.ico</ApplicationIcon>
|
||||
<!-- Avalonia-Previewer und XAML-Compiler: Layout wird deklarativ in .axaml gebaut,
|
||||
nicht zur Laufzeit im Code (Layout-Regel des Projekts). -->
|
||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||
@@ -29,9 +42,6 @@
|
||||
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.3.13" />
|
||||
<!-- Diagramme (Entscheidung: LiveCharts2 statt ScottPlot, aus optischen Gruenden). -->
|
||||
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" Version="2.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -40,12 +50,22 @@
|
||||
<ProjectReference Include="..\PolyTrader.Modules.ResolutionFarming\PolyTrader.Modules.ResolutionFarming.csproj" />
|
||||
<ProjectReference Include="..\PolyTrader.Modules.Supervisor\PolyTrader.Modules.Supervisor.csproj" />
|
||||
<ProjectReference Include="..\PolyTrader.Modules.Accounting\PolyTrader.Modules.Accounting.csproj" />
|
||||
<ProjectReference Include="..\PolyTrader.Web\PolyTrader.Web.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Symbole der Oberflaeche (siehe Shell/ViewIcons.cs). Lagen bis zum WinForms-Ausbau im
|
||||
Repo-Root unter Resources/ und wurden von dort verlinkt; jetzt liegen sie im Projekt,
|
||||
wo sie hingehoeren. Der avares-Pfad "Assets/<datei>.png" bleibt dabei unveraendert. -->
|
||||
<!-- Schliesst "icon.png" mit ein - das Fenstersymbol, das die drei Window-Dateien ueber
|
||||
avares:// laden. Es muss eingebettet sein und nicht bloss neben der ausfuehrbaren Datei
|
||||
liegen, sonst faellt es weg, sobald jemand das Installationsverzeichnis aufraeumt.
|
||||
"icon.ico" ist bewusst KEINE Avalonia-Ressource: Die Datei wird nur zur Bauzeit von
|
||||
ApplicationIcon gelesen, eingebettet waere sie 190 KB tote Last im Paket. -->
|
||||
<AvaloniaResource Include="Assets\*.png" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -55,6 +75,12 @@
|
||||
<!-- D-5: vom Deploymentcenter-Installer gelesen (update-agent im Modus "install"). Gehört ins
|
||||
Publish-Verzeichnis, landet damit im Release-Paket neben der manifest.json. -->
|
||||
<None Update="setup.json" CopyToOutputDirectory="PreserveNewest" />
|
||||
<!-- Dasselbe Bild noch einmal als Datei neben der Anwendung - nicht doppelt gemoppelt:
|
||||
Der Fenstermanager unter Linux liest das Symbol fuer deploy/polytrader.desktop aus einer
|
||||
Datei und kann in kein Assembly hineinsehen. Die eingebettete Fassung (AvaloniaResource
|
||||
oben) bleibt fuer das Fenstersymbol zustaendig. -->
|
||||
<Content Include="Assets\icon.png" Link="icon.png" CopyToOutputDirectory="PreserveNewest" />
|
||||
<Content Include="..\PolyTrader.Web\wwwroot\**" Link="wwwroot\%(RecursiveDir)%(Filename)%(Extension)" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -20,6 +20,8 @@ using PolyTrader.Modules.Supervisor;
|
||||
using PolyTraderSharp;
|
||||
using PolyTraderSharp.Models;
|
||||
using PolyTraderSharp.Services;
|
||||
using PolyTrader.Web.Configuration;
|
||||
using PolyTrader.Web.Hosting;
|
||||
|
||||
namespace PolyTrader.App.Avalonia
|
||||
{
|
||||
@@ -166,6 +168,22 @@ namespace PolyTrader.App.Avalonia
|
||||
return config["Database:MySqlConnectionString"] ?? string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lädt die WebUI-Konfiguration (Port, LocalOnly, AuthToken) aus den Konfigurationsdateien.
|
||||
/// </summary>
|
||||
internal static WebUiOptions LoadWebUiOptions()
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(AppContext.BaseDirectory)
|
||||
.AddJsonFile("appsettings.json", optional: true)
|
||||
.AddJsonFile("appsettings.Local.json", optional: true)
|
||||
.Build();
|
||||
|
||||
var options = new WebUiOptions();
|
||||
config.GetSection(WebUiOptions.SectionName).Bind(options);
|
||||
return options;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Baut den Anwendungs-Host: Konfiguration, Master-Key, Persistenz, Core-Dienste und die
|
||||
/// aktiven Module. Kennt die Oberfläche nicht.
|
||||
@@ -235,6 +253,25 @@ namespace PolyTrader.App.Avalonia
|
||||
|
||||
var modules = allModules.Where(m => !disabled.Contains(m.Name)).ToList();
|
||||
|
||||
var webOptions = LoadWebUiOptions();
|
||||
if (!enforceLicense)
|
||||
{
|
||||
// Bei Konstruktionsprüfung (--smoke-ui) kein Kestrel starten
|
||||
webOptions.Enabled = false;
|
||||
}
|
||||
|
||||
if (webOptions.Enabled)
|
||||
{
|
||||
string bind = webOptions.LocalOnly ? "127.0.0.1 (nur lokal)" : "0.0.0.0 (Netzwerk/VPN)";
|
||||
logger.Info($"🌐 WebGUI aktiv auf Port {webOptions.Port} [{bind}].");
|
||||
if (string.IsNullOrWhiteSpace(webOptions.AuthToken))
|
||||
logger.Warning("⚠️ WebGUI: Kein Zugangs-Token gesetzt – Zugriff ist vollständig gesperrt.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Info("🌐 WebGUI deaktiviert (WebUi:Enabled = false).");
|
||||
}
|
||||
|
||||
return Host.CreateDefaultBuilder()
|
||||
.UseContentRoot(AppContext.BaseDirectory)
|
||||
.ConfigureAppConfiguration((_, config) =>
|
||||
@@ -242,6 +279,7 @@ namespace PolyTrader.App.Avalonia
|
||||
.ConfigureServices((context, services) =>
|
||||
{
|
||||
services.AddSingleton(dcOptions);
|
||||
services.AddSingleton(webOptions);
|
||||
var databaseOptions = new DatabaseOptions
|
||||
{
|
||||
MySqlConnectionString = context.Configuration["Database:MySqlConnectionString"] ?? string.Empty
|
||||
@@ -306,6 +344,7 @@ namespace PolyTrader.App.Avalonia
|
||||
// Shell-Zustand (Fensterverwaltung). Auch im kopflosen Betrieb harmlos.
|
||||
services.AddSingleton<AvaloniaUiHost>();
|
||||
})
|
||||
.ConfigurePolyTraderWeb(webOptions)
|
||||
.Build();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
@@ -63,7 +63,8 @@ namespace PolyTrader.App.Avalonia.Shell
|
||||
services.GetRequiredService<TerminalLogger>(),
|
||||
services.GetService<WatchdogHeartbeatService>(),
|
||||
services.GetService<MullvadVpnService>(),
|
||||
services.GetService<PolyTrader.Core.Configuration.DeploymentcenterOptions>())
|
||||
services.GetService<PolyTrader.Core.Configuration.DeploymentcenterOptions>(),
|
||||
services.GetService<PolyTrader.Web.Configuration.WebUiOptions>())
|
||||
});
|
||||
|
||||
host.RegisterView(new ModuleView
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="PolyTrader.App.Avalonia.Views.DialogWindow"
|
||||
Icon="avares://PolyTrader.App.Avalonia/Assets/icon.png"
|
||||
Width="520" SizeToContent="Height"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
CanResize="False"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:PolyTrader.App.Avalonia.Controls"
|
||||
xmlns:models="using:PolyTraderSharp.Models"
|
||||
@@ -70,6 +70,64 @@
|
||||
</DockPanel>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="WebUI">
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Margin="24,20" MaxWidth="680" HorizontalAlignment="Left" Spacing="16">
|
||||
<TextBlock Text="WebUI Konfiguration & Fernzugriff" FontSize="18" FontWeight="SemiBold" />
|
||||
<TextBlock Text="Das WebUI ermöglicht die Steuerung und Überwachung von PolyTrader über einen Browser – parallel zum Desktop GUI oder im kopflosen Server-Betrieb."
|
||||
Foreground="{DynamicResource AppMutedTextBrush}" TextWrapping="Wrap" />
|
||||
|
||||
<Border Background="{DynamicResource AppSurfaceBrush}" BorderBrush="{DynamicResource AppBorderBrush}" BorderThickness="1" CornerRadius="8" Padding="16">
|
||||
<StackPanel Spacing="12">
|
||||
<TextBlock Text="Server-Status" FontWeight="SemiBold" FontSize="14" />
|
||||
<TextBlock Name="lblWebUiStatus" Text="Status wird ermittelt …" Foreground="{DynamicResource AppAccentBrush}" />
|
||||
<TextBlock Name="lblWebUiUrl" Text="http://127.0.0.1:5001" Foreground="{DynamicResource AppMutedTextBrush}" FontSize="12" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Background="{DynamicResource AppSurfaceBrush}" BorderBrush="{DynamicResource AppBorderBrush}" BorderThickness="1" CornerRadius="8" Padding="16">
|
||||
<StackPanel Spacing="16">
|
||||
<TextBlock Text="Netzwerk & Port" FontWeight="SemiBold" FontSize="14" />
|
||||
|
||||
<CheckBox Name="chkWebUiEnabled" Content="WebUI Server aktivieren" />
|
||||
|
||||
<Grid ColumnDefinitions="140,*" Margin="0,4">
|
||||
<TextBlock Grid.Column="0" Text="Port:" VerticalAlignment="Center" />
|
||||
<NumericUpDown Name="numWebUiPort" Grid.Column="1" Minimum="1024" Maximum="65535" Value="5001" Width="150" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
|
||||
<CheckBox Name="chkWebUiLocalOnly" Content="Nur lokaler Zugriff (127.0.0.1)" />
|
||||
<TextBlock Text="Wenn deaktiviert, lauscht der Server auf 0.0.0.0 und ist über LAN/VPN erreichbar."
|
||||
Foreground="{DynamicResource AppMutedTextBrush}" FontSize="12" Margin="24,-8,0,0" TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Background="{DynamicResource AppSurfaceBrush}" BorderBrush="{DynamicResource AppBorderBrush}" BorderThickness="1" CornerRadius="8" Padding="16">
|
||||
<StackPanel Spacing="12">
|
||||
<TextBlock Text="Zugangssicherung (Token)" FontWeight="SemiBold" FontSize="14" />
|
||||
<TextBlock Text="Ohne gültiges Token verweigert das WebUI jeden Zugriff. Das Token wird in appsettings.Local.json gespeichert."
|
||||
Foreground="{DynamicResource AppMutedTextBrush}" FontSize="12" TextWrapping="Wrap" />
|
||||
|
||||
<Grid ColumnDefinitions="*,Auto,Auto" Margin="0,6">
|
||||
<TextBox Name="txtWebUiToken" Grid.Column="0" PasswordChar="●" FontFamily="Consolas,monospace" FontSize="12" VerticalAlignment="Center" Margin="0,0,8,0" />
|
||||
<Button Name="btnWebUiToggleShowToken" Grid.Column="1" Content="Anzeigen" Margin="0,0,8,0" />
|
||||
<Button Name="btnWebUiCopyToken" Grid.Column="2" Content="Kopieren" />
|
||||
</Grid>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="10" Margin="0,4,0,0">
|
||||
<Button Name="btnWebUiGenToken" Content="Neuen Token generieren" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="12" Margin="0,8,0,0">
|
||||
<Button Name="btnSaveWebUi" Content="WebUI-Einstellungen speichern" />
|
||||
<TextBlock Name="lblWebUiSaveStatus" Text="" VerticalAlignment="Center" Foreground="{DynamicResource AppPositiveBrush}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
</TabControl>
|
||||
</DockPanel>
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ using PolyTrader.Core.Security;
|
||||
using PolyTraderSharp;
|
||||
using PolyTraderSharp.Models;
|
||||
using PolyTraderSharp.Services;
|
||||
using PolyTrader.Web.Configuration;
|
||||
|
||||
namespace PolyTrader.App.Avalonia.Views
|
||||
{
|
||||
@@ -36,12 +37,14 @@ namespace PolyTrader.App.Avalonia.Views
|
||||
private MullvadVpnService? _vpn;
|
||||
private TerminalLogger? _logger;
|
||||
private DeploymentcenterOptions? _dcOptions;
|
||||
private WebUiOptions _webOptions = new();
|
||||
|
||||
public SettingsWindow() => AvaloniaXamlLoader.Load(this);
|
||||
|
||||
public SettingsWindow(IModuleUiHost host, IAccountRepository accountRepo, TradingState state,
|
||||
TerminalLogger logger, WatchdogHeartbeatService? watchdog = null,
|
||||
MullvadVpnService? vpn = null, DeploymentcenterOptions? dcOptions = null) : this()
|
||||
MullvadVpnService? vpn = null, DeploymentcenterOptions? dcOptions = null,
|
||||
WebUiOptions? webOptions = null) : this()
|
||||
{
|
||||
_accountRepo = accountRepo;
|
||||
_state = state;
|
||||
@@ -49,6 +52,7 @@ namespace PolyTrader.App.Avalonia.Views
|
||||
_watchdog = watchdog;
|
||||
_vpn = vpn;
|
||||
_dcOptions = dcOptions;
|
||||
_webOptions = webOptions ?? Program.LoadWebUiOptions();
|
||||
|
||||
var grid = this.FindControl<DataGrid>("gridAccounts")!;
|
||||
grid.ItemsSource = _accounts;
|
||||
@@ -68,8 +72,14 @@ namespace PolyTrader.App.Avalonia.Views
|
||||
this.FindControl<Button>("btnAccDelete")!.Click += async (_, _) => await DeleteAccountAsync();
|
||||
this.FindControl<Button>("btnAccSave")!.Click += (_, _) => SaveSelectedAccount();
|
||||
|
||||
this.FindControl<Button>("btnWebUiGenToken")!.Click += (_, _) => GenerateWebUiToken();
|
||||
this.FindControl<Button>("btnWebUiToggleShowToken")!.Click += (_, _) => ToggleWebUiTokenVisibility();
|
||||
this.FindControl<Button>("btnWebUiCopyToken")!.Click += async (_, _) => await CopyWebUiTokenAsync();
|
||||
this.FindControl<Button>("btnSaveWebUi")!.Click += (_, _) => SaveWebUiSettings();
|
||||
|
||||
ReloadServerSettings();
|
||||
LoadAccounts();
|
||||
LoadWebUiSettings();
|
||||
UpdateMasterKeyButtonState();
|
||||
}
|
||||
|
||||
@@ -422,5 +432,98 @@ namespace PolyTrader.App.Avalonia.Views
|
||||
btn.IsEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== WebUI-Einstellungen =====
|
||||
|
||||
private void LoadWebUiSettings()
|
||||
{
|
||||
_webOptions = Program.LoadWebUiOptions();
|
||||
var chkEnabled = this.FindControl<CheckBox>("chkWebUiEnabled")!;
|
||||
var numPort = this.FindControl<NumericUpDown>("numWebUiPort")!;
|
||||
var chkLocal = this.FindControl<CheckBox>("chkWebUiLocalOnly")!;
|
||||
var txtToken = this.FindControl<TextBox>("txtWebUiToken")!;
|
||||
var lblStatus = this.FindControl<TextBlock>("lblWebUiStatus")!;
|
||||
var lblUrl = this.FindControl<TextBlock>("lblWebUiUrl")!;
|
||||
|
||||
chkEnabled.IsChecked = _webOptions.Enabled;
|
||||
numPort.Value = _webOptions.Port;
|
||||
chkLocal.IsChecked = _webOptions.LocalOnly;
|
||||
txtToken.Text = _webOptions.AuthToken ?? string.Empty;
|
||||
|
||||
if (_webOptions.Enabled)
|
||||
{
|
||||
string ip = _webOptions.LocalOnly ? "127.0.0.1" : "0.0.0.0";
|
||||
lblStatus.Text = $"Aktiv (lauscht auf {ip}:{_webOptions.Port})";
|
||||
lblUrl.Text = $"http://{(_webOptions.LocalOnly ? "localhost" : "0.0.0.0")}:{_webOptions.Port}";
|
||||
}
|
||||
else
|
||||
{
|
||||
lblStatus.Text = "Deaktiviert (WebUi:Enabled = false)";
|
||||
lblUrl.Text = "—";
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateWebUiToken()
|
||||
{
|
||||
string newToken = WebUiConfigManager.GenerateSecureToken();
|
||||
var txtToken = this.FindControl<TextBox>("txtWebUiToken")!;
|
||||
txtToken.Text = newToken;
|
||||
_webOptions.AuthToken = newToken;
|
||||
WebUiConfigManager.SaveToLocalSettings(_webOptions);
|
||||
_logger?.Info("🔐 WebUI: Neues Zugangs-Token im Einstellungsfenster generiert und gespeichert.");
|
||||
SetWebUiSaveStatus("Neues Token generiert & gespeichert.");
|
||||
}
|
||||
|
||||
private void ToggleWebUiTokenVisibility()
|
||||
{
|
||||
var txt = this.FindControl<TextBox>("txtWebUiToken")!;
|
||||
var btn = this.FindControl<Button>("btnWebUiToggleShowToken")!;
|
||||
if (txt.PasswordChar == '●')
|
||||
{
|
||||
txt.PasswordChar = '\0';
|
||||
btn.Content = "Ausblenden";
|
||||
}
|
||||
else
|
||||
{
|
||||
txt.PasswordChar = '●';
|
||||
btn.Content = "Anzeigen";
|
||||
}
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task CopyWebUiTokenAsync()
|
||||
{
|
||||
var txt = this.FindControl<TextBox>("txtWebUiToken")!;
|
||||
if (string.IsNullOrEmpty(txt.Text)) return;
|
||||
var topLevel = TopLevel.GetTopLevel(this);
|
||||
if (topLevel?.Clipboard != null)
|
||||
{
|
||||
await topLevel.Clipboard.SetTextAsync(txt.Text);
|
||||
SetWebUiSaveStatus("Token in Zwischenablage kopiert.");
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveWebUiSettings()
|
||||
{
|
||||
var chkEnabled = this.FindControl<CheckBox>("chkWebUiEnabled")!;
|
||||
var numPort = this.FindControl<NumericUpDown>("numWebUiPort")!;
|
||||
var chkLocal = this.FindControl<CheckBox>("chkWebUiLocalOnly")!;
|
||||
var txtToken = this.FindControl<TextBox>("txtWebUiToken")!;
|
||||
|
||||
_webOptions.Enabled = chkEnabled.IsChecked ?? true;
|
||||
_webOptions.Port = (int)(numPort.Value ?? 5001);
|
||||
_webOptions.LocalOnly = chkLocal.IsChecked ?? true;
|
||||
_webOptions.AuthToken = txtToken.Text?.Trim() ?? string.Empty;
|
||||
|
||||
WebUiConfigManager.SaveToLocalSettings(_webOptions);
|
||||
_logger?.Info($"WebUI-Einstellungen in appsettings.Local.json gespeichert (Port {_webOptions.Port}, LocalOnly: {_webOptions.LocalOnly}).");
|
||||
SetWebUiSaveStatus("Gespeichert in appsettings.Local.json (Port-/Netzwerkänderungen greifen nach Neustart).");
|
||||
LoadWebUiSettings();
|
||||
}
|
||||
|
||||
private void SetWebUiSaveStatus(string msg)
|
||||
{
|
||||
var lbl = this.FindControl<TextBlock>("lblWebUiSaveStatus")!;
|
||||
lbl.Text = $"✓ {msg}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
x:Class="PolyTrader.App.Avalonia.Views.ShellWindow"
|
||||
x:DataType="shell:ShellNavModel"
|
||||
Title="PolyTrader"
|
||||
Icon="avares://PolyTrader.App.Avalonia/Assets/icon.png"
|
||||
Width="1600" Height="900"
|
||||
WindowState="Maximized">
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="PolyTrader.App.Avalonia.Views.ShutdownConfirmWindow"
|
||||
Title="PolyTrader beenden"
|
||||
Icon="avares://PolyTrader.App.Avalonia/Assets/icon.png"
|
||||
Width="480" SizeToContent="Height"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
CanResize="False"
|
||||
|
||||
@@ -23,5 +23,12 @@
|
||||
"Microsoft.EntityFrameworkCore": "Warning",
|
||||
"Microsoft.EntityFrameworkCore.Database.Command": "Warning"
|
||||
}
|
||||
},
|
||||
"WebUi": {
|
||||
"_comment": "Port (Standard 5001), LocalOnly (Standard true = nur 127.0.0.1). AuthToken liegt in appsettings.Local.json.",
|
||||
"Enabled": true,
|
||||
"Port": 5001,
|
||||
"LocalOnly": true,
|
||||
"AuthToken": ""
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user