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
+67
View File
@@ -36,6 +36,7 @@ namespace PolyTraderSharp.Ui.Views
btn_save.Click += (_, _) => Save();
btn_loadsettings.Click += (_, _) => Reload();
btnGenMasterKey.Click += (_, _) => GenerateMasterKey();
btnSetOpenRouterKey.Click += (_, _) => SetOpenRouterKey();
UpdateMasterKeyButtonState();
btnAccNew.Click += (_, _) => AddAccount();
@@ -182,5 +183,71 @@ namespace PolyTraderSharp.Ui.Views
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;
}
}
}