UI Slice 2: Settings-Fenster Scaling-Fix + OpenRouter-Key konfigurierbar

Scaling-Bug behoben (war 'teilweise unbenutzbar'):
- General Settings: toolStrip2 war NICHT gedockt (floatete), propertyGrid war Dock=Bottom mit
  fixer Hoehe -> jetzt toolStrip2 Dock=Top, propertyGrid Dock=Fill (Controls-Reihenfolge korrigiert).
- Accounts: toolStripAccounts Dock=Top (war floatend); Grid Left + PropertyGrid Fill bleiben.
- Form: tabControl1 Dock=Fill statt Anchor mit falscher Groesse; leere toolStrip1 entfernt;
  ueberhohe ClientSize (1523) korrigiert. Skaliert jetzt sauber mit der Fenstergroesse.

Fehlende Einstellung ergaenzt:
- Button 'OpenRouter-Key setzen …' (General Settings, via Designer): maskierte Eingabe, schreibt
  in die gitignorierte openrouter.key (genau das liest der OpenRouterClient) - KEIN Secret im
  Klartext in server_settings.xml. Leer = entfernen. Hinweis auf Spend-Limit.

Build 0 Fehler, --smoke-ui gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-07-20 20:54:44 +02:00
co-authored by Claude Opus 4.8
parent 0725a81dbd
commit 936144c318
2 changed files with 90 additions and 26 deletions
+19 -22
View File
@@ -18,13 +18,13 @@ namespace PolyTraderSharp.Ui.Views
private void InitializeComponent() private void InitializeComponent()
{ {
propertyGrid = new PropertyGrid(); propertyGrid = new PropertyGrid();
toolStrip1 = new ToolStrip();
tabControl1 = new TabControl(); tabControl1 = new TabControl();
tabPage1 = new TabPage(); tabPage1 = new TabPage();
toolStrip2 = new ToolStrip(); toolStrip2 = new ToolStrip();
btn_save = new ToolStripButton(); btn_save = new ToolStripButton();
btn_loadsettings = new ToolStripButton(); btn_loadsettings = new ToolStripButton();
btnGenMasterKey = new ToolStripButton(); btnGenMasterKey = new ToolStripButton();
btnSetOpenRouterKey = new ToolStripButton();
tabPage2 = new TabPage(); tabPage2 = new TabPage();
pgAccount = new PropertyGrid(); pgAccount = new PropertyGrid();
dgvAccounts = new DataGridView(); dgvAccounts = new DataGridView();
@@ -41,37 +41,25 @@ namespace PolyTraderSharp.Ui.Views
// //
// propertyGrid // propertyGrid
// //
propertyGrid.Dock = DockStyle.Bottom; propertyGrid.Dock = DockStyle.Fill;
propertyGrid.Location = new Point(3, 610);
propertyGrid.Margin = new Padding(4, 25, 4, 5);
propertyGrid.Name = "propertyGrid"; propertyGrid.Name = "propertyGrid";
propertyGrid.Size = new Size(1171, 274);
propertyGrid.TabIndex = 1; propertyGrid.TabIndex = 1;
// //
// toolStrip1
//
toolStrip1.ImageScalingSize = new Size(24, 24);
toolStrip1.Location = new Point(0, 0);
toolStrip1.Name = "toolStrip1";
toolStrip1.Size = new Size(1185, 25);
toolStrip1.TabIndex = 2;
toolStrip1.Text = "toolStrip1";
//
// tabControl1 // tabControl1
// //
tabControl1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
tabControl1.Controls.Add(tabPage1); tabControl1.Controls.Add(tabPage1);
tabControl1.Controls.Add(tabPage2); tabControl1.Controls.Add(tabPage2);
tabControl1.Location = new Point(0, 24); tabControl1.Dock = DockStyle.Fill;
tabControl1.Location = new Point(0, 0);
tabControl1.Name = "tabControl1"; tabControl1.Name = "tabControl1";
tabControl1.SelectedIndex = 0; tabControl1.SelectedIndex = 0;
tabControl1.Size = new Size(1185, 925); tabControl1.Size = new Size(1185, 800);
tabControl1.TabIndex = 3; tabControl1.TabIndex = 3;
// //
// tabPage1 // tabPage1
// //
tabPage1.Controls.Add(toolStrip2);
tabPage1.Controls.Add(propertyGrid); tabPage1.Controls.Add(propertyGrid);
tabPage1.Controls.Add(toolStrip2);
tabPage1.Location = new Point(4, 34); tabPage1.Location = new Point(4, 34);
tabPage1.Name = "tabPage1"; tabPage1.Name = "tabPage1";
tabPage1.Padding = new Padding(3); tabPage1.Padding = new Padding(3);
@@ -82,8 +70,9 @@ namespace PolyTraderSharp.Ui.Views
// //
// toolStrip2 // toolStrip2
// //
toolStrip2.Dock = DockStyle.Top;
toolStrip2.ImageScalingSize = new Size(24, 24); toolStrip2.ImageScalingSize = new Size(24, 24);
toolStrip2.Items.AddRange(new ToolStripItem[] { btn_save, btn_loadsettings, btnGenMasterKey }); toolStrip2.Items.AddRange(new ToolStripItem[] { btn_save, btn_loadsettings, btnGenMasterKey, btnSetOpenRouterKey });
toolStrip2.Location = new Point(3, 3); toolStrip2.Location = new Point(3, 3);
toolStrip2.Name = "toolStrip2"; toolStrip2.Name = "toolStrip2";
toolStrip2.Size = new Size(1171, 34); toolStrip2.Size = new Size(1171, 34);
@@ -114,6 +103,14 @@ namespace PolyTraderSharp.Ui.Views
btnGenMasterKey.Text = "Master-Key erzeugen"; btnGenMasterKey.Text = "Master-Key erzeugen";
btnGenMasterKey.ToolTipText = "Erzeugt einen zufälligen AES-Master-Key (nur wenn noch keiner existiert)."; btnGenMasterKey.ToolTipText = "Erzeugt einen zufälligen AES-Master-Key (nur wenn noch keiner existiert).";
// //
// btnSetOpenRouterKey
//
btnSetOpenRouterKey.DisplayStyle = ToolStripItemDisplayStyle.Text;
btnSetOpenRouterKey.Name = "btnSetOpenRouterKey";
btnSetOpenRouterKey.Size = new Size(200, 29);
btnSetOpenRouterKey.Text = "OpenRouter-Key setzen …";
btnSetOpenRouterKey.ToolTipText = "Speichert den OpenRouter-API-Key für den Supervisor (gitignorierte Datei openrouter.key).";
//
// tabPage2 // tabPage2
// //
tabPage2.Controls.Add(pgAccount); tabPage2.Controls.Add(pgAccount);
@@ -153,6 +150,7 @@ namespace PolyTraderSharp.Ui.Views
// //
// toolStripAccounts // toolStripAccounts
// //
toolStripAccounts.Dock = DockStyle.Top;
toolStripAccounts.ImageScalingSize = new Size(24, 24); toolStripAccounts.ImageScalingSize = new Size(24, 24);
toolStripAccounts.Items.AddRange(new ToolStripItem[] { btnAccNew, btnAccDelete }); toolStripAccounts.Items.AddRange(new ToolStripItem[] { btnAccNew, btnAccDelete });
toolStripAccounts.Location = new Point(3, 3); toolStripAccounts.Location = new Point(3, 3);
@@ -178,9 +176,8 @@ namespace PolyTraderSharp.Ui.Views
// //
AutoScaleDimensions = new SizeF(10F, 25F); AutoScaleDimensions = new SizeF(10F, 25F);
AutoScaleMode = AutoScaleMode.Font; AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(1185, 1523); ClientSize = new Size(1185, 820);
Controls.Add(tabControl1); Controls.Add(tabControl1);
Controls.Add(toolStrip1);
Margin = new Padding(4, 5, 4, 5); Margin = new Padding(4, 5, 4, 5);
Name = "SettingsView"; Name = "SettingsView";
Text = "Server Settings"; Text = "Server Settings";
@@ -201,7 +198,6 @@ namespace PolyTraderSharp.Ui.Views
#endregion #endregion
private System.Windows.Forms.PropertyGrid propertyGrid; private System.Windows.Forms.PropertyGrid propertyGrid;
private ToolStrip toolStrip1;
private TabControl tabControl1; private TabControl tabControl1;
private TabPage tabPage1; private TabPage tabPage1;
private ToolStrip toolStrip2; private ToolStrip toolStrip2;
@@ -209,6 +205,7 @@ namespace PolyTraderSharp.Ui.Views
private ToolStripButton btn_save; private ToolStripButton btn_save;
private ToolStripButton btn_loadsettings; private ToolStripButton btn_loadsettings;
private ToolStripButton btnGenMasterKey; private ToolStripButton btnGenMasterKey;
private ToolStripButton btnSetOpenRouterKey;
private ToolStrip toolStripAccounts; private ToolStrip toolStripAccounts;
private ToolStripButton btnAccNew; private ToolStripButton btnAccNew;
private ToolStripButton btnAccDelete; private ToolStripButton btnAccDelete;
+67
View File
@@ -36,6 +36,7 @@ namespace PolyTraderSharp.Ui.Views
btn_save.Click += (_, _) => Save(); btn_save.Click += (_, _) => Save();
btn_loadsettings.Click += (_, _) => Reload(); btn_loadsettings.Click += (_, _) => Reload();
btnGenMasterKey.Click += (_, _) => GenerateMasterKey(); btnGenMasterKey.Click += (_, _) => GenerateMasterKey();
btnSetOpenRouterKey.Click += (_, _) => SetOpenRouterKey();
UpdateMasterKeyButtonState(); UpdateMasterKeyButtonState();
btnAccNew.Click += (_, _) => AddAccount(); btnAccNew.Click += (_, _) => AddAccount();
@@ -182,5 +183,71 @@ namespace PolyTraderSharp.Ui.Views
UpdateMasterKeyButtonState(); // nach Erzeugung deaktivieren UpdateMasterKeyButtonState(); // nach Erzeugung deaktivieren
} }
// ===== OpenRouter-API-Key (Supervisor) =====
/// <summary>
/// Setzt/entfernt den OpenRouter-API-Key des Supervisors. Ablage in der gitignorierten Datei
/// openrouter.key (genau das liest der OpenRouterClient) kein Secret im Klartext in
/// server_settings.xml. Der Nutzer gibt den Key selbst maskiert ein.
/// </summary>
private void SetOpenRouterKey()
{
string keyFile = Path.Combine(AppContext.BaseDirectory, "openrouter.key");
bool exists = File.Exists(keyFile) ||
!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("POLYTRADER_OPENROUTER_KEY"));
string? key = PromptForSecret("OpenRouter-API-Key",
"OpenRouter-API-Key für den Supervisor eingeben.\n" +
"Wird in der gitignorierten Datei 'openrouter.key' gespeichert (leer = entfernen).\n" +
(exists ? "Aktuell ist bereits ein Key hinterlegt." : "Aktuell ist KEIN Key gesetzt."));
if (key == null) return; // Abbruch
try
{
if (string.IsNullOrWhiteSpace(key))
{
if (File.Exists(keyFile)) File.Delete(keyFile);
_logger?.Info("OpenRouter-Key aus openrouter.key entfernt.");
MessageBox.Show("OpenRouter-Key entfernt.", "OpenRouter",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
File.WriteAllText(keyFile, key.Trim());
_logger?.Info("OpenRouter-Key gespeichert (openrouter.key).");
MessageBox.Show("OpenRouter-Key gespeichert. Wirkt beim nächsten Programmstart bzw. der nächsten Supervisor-Anfrage.\n\n" +
"Tipp: bei OpenRouter ein Spend-Limit für diesen Key setzen (separater Key für den Supervisor empfohlen).",
"OpenRouter", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
catch (Exception ex)
{
MessageBox.Show($"Fehler beim Speichern des OpenRouter-Keys: {ex.Message}",
"Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>Modaler Mini-Dialog mit maskierter Eingabe. Rückgabe null = Abbruch.</summary>
private string? PromptForSecret(string title, string prompt)
{
using var form = new Form
{
Text = title,
Width = 480,
Height = 210,
FormBorderStyle = FormBorderStyle.FixedDialog,
StartPosition = FormStartPosition.CenterParent,
MinimizeBox = false,
MaximizeBox = false
};
var lbl = new Label { Text = prompt, Left = 12, Top = 12, Width = 445, Height = 70, AutoSize = false };
var tb = new TextBox { Left = 12, Top = 92, Width = 445, UseSystemPasswordChar = true };
var ok = new Button { Text = "OK", DialogResult = DialogResult.OK, Left = 296, Top = 128, Width = 75 };
var cancel = new Button { Text = "Abbrechen", DialogResult = DialogResult.Cancel, Left = 380, Top = 128, Width = 77 };
form.Controls.AddRange(new Control[] { lbl, tb, ok, cancel });
form.AcceptButton = ok;
form.CancelButton = cancel;
return form.ShowDialog(this) == DialogResult.OK ? tb.Text : null;
}
} }
} }