import { App, PluginSettingTab, Setting, Notice } from 'obsidian'; import type LogfirePlugin from '../main'; export class LogfireSettingTab extends PluginSettingTab { constructor(app: App, private plugin: LogfirePlugin) { super(app, plugin); } display(): void { const { containerEl } = this; containerEl.empty(); // ----- General ----- containerEl.createEl('h2', { text: 'Allgemein' }); new Setting(containerEl) .setName('Tracking aktiviert') .setDesc('Hauptschalter für alle Event-Collector.') .addToggle(t => t .setValue(this.plugin.settings.general.enabled) .onChange(async (v) => { this.plugin.settings.general.enabled = v; await this.plugin.saveSettings(); })); new Setting(containerEl) .setName('Log-Ordner') .setDesc('Ordner für Markdown-Projektionen. Wird automatisch vom Tracking ausgeschlossen.') .addText(t => t .setPlaceholder('Logfire') .setValue(this.plugin.settings.general.logFolder) .onChange(async (v) => { this.plugin.settings.general.logFolder = v || 'Logfire'; await this.plugin.saveSettings(); })); new Setting(containerEl) .setName('Beim Start pausieren') .setDesc('Startet im pausierten Zustand — keine Events bis manuell fortgesetzt.') .addToggle(t => t .setValue(this.plugin.settings.general.pauseOnStartup) .onChange(async (v) => { this.plugin.settings.general.pauseOnStartup = v; await this.plugin.saveSettings(); })); // ----- Tracking ----- containerEl.createEl('h2', { text: 'Tracking' }); new Setting(containerEl) .setName('Datei-Events') .setDesc('Erstellen, Löschen, Umbenennen, Verschieben und Ändern von Dateien.') .addToggle(t => t .setValue(this.plugin.settings.tracking.fileEvents) .onChange(async (v) => { this.plugin.settings.tracking.fileEvents = v; await this.plugin.saveSettings(); })); new Setting(containerEl) .setName('Content-Analyse') .setDesc('Semantische Diffs: Wortzählung, Links, Tags, Überschriften, Frontmatter.') .addToggle(t => t .setValue(this.plugin.settings.tracking.contentAnalysis) .onChange(async (v) => { this.plugin.settings.tracking.contentAnalysis = v; await this.plugin.saveSettings(); })); new Setting(containerEl) .setName('Navigation') .setDesc('Aktive Datei-Wechsel, Datei öffnen/schließen mit Dauer.') .addToggle(t => t .setValue(this.plugin.settings.tracking.navigation) .onChange(async (v) => { this.plugin.settings.tracking.navigation = v; await this.plugin.saveSettings(); })); new Setting(containerEl) .setName('Editor-Änderungen') .setDesc('Tastenanschläge (debounced und aggregiert).') .addToggle(t => t .setValue(this.plugin.settings.tracking.editorChanges) .onChange(async (v) => { this.plugin.settings.tracking.editorChanges = v; await this.plugin.saveSettings(); })); new Setting(containerEl) .setName('Kommando-Tracking') .setDesc('Ausführung von Befehlen über Palette und Hotkeys.') .addToggle(t => t .setValue(this.plugin.settings.tracking.commandTracking) .onChange(async (v) => { this.plugin.settings.tracking.commandTracking = v; await this.plugin.saveSettings(); })); new Setting(containerEl) .setName('Ausgeschlossene Ordner') .setDesc('Komma-getrennte Liste von Ordnern, die nicht getrackt werden.') .addText(t => t .setPlaceholder('.obsidian, templates') .setValue(this.plugin.settings.tracking.excludedFolders.join(', ')) .onChange(async (v) => { this.plugin.settings.tracking.excludedFolders = v .split(',') .map(s => s.trim()) .filter(s => s.length > 0); await this.plugin.saveSettings(); })); new Setting(containerEl) .setName('Ausgeschlossene Patterns') .setDesc('Komma-getrennte Glob-Patterns (z.B. **/*.excalidraw.md).') .addText(t => t .setPlaceholder('**/*.excalidraw.md') .setValue(this.plugin.settings.tracking.excludedPatterns.join(', ')) .onChange(async (v) => { this.plugin.settings.tracking.excludedPatterns = v .split(',') .map(s => s.trim()) .filter(s => s.length > 0); await this.plugin.saveSettings(); })); // ----- Projections ----- containerEl.createEl('h2', { text: 'Projektionen' }); new Setting(containerEl) .setName('Projektionen aktiviert') .setDesc('Automatische Markdown-Reports aus Event-Daten.') .addToggle(t => t .setValue(this.plugin.settings.projections.enabled) .onChange(async (v) => { this.plugin.settings.projections.enabled = v; await this.plugin.saveSettings(); })); new Setting(containerEl) .setName('Output-Ordner') .setDesc('Ordner für generierte Projektions-Dateien.') .addText(t => t .setPlaceholder('Logfire') .setValue(this.plugin.settings.projections.outputFolder) .onChange(async (v) => { this.plugin.settings.projections.outputFolder = v || 'Logfire'; await this.plugin.saveSettings(); })); new Setting(containerEl) .setName('Tagesprotokoll') .setDesc('Automatisches Tagesprotokoll generieren.') .addToggle(t => t .setValue(this.plugin.settings.projections.dailyLog.enabled) .onChange(async (v) => { this.plugin.settings.projections.dailyLog.enabled = v; await this.plugin.saveSettings(); })) .addText(t => t .setPlaceholder('23:00') .setValue(this.plugin.settings.projections.dailyLog.time) .onChange(async (v) => { if (/^\d{2}:\d{2}$/.test(v)) { this.plugin.settings.projections.dailyLog.time = v; await this.plugin.saveSettings(); } })); new Setting(containerEl) .setName('Session-Protokoll') .setDesc('Protokoll bei Session-Ende generieren.') .addToggle(t => t .setValue(this.plugin.settings.projections.sessionLog.enabled) .onChange(async (v) => { this.plugin.settings.projections.sessionLog.enabled = v; await this.plugin.saveSettings(); })); new Setting(containerEl) .setName('Wochen-Digest') .setDesc('Wöchentliche Zusammenfassung generieren.') .addToggle(t => t .setValue(this.plugin.settings.projections.weeklyDigest.enabled) .onChange(async (v) => { this.plugin.settings.projections.weeklyDigest.enabled = v; await this.plugin.saveSettings(); })) .addDropdown(d => d .addOptions({ '0': 'Sonntag', '1': 'Montag', '2': 'Dienstag', '3': 'Mittwoch', '4': 'Donnerstag', '5': 'Freitag', '6': 'Samstag', }) .setValue(String(this.plugin.settings.projections.weeklyDigest.dayOfWeek)) .onChange(async (v) => { this.plugin.settings.projections.weeklyDigest.dayOfWeek = parseInt(v, 10); await this.plugin.saveSettings(); })); // ----- Advanced (collapsible) ----- const advancedHeader = containerEl.createEl('details'); advancedHeader.createEl('summary', { text: 'Erweiterte Einstellungen' }) .style.cursor = 'pointer'; const advEl = advancedHeader.createDiv(); advEl.createEl('p', { text: 'Diese Einstellungen beeinflussen Performance und Speicher. Die Standardwerte sind für die meisten Vaults optimal.', cls: 'setting-item-description', }); // Performance advEl.createEl('h3', { text: 'Performance' }); new Setting(advEl) .setName('Editor-Debounce (ms)') .setDesc('Wartezeit nach letztem Tastenanschlag vor editor:change Event.') .addText(t => t .setValue(String(this.plugin.settings.advanced.debounceMs)) .onChange(async (v) => { const n = parseInt(v, 10); if (!isNaN(n) && n >= 500) { this.plugin.settings.advanced.debounceMs = n; await this.plugin.saveSettings(); } })); new Setting(advEl) .setName('Flush-Intervall (ms)') .setDesc('Wie oft gepufferte Events in die Datenbank geschrieben werden.') .addText(t => t .setValue(String(this.plugin.settings.advanced.flushIntervalMs)) .onChange(async (v) => { const n = parseInt(v, 10); if (!isNaN(n) && n >= 1000) { this.plugin.settings.advanced.flushIntervalMs = n; await this.plugin.saveSettings(); } })); new Setting(advEl) .setName('Flush-Schwellwert') .setDesc('Maximale Events im Puffer vor erzwungenem Schreiben.') .addText(t => t .setValue(String(this.plugin.settings.advanced.flushThreshold)) .onChange(async (v) => { const n = parseInt(v, 10); if (!isNaN(n) && n >= 10) { this.plugin.settings.advanced.flushThreshold = n; await this.plugin.saveSettings(); } })); // Retention advEl.createEl('h3', { text: 'Aufbewahrung' }); new Setting(advEl) .setName('Raw-Events aufbewahren (Tage)') .setDesc('Danach werden Events in Tages-Statistiken aggregiert und gelöscht.') .addText(t => t .setValue(String(this.plugin.settings.advanced.retention.rawEventsDays)) .onChange(async (v) => { const n = parseInt(v, 10); if (!isNaN(n) && n >= 1) { this.plugin.settings.advanced.retention.rawEventsDays = n; await this.plugin.saveSettings(); } })); new Setting(advEl) .setName('Tages-Statistiken aufbewahren (Tage)') .setDesc('Danach werden Tages-Statistiken in Monats-Statistiken aggregiert.') .addText(t => t .setValue(String(this.plugin.settings.advanced.retention.dailyStatsDays)) .onChange(async (v) => { const n = parseInt(v, 10); if (!isNaN(n) && n >= 30) { this.plugin.settings.advanced.retention.dailyStatsDays = n; await this.plugin.saveSettings(); } })); new Setting(advEl) .setName('Wartung beim Start') .setDesc('Automatisch Retention-Cleanup beim Plugin-Start ausführen.') .addToggle(t => t .setValue(this.plugin.settings.advanced.retention.maintenanceOnStartup) .onChange(async (v) => { this.plugin.settings.advanced.retention.maintenanceOnStartup = v; await this.plugin.saveSettings(); })); // Database info advEl.createEl('h3', { text: 'Datenbank' }); const dbInfoEl = advEl.createDiv(); try { const eventCount = this.plugin.db.getEventCount(); const dbSize = this.plugin.db.getDatabaseSizeBytes(); const oldest = this.plugin.db.getOldestEventTimestamp(); dbInfoEl.createEl('p', { text: `Events: ${eventCount.toLocaleString()} | Größe: ${formatBytes(dbSize)} | Ältestes: ${oldest ? new Date(oldest).toLocaleDateString() : 'k.A.'}`, }); } catch { dbInfoEl.createEl('p', { text: 'Datenbank-Info nicht verfügbar.' }); } new Setting(advEl) .setName('Datenbank-Aktionen') .addButton(b => b .setButtonText('Wartung ausführen') .onClick(() => { try { this.plugin.db.runMaintenance(this.plugin.settings.advanced.retention); new Notice('Logfire: Wartung abgeschlossen.'); this.display(); } catch (err) { new Notice('Logfire: Wartung fehlgeschlagen.'); console.error('[Logfire] Wartung fehlgeschlagen:', err); } })); } } function formatBytes(bytes: number): string { if (bytes < 1024) return `${bytes} B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; }