Files
ClawdDotNet/UI/BackupPanel.Designer.cs
T
RichardandClaude Opus 4.8 b51cc29667 Backup-Oberflaeche im Settings-Tab
Der BackupService bekommt eine Bedienoberflaeche im neuen Unterreiter "Backup".

Aufbau als eigenes UserControl (UI/BackupPanel) statt direkt in frm_main.Designer.cs.
Diese Datei ist ueber 1250 Zeilen gewachsene Handarbeit; ein Fehler beim Bearbeiten
waere teuer. Eingehaengt wird das Panel mit vier Zeilen.

Drei Bereiche: Sicherung erstellen (Zielordner, Umgang mit Zugangsdaten, Umfang),
automatische Sicherung (Uhrzeit, Aufbewahrungszahl) und die Liste vorhandener
Sicherungen mit Wiederherstellen, Anzeigen und Loeschen. Die Liste liest das
Manifest jeder Datei und zeigt Instanz und ob Zugangsdaten enthalten sind;
unlesbare oder fremde Archive werden ausgegraut mitgezeigt, statt sie zu
verschweigen.

Zwei Entscheidungen praegen das Verhalten.

Die Passphrase wird nirgends gespeichert. Laege sie neben den Sicherungen, waere
die Verschluesselung wirkungslos. Sie muss deshalb bei jeder geschuetzten
Sicherung neu eingegeben und wiederholt werden, und vor dem Erstellen wird
ausdruecklich bestaetigt, dass sie notiert ist — ohne sie sind die Zugangsdaten
unwiederbringlich. Die Automatik sichert aus demselben Grund ohne Zugangsdaten.

Wiederhergestellt wird standardmaessig in einen NEUEN Ordner neben der Instanz,
nicht ueber die laufende. Diese haelt Chatverlaeufe im Speicher und die Datenbank
geoeffnet — ein Ueberschreiben im Betrieb wuerde teils sofort wieder ueberschrieben
und teils scheitern. Der Dialog benennt das.

Vor dem Schreiben laeuft immer ein Probelauf: Er prueft die Pruefsummen und zaehlt
die Konflikte, sodass ein beschaedigtes Archiv auffaellt und Ueberschreiben
bestaetigt wird, bevor etwas passiert.

BackupScheduler sichert taeglich zur eingestellten Uhrzeit und wendet die Rotation
an. Der Zeitpunkt wird bei jedem Durchlauf neu aus den Einstellungen gelesen,
damit eine Aenderung ohne Neustart greift.

Die Oberflaeche ist noch nicht optisch geprueft — die Dev-Instanz haelt einen
echten API-Key und wuerde beim Start Agenten ausfuehren.

385 Tests gruen (237 Core, 148 Tools).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-30 10:37:16 +02:00

429 lines
17 KiB
C#

namespace ClawdDotNet.UI;
partial class BackupPanel
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && components is not null)
components.Dispose();
base.Dispose(disposing);
}
private void InitializeComponent()
{
layoutRoot = new TableLayoutPanel();
grp_create = new GroupBox();
layoutCreate = new TableLayoutPanel();
label_target = new Label();
txt_targetFolder = new TextBox();
btn_browseFolder = new Button();
label_secrets = new Label();
panel_secretMode = new FlowLayoutPanel();
rb_secretsExclude = new RadioButton();
rb_secretsPassphrase = new RadioButton();
label_passphrase = new Label();
txt_passphrase = new TextBox();
label_passphraseRepeat = new Label();
txt_passphraseRepeat = new TextBox();
label_scope = new Label();
panel_scope = new FlowLayoutPanel();
chk_includeChatHistory = new CheckBox();
chk_includeLogs = new CheckBox();
panel_createActions = new FlowLayoutPanel();
btn_createBackup = new Button();
label_createStatus = new Label();
grp_auto = new GroupBox();
layoutAuto = new TableLayoutPanel();
chk_autoEnabled = new CheckBox();
dtp_autoTime = new DateTimePicker();
label_keepCount = new Label();
num_keepCount = new NumericUpDown();
label_autoHint = new Label();
grp_existing = new GroupBox();
layoutExisting = new TableLayoutPanel();
lv_backups = new ListView();
col_file = new ColumnHeader();
col_created = new ColumnHeader();
col_instance = new ColumnHeader();
col_size = new ColumnHeader();
col_secrets = new ColumnHeader();
panel_existingActions = new FlowLayoutPanel();
btn_refresh = new Button();
btn_restore = new Button();
btn_showInFolder = new Button();
btn_delete = new Button();
layoutRoot.SuspendLayout();
grp_create.SuspendLayout();
layoutCreate.SuspendLayout();
panel_secretMode.SuspendLayout();
panel_scope.SuspendLayout();
panel_createActions.SuspendLayout();
grp_auto.SuspendLayout();
layoutAuto.SuspendLayout();
((System.ComponentModel.ISupportInitialize)num_keepCount).BeginInit();
grp_existing.SuspendLayout();
layoutExisting.SuspendLayout();
panel_existingActions.SuspendLayout();
SuspendLayout();
// ─── Wurzel ───
layoutRoot.ColumnCount = 1;
layoutRoot.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
layoutRoot.Dock = DockStyle.Fill;
layoutRoot.Name = "layoutRoot";
layoutRoot.Padding = new Padding(12);
layoutRoot.RowCount = 3;
layoutRoot.RowStyles.Add(new RowStyle(SizeType.AutoSize));
layoutRoot.RowStyles.Add(new RowStyle(SizeType.AutoSize));
layoutRoot.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
layoutRoot.Controls.Add(grp_create, 0, 0);
layoutRoot.Controls.Add(grp_auto, 0, 1);
layoutRoot.Controls.Add(grp_existing, 0, 2);
// ═══ Sicherung erstellen ═══
grp_create.AutoSize = true;
grp_create.AutoSizeMode = AutoSizeMode.GrowAndShrink;
grp_create.Controls.Add(layoutCreate);
grp_create.Dock = DockStyle.Fill;
grp_create.Name = "grp_create";
grp_create.Padding = new Padding(10);
grp_create.TabIndex = 0;
grp_create.TabStop = false;
grp_create.Text = "Sicherung erstellen";
layoutCreate.AutoSize = true;
layoutCreate.AutoSizeMode = AutoSizeMode.GrowAndShrink;
layoutCreate.ColumnCount = 3;
layoutCreate.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
layoutCreate.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
layoutCreate.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
layoutCreate.Dock = DockStyle.Fill;
layoutCreate.Name = "layoutCreate";
layoutCreate.RowCount = 6;
for (var i = 0; i < 6; i++)
layoutCreate.RowStyles.Add(new RowStyle(SizeType.AutoSize));
label_target.Anchor = AnchorStyles.Left;
label_target.AutoSize = true;
label_target.Name = "label_target";
label_target.Text = "Zielordner:";
txt_targetFolder.Anchor = AnchorStyles.Left | AnchorStyles.Right;
txt_targetFolder.Name = "txt_targetFolder";
btn_browseFolder.AutoSize = true;
btn_browseFolder.Name = "btn_browseFolder";
btn_browseFolder.Text = "Durchsuchen…";
btn_browseFolder.UseVisualStyleBackColor = true;
label_secrets.Anchor = AnchorStyles.Left;
label_secrets.AutoSize = true;
label_secrets.Name = "label_secrets";
label_secrets.Text = "Zugangsdaten:";
panel_secretMode.AutoSize = true;
panel_secretMode.Controls.Add(rb_secretsExclude);
panel_secretMode.Controls.Add(rb_secretsPassphrase);
panel_secretMode.Margin = new Padding(0);
panel_secretMode.Name = "panel_secretMode";
panel_secretMode.WrapContents = false;
rb_secretsExclude.AutoSize = true;
rb_secretsExclude.Checked = true;
rb_secretsExclude.Name = "rb_secretsExclude";
rb_secretsExclude.TabStop = true;
rb_secretsExclude.Text = "nicht mitsichern";
rb_secretsExclude.UseVisualStyleBackColor = true;
rb_secretsPassphrase.AutoSize = true;
rb_secretsPassphrase.Name = "rb_secretsPassphrase";
rb_secretsPassphrase.Text = "mit Passphrase schützen";
rb_secretsPassphrase.UseVisualStyleBackColor = true;
label_passphrase.Anchor = AnchorStyles.Left;
label_passphrase.AutoSize = true;
label_passphrase.Name = "label_passphrase";
label_passphrase.Text = "Passphrase:";
txt_passphrase.Anchor = AnchorStyles.Left | AnchorStyles.Right;
txt_passphrase.Name = "txt_passphrase";
txt_passphrase.UseSystemPasswordChar = true;
label_passphraseRepeat.Anchor = AnchorStyles.Left;
label_passphraseRepeat.AutoSize = true;
label_passphraseRepeat.Name = "label_passphraseRepeat";
label_passphraseRepeat.Text = "Wiederholen:";
txt_passphraseRepeat.Anchor = AnchorStyles.Left | AnchorStyles.Right;
txt_passphraseRepeat.Name = "txt_passphraseRepeat";
txt_passphraseRepeat.UseSystemPasswordChar = true;
label_scope.Anchor = AnchorStyles.Left;
label_scope.AutoSize = true;
label_scope.Name = "label_scope";
label_scope.Text = "Umfang:";
panel_scope.AutoSize = true;
panel_scope.Controls.Add(chk_includeChatHistory);
panel_scope.Controls.Add(chk_includeLogs);
panel_scope.Margin = new Padding(0);
panel_scope.Name = "panel_scope";
panel_scope.WrapContents = false;
chk_includeChatHistory.AutoSize = true;
chk_includeChatHistory.Checked = true;
chk_includeChatHistory.CheckState = CheckState.Checked;
chk_includeChatHistory.Name = "chk_includeChatHistory";
chk_includeChatHistory.Text = "Chatverläufe";
chk_includeChatHistory.UseVisualStyleBackColor = true;
chk_includeLogs.AutoSize = true;
chk_includeLogs.Name = "chk_includeLogs";
chk_includeLogs.Text = "Protokolle";
chk_includeLogs.UseVisualStyleBackColor = true;
panel_createActions.AutoSize = true;
panel_createActions.Controls.Add(btn_createBackup);
panel_createActions.Controls.Add(label_createStatus);
panel_createActions.Margin = new Padding(0, 8, 0, 0);
panel_createActions.Name = "panel_createActions";
panel_createActions.WrapContents = false;
btn_createBackup.AutoSize = true;
btn_createBackup.Name = "btn_createBackup";
btn_createBackup.Padding = new Padding(8, 2, 8, 2);
btn_createBackup.Text = "Sicherung jetzt erstellen";
btn_createBackup.UseVisualStyleBackColor = true;
label_createStatus.Anchor = AnchorStyles.Left;
label_createStatus.AutoSize = true;
label_createStatus.Margin = new Padding(12, 8, 3, 0);
label_createStatus.Name = "label_createStatus";
layoutCreate.Controls.Add(label_target, 0, 0);
layoutCreate.Controls.Add(txt_targetFolder, 1, 0);
layoutCreate.Controls.Add(btn_browseFolder, 2, 0);
layoutCreate.Controls.Add(label_secrets, 0, 1);
layoutCreate.Controls.Add(panel_secretMode, 1, 1);
layoutCreate.Controls.Add(label_passphrase, 0, 2);
layoutCreate.Controls.Add(txt_passphrase, 1, 2);
layoutCreate.Controls.Add(label_passphraseRepeat, 0, 3);
layoutCreate.Controls.Add(txt_passphraseRepeat, 1, 3);
layoutCreate.Controls.Add(label_scope, 0, 4);
layoutCreate.Controls.Add(panel_scope, 1, 4);
layoutCreate.Controls.Add(panel_createActions, 1, 5);
// ═══ Automatik ═══
grp_auto.AutoSize = true;
grp_auto.AutoSizeMode = AutoSizeMode.GrowAndShrink;
grp_auto.Controls.Add(layoutAuto);
grp_auto.Dock = DockStyle.Fill;
grp_auto.Margin = new Padding(3, 10, 3, 3);
grp_auto.Name = "grp_auto";
grp_auto.Padding = new Padding(10);
grp_auto.TabIndex = 1;
grp_auto.TabStop = false;
grp_auto.Text = "Automatische Sicherung";
layoutAuto.AutoSize = true;
layoutAuto.AutoSizeMode = AutoSizeMode.GrowAndShrink;
layoutAuto.ColumnCount = 5;
for (var i = 0; i < 4; i++)
layoutAuto.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
layoutAuto.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
layoutAuto.Dock = DockStyle.Fill;
layoutAuto.Name = "layoutAuto";
layoutAuto.RowCount = 2;
layoutAuto.RowStyles.Add(new RowStyle(SizeType.AutoSize));
layoutAuto.RowStyles.Add(new RowStyle(SizeType.AutoSize));
chk_autoEnabled.Anchor = AnchorStyles.Left;
chk_autoEnabled.AutoSize = true;
chk_autoEnabled.Name = "chk_autoEnabled";
chk_autoEnabled.Text = "täglich sichern um";
chk_autoEnabled.UseVisualStyleBackColor = true;
dtp_autoTime.Anchor = AnchorStyles.Left;
dtp_autoTime.Format = DateTimePickerFormat.Time;
dtp_autoTime.Name = "dtp_autoTime";
dtp_autoTime.ShowUpDown = true;
dtp_autoTime.Width = 90;
label_keepCount.Anchor = AnchorStyles.Left;
label_keepCount.AutoSize = true;
label_keepCount.Margin = new Padding(24, 6, 3, 0);
label_keepCount.Name = "label_keepCount";
label_keepCount.Text = "Aufbewahren:";
num_keepCount.Anchor = AnchorStyles.Left;
num_keepCount.Maximum = 999;
num_keepCount.Name = "num_keepCount";
num_keepCount.Width = 70;
label_autoHint.Anchor = AnchorStyles.Left;
label_autoHint.AutoSize = true;
label_autoHint.ForeColor = SystemColors.GrayText;
label_autoHint.Name = "label_autoHint";
label_autoHint.Text = "Die Automatik sichert ohne Zugangsdaten — eine gespeicherte Passphrase "
+ "neben den Sicherungen wäre wirkungslos.";
layoutAuto.Controls.Add(chk_autoEnabled, 0, 0);
layoutAuto.Controls.Add(dtp_autoTime, 1, 0);
layoutAuto.Controls.Add(label_keepCount, 2, 0);
layoutAuto.Controls.Add(num_keepCount, 3, 0);
layoutAuto.Controls.Add(label_autoHint, 0, 1);
layoutAuto.SetColumnSpan(label_autoHint, 5);
// ═══ Vorhandene Sicherungen ═══
grp_existing.Controls.Add(layoutExisting);
grp_existing.Dock = DockStyle.Fill;
grp_existing.Margin = new Padding(3, 10, 3, 3);
grp_existing.Name = "grp_existing";
grp_existing.Padding = new Padding(10);
grp_existing.TabIndex = 2;
grp_existing.TabStop = false;
grp_existing.Text = "Vorhandene Sicherungen";
layoutExisting.ColumnCount = 1;
layoutExisting.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
layoutExisting.Dock = DockStyle.Fill;
layoutExisting.Name = "layoutExisting";
layoutExisting.RowCount = 2;
layoutExisting.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
layoutExisting.RowStyles.Add(new RowStyle(SizeType.AutoSize));
layoutExisting.Controls.Add(lv_backups, 0, 0);
layoutExisting.Controls.Add(panel_existingActions, 0, 1);
lv_backups.Columns.AddRange(new[] { col_file, col_created, col_instance, col_size, col_secrets });
lv_backups.Dock = DockStyle.Fill;
lv_backups.FullRowSelect = true;
lv_backups.MultiSelect = false;
lv_backups.Name = "lv_backups";
lv_backups.UseCompatibleStateImageBehavior = false;
lv_backups.View = View.Details;
col_file.Text = "Datei";
col_file.Width = 420;
col_created.Text = "Erstellt";
col_created.Width = 150;
col_instance.Text = "Instanz";
col_instance.Width = 180;
col_size.Text = "Größe";
col_size.Width = 100;
col_secrets.Text = "Zugangsdaten";
col_secrets.Width = 140;
panel_existingActions.AutoSize = true;
panel_existingActions.Controls.Add(btn_refresh);
panel_existingActions.Controls.Add(btn_restore);
panel_existingActions.Controls.Add(btn_showInFolder);
panel_existingActions.Controls.Add(btn_delete);
panel_existingActions.Margin = new Padding(0, 8, 0, 0);
panel_existingActions.Name = "panel_existingActions";
panel_existingActions.WrapContents = false;
btn_refresh.AutoSize = true;
btn_refresh.Name = "btn_refresh";
btn_refresh.Text = "Aktualisieren";
btn_refresh.UseVisualStyleBackColor = true;
btn_restore.AutoSize = true;
btn_restore.Name = "btn_restore";
btn_restore.Padding = new Padding(8, 2, 8, 2);
btn_restore.Text = "Wiederherstellen…";
btn_restore.UseVisualStyleBackColor = true;
btn_showInFolder.AutoSize = true;
btn_showInFolder.Name = "btn_showInFolder";
btn_showInFolder.Text = "Im Ordner zeigen";
btn_showInFolder.UseVisualStyleBackColor = true;
btn_delete.AutoSize = true;
btn_delete.Name = "btn_delete";
btn_delete.Text = "Löschen";
btn_delete.UseVisualStyleBackColor = true;
// ─── Steuerelement ───
AutoScaleDimensions = new SizeF(10F, 25F);
AutoScaleMode = AutoScaleMode.Font;
Controls.Add(layoutRoot);
Name = "BackupPanel";
Size = new Size(1200, 800);
layoutRoot.ResumeLayout(false);
layoutRoot.PerformLayout();
grp_create.ResumeLayout(false);
grp_create.PerformLayout();
layoutCreate.ResumeLayout(false);
layoutCreate.PerformLayout();
panel_secretMode.ResumeLayout(false);
panel_secretMode.PerformLayout();
panel_scope.ResumeLayout(false);
panel_scope.PerformLayout();
panel_createActions.ResumeLayout(false);
panel_createActions.PerformLayout();
grp_auto.ResumeLayout(false);
grp_auto.PerformLayout();
layoutAuto.ResumeLayout(false);
layoutAuto.PerformLayout();
((System.ComponentModel.ISupportInitialize)num_keepCount).EndInit();
grp_existing.ResumeLayout(false);
layoutExisting.ResumeLayout(false);
layoutExisting.PerformLayout();
panel_existingActions.ResumeLayout(false);
panel_existingActions.PerformLayout();
ResumeLayout(false);
}
private TableLayoutPanel layoutRoot;
private GroupBox grp_create;
private TableLayoutPanel layoutCreate;
private Label label_target;
private TextBox txt_targetFolder;
private Button btn_browseFolder;
private Label label_secrets;
private FlowLayoutPanel panel_secretMode;
private RadioButton rb_secretsExclude;
private RadioButton rb_secretsPassphrase;
private Label label_passphrase;
private TextBox txt_passphrase;
private Label label_passphraseRepeat;
private TextBox txt_passphraseRepeat;
private Label label_scope;
private FlowLayoutPanel panel_scope;
private CheckBox chk_includeChatHistory;
private CheckBox chk_includeLogs;
private FlowLayoutPanel panel_createActions;
private Button btn_createBackup;
private Label label_createStatus;
private GroupBox grp_auto;
private TableLayoutPanel layoutAuto;
private CheckBox chk_autoEnabled;
private DateTimePicker dtp_autoTime;
private Label label_keepCount;
private NumericUpDown num_keepCount;
private Label label_autoHint;
private GroupBox grp_existing;
private TableLayoutPanel layoutExisting;
private ListView lv_backups;
private ColumnHeader col_file;
private ColumnHeader col_created;
private ColumnHeader col_instance;
private ColumnHeader col_size;
private ColumnHeader col_secrets;
private FlowLayoutPanel panel_existingActions;
private Button btn_refresh;
private Button btn_restore;
private Button btn_showInFolder;
private Button btn_delete;
}