From 56049b9318e72197191ae15b52a2008143bb2fb0 Mon Sep 17 00:00:00 2001 From: Lars Date: Sat, 17 Jan 2026 10:54:32 +0100 Subject: [PATCH] Enhance Mindnet settings interface with new configuration options - Added sections for Dictionary & Schema Configuration, Graph Traversal & Linting, Interview & Note Creation, Unresolved Link Handling, Templater Compatibility, Note Adoption, and Semantic Mapping Builder. - Updated descriptions for various settings to provide clearer guidance in German. - Introduced new settings for interview configuration paths, default notes folder, and handling of unresolved links. - Improved user experience with additional validation options and clearer descriptions for existing settings. --- src/ui/MindnetSettingTab.ts | 359 ++++++++++++++++++++++++------------ 1 file changed, 240 insertions(+), 119 deletions(-) diff --git a/src/ui/MindnetSettingTab.ts b/src/ui/MindnetSettingTab.ts index 398df4f..7e8fe3f 100644 --- a/src/ui/MindnetSettingTab.ts +++ b/src/ui/MindnetSettingTab.ts @@ -17,10 +17,21 @@ export class MindnetSettingTab extends PluginSettingTab { containerEl.createEl("h2", { text: "Mindnet Settings" }); + // ============================================ + // 1. Dictionary & Schema Configuration + // ============================================ + containerEl.createEl("h3", { text: "📚 Dictionary & Schema" }); + containerEl.createEl("p", { + text: "Konfigurationsdateien für Edge-Vokabular, Graph-Schema und Interview-Profile.", + cls: "setting-item-description", + }); + // Edge vocabulary path new Setting(containerEl) .setName("Edge vocabulary path") - .setDesc("Vault-relative path to the edge vocabulary markdown file") + .setDesc( + "Pfad zur Edge-Vokabular-Datei (Markdown). Definiert verfügbare Edge-Typen und deren Beschreibungen. Wird für die semantische Mapping-Erstellung verwendet." + ) .addText((text) => text .setPlaceholder("_system/dictionary/edge_vocabulary.md") @@ -55,7 +66,9 @@ export class MindnetSettingTab extends PluginSettingTab { // Graph schema path new Setting(containerEl) .setName("Graph schema path") - .setDesc("Vault-relative path to the graph schema markdown file") + .setDesc( + "Pfad zur Graph-Schema-Datei (Markdown). Definiert typische und verbotene Edge-Typen für verschiedene Quelltypen. Wird für Empfehlungen beim Mapping verwendet." + ) .addText((text) => text .setPlaceholder("_system/dictionary/graph_schema.md") @@ -95,71 +108,12 @@ export class MindnetSettingTab extends PluginSettingTab { }) ); - // Strict mode toggle - new Setting(containerEl) - .setName("Strict mode") - .setDesc("Enable strict validation mode") - .addToggle((toggle) => - toggle - .setValue(this.plugin.settings.strictMode) - .onChange(async (value) => { - this.plugin.settings.strictMode = value; - await this.plugin.saveSettings(); - }) - ); - - // Max hops number input - new Setting(containerEl) - .setName("Max hops") - .setDesc("Maximum number of hops for graph traversal") - .addText((text) => - text - .setPlaceholder("3") - .setValue(String(this.plugin.settings.maxHops)) - .onChange(async (value) => { - const numValue = parseInt(value, 10); - if (!isNaN(numValue) && numValue > 0) { - this.plugin.settings.maxHops = numValue; - await this.plugin.saveSettings(); - } - }) - ); - - // Show canonical hints toggle - new Setting(containerEl) - .setName("Show canonical hints") - .setDesc("Show INFO findings with canonical edge type resolution in lint results") - .addToggle((toggle) => - toggle - .setValue(this.plugin.settings.showCanonicalHints) - .onChange(async (value) => { - this.plugin.settings.showCanonicalHints = value; - await this.plugin.saveSettings(); - }) - ); - - // Chain direction dropdown - new Setting(containerEl) - .setName("Chain direction") - .setDesc("Direction for chain traversal: forward, backward, or both") - .addDropdown((dropdown) => - dropdown - .addOption("forward", "Forward") - .addOption("backward", "Backward") - .addOption("both", "Both") - .setValue(this.plugin.settings.chainDirection) - .onChange(async (value) => { - if (value === "forward" || value === "backward" || value === "both") { - this.plugin.settings.chainDirection = value; - await this.plugin.saveSettings(); - } - }) - ); - // Interview config path new Setting(containerEl) .setName("Interview config path") - .setDesc("Vault-relative path to the interview config YAML file") + .setDesc( + "Pfad zur Interview-Konfigurationsdatei (YAML). Definiert verfügbare Interview-Profile mit ihren Schritten und Einstellungen." + ) .addText((text) => text .setPlaceholder("_system/dictionary/interview_config.yaml") @@ -197,10 +151,99 @@ export class MindnetSettingTab extends PluginSettingTab { }) ); - // Auto-start interview toggle + // ============================================ + // 2. Graph Traversal & Linting + // ============================================ + containerEl.createEl("h3", { text: "🔍 Graph Traversal & Linting" }); + containerEl.createEl("p", { + text: "Einstellungen für Graph-Durchquerung und Lint-Validierung.", + cls: "setting-item-description", + }); + + // Max hops + new Setting(containerEl) + .setName("Max hops") + .setDesc( + "Maximale Anzahl von Hops (Schritten) bei der Graph-Durchquerung. Bestimmt, wie tief der Graph durchsucht wird." + ) + .addText((text) => + text + .setPlaceholder("3") + .setValue(String(this.plugin.settings.maxHops)) + .onChange(async (value) => { + const numValue = parseInt(value, 10); + if (!isNaN(numValue) && numValue > 0) { + this.plugin.settings.maxHops = numValue; + await this.plugin.saveSettings(); + } + }) + ); + + // Chain direction + new Setting(containerEl) + .setName("Chain direction") + .setDesc( + "Richtung für Chain-Traversal: 'Forward' (vorwärts), 'Backward' (rückwärts) oder 'Both' (beide Richtungen)." + ) + .addDropdown((dropdown) => + dropdown + .addOption("forward", "Forward") + .addOption("backward", "Backward") + .addOption("both", "Both") + .setValue(this.plugin.settings.chainDirection) + .onChange(async (value) => { + if (value === "forward" || value === "backward" || value === "both") { + this.plugin.settings.chainDirection = value; + await this.plugin.saveSettings(); + } + }) + ); + + // Strict mode + new Setting(containerEl) + .setName("Strict mode") + .setDesc( + "Aktiviert den strikten Validierungsmodus. Erzwingt strengere Regeln bei der Lint-Validierung." + ) + .addToggle((toggle) => + toggle + .setValue(this.plugin.settings.strictMode) + .onChange(async (value) => { + this.plugin.settings.strictMode = value; + await this.plugin.saveSettings(); + }) + ); + + // Show canonical hints + new Setting(containerEl) + .setName("Show canonical hints") + .setDesc( + "Zeigt INFO-Hinweise mit kanonischer Edge-Typ-Auflösung in den Lint-Ergebnissen an. Hilfreich für die Debugging von Edge-Typ-Zuordnungen." + ) + .addToggle((toggle) => + toggle + .setValue(this.plugin.settings.showCanonicalHints) + .onChange(async (value) => { + this.plugin.settings.showCanonicalHints = value; + await this.plugin.saveSettings(); + }) + ); + + // ============================================ + // 3. Interview & Note Creation + // ============================================ + containerEl.createEl("h3", { text: "📝 Interview & Note Creation" }); + containerEl.createEl("p", { + text: "Einstellungen für Interview-Wizard und Notiz-Erstellung.", + cls: "setting-item-description", + }); + + // Auto-start interview on create new Setting(containerEl) .setName("Auto-start interview on create") - .setDesc("Automatically start interview wizard when creating a note from profile") + .setDesc( + "Startet automatisch den Interview-Wizard, wenn eine neue Notiz über ein Profil erstellt wird." + ) .addToggle((toggle) => toggle .setValue(this.plugin.settings.autoStartInterviewOnCreate) @@ -210,10 +253,37 @@ export class MindnetSettingTab extends PluginSettingTab { }) ); - // Intercept unresolved links toggle + // Default notes folder + new Setting(containerEl) + .setName("Default notes folder") + .setDesc( + "Standard-Ordner für neue Notizen (vault-relativer Pfad, leer für Root). Profil-spezifische Defaults haben Vorrang." + ) + .addText((text) => + text + .setPlaceholder("") + .setValue(this.plugin.settings.defaultNotesFolder) + .onChange(async (value) => { + this.plugin.settings.defaultNotesFolder = value || ""; + await this.plugin.saveSettings(); + }) + ); + + // ============================================ + // 4. Unresolved Link Handling + // ============================================ + containerEl.createEl("h3", { text: "🔗 Unresolved Link Handling" }); + containerEl.createEl("p", { + text: "Konfiguration für das Verhalten bei Klicks auf nicht aufgelöste Links.", + cls: "setting-item-description", + }); + + // Intercept unresolved links new Setting(containerEl) .setName("Intercept unresolved link clicks") - .setDesc("Open profile selection when clicking unresolved internal links") + .setDesc( + "Aktiviert die Abfangen von Klicks auf nicht aufgelöste interne Links. Öffnet die Profilauswahl, wenn auf einen nicht existierenden Link geklickt wird." + ) .addToggle((toggle) => toggle .setValue(this.plugin.settings.interceptUnresolvedLinkClicks) @@ -223,10 +293,12 @@ export class MindnetSettingTab extends PluginSettingTab { }) ); - // Auto-start interview on unresolved click toggle + // Auto-start interview on unresolved click new Setting(containerEl) .setName("Auto-start interview on unresolved link click") - .setDesc("Automatically start interview wizard when creating note from unresolved link") + .setDesc( + "Startet automatisch den Interview-Wizard, wenn eine Notiz aus einem nicht aufgelösten Link erstellt wird. Erfordert, dass 'Intercept unresolved link clicks' aktiviert ist." + ) .addToggle((toggle) => toggle .setValue(this.plugin.settings.autoStartOnUnresolvedClick) @@ -239,7 +311,9 @@ export class MindnetSettingTab extends PluginSettingTab { // Bypass modifier (Reading View) new Setting(containerEl) .setName("Bypass modifier (Reading View)") - .setDesc("Modifier key to bypass unresolved link intercept in Reading View (Alt/Ctrl/Shift/None)") + .setDesc( + "Modifier-Taste zum Umgehen des Link-Intercepts in der Leseansicht. Wenn diese Taste gedrückt wird, wird der Standard-Link-Klick ausgeführt (z.B. zum Erstellen einer leeren Notiz)." + ) .addDropdown((dropdown) => dropdown .addOption("Alt", "Alt") @@ -258,7 +332,9 @@ export class MindnetSettingTab extends PluginSettingTab { // Editor follow modifier (Live Preview/Source) new Setting(containerEl) .setName("Editor follow modifier (Live Preview/Source)") - .setDesc("Modifier key required to intercept unresolved links in editor (Alt/Ctrl/Shift/None). Default: Ctrl/Cmd") + .setDesc( + "Modifier-Taste, die im Editor (Live Preview/Source) gedrückt werden muss, um den Link-Intercept zu aktivieren. Standard: Ctrl/Cmd. Verhindert versehentliche Intercepts beim normalen Bearbeiten." + ) .addDropdown((dropdown) => dropdown .addOption("Alt", "Alt") @@ -274,10 +350,21 @@ export class MindnetSettingTab extends PluginSettingTab { }) ); + // ============================================ + // 5. Templater Compatibility + // ============================================ + containerEl.createEl("h3", { text: "⚙️ Templater Compatibility" }); + containerEl.createEl("p", { + text: "Einstellungen für die Kompatibilität mit dem Templater-Plugin.", + cls: "setting-item-description", + }); + // Wait for first modify after create new Setting(containerEl) .setName("Wait for first modify after create") - .setDesc("Wait for Templater to modify file before starting wizard (recommended if using Templater)") + .setDesc( + "Wartet, bis Templater die Datei modifiziert hat, bevor der Wizard gestartet wird. Empfohlen, wenn Templater verwendet wird, um Konflikte zu vermeiden." + ) .addToggle((toggle) => toggle .setValue(this.plugin.settings.waitForFirstModifyAfterCreate) @@ -290,7 +377,9 @@ export class MindnetSettingTab extends PluginSettingTab { // Modify timeout new Setting(containerEl) .setName("Modify timeout (ms)") - .setDesc("Timeout in milliseconds for waiting for file modify event") + .setDesc( + "Timeout in Millisekunden für das Warten auf ein File-Modify-Event. Wenn Templater nicht innerhalb dieser Zeit reagiert, wird der Wizard trotzdem gestartet." + ) .addText((text) => text .setPlaceholder("1200") @@ -304,23 +393,21 @@ export class MindnetSettingTab extends PluginSettingTab { }) ); - // Debug logging - new Setting(containerEl) - .setName("Debug logging") - .setDesc("Enable debug logging for unresolved link handling") - .addToggle((toggle) => - toggle - .setValue(this.plugin.settings.debugLogging) - .onChange(async (value) => { - this.plugin.settings.debugLogging = value; - await this.plugin.saveSettings(); - }) - ); + // ============================================ + // 6. Note Adoption + // ============================================ + containerEl.createEl("h3", { text: "🔄 Note Adoption" }); + containerEl.createEl("p", { + text: "Einstellungen für die automatische Übernahme neu erstellter Notizen im Editor.", + cls: "setting-item-description", + }); // Adopt new notes in editor new Setting(containerEl) .setName("Adopt new notes in editor") - .setDesc("Automatically adopt newly created notes in editor and convert to Mindnet format") + .setDesc( + "Übernimmt automatisch neu erstellte Notizen im Editor und konvertiert sie in das Mindnet-Format (mit Frontmatter-ID). Nützlich, wenn Obsidian eine Notiz direkt erstellt, bevor unser Intercept greift." + ) .addToggle((toggle) => toggle .setValue(this.plugin.settings.adoptNewNotesInEditor) @@ -333,7 +420,9 @@ export class MindnetSettingTab extends PluginSettingTab { // Adopt max chars new Setting(containerEl) .setName("Adopt max chars") - .setDesc("Maximum content length to consider a note as adopt-candidate (default: 200)") + .setDesc( + "Maximale Inhaltslänge (in Zeichen), um eine Notiz als Übernahme-Kandidat zu betrachten. Leere oder sehr kurze Notizen werden bevorzugt übernommen." + ) .addText((text) => text .setPlaceholder("200") @@ -350,7 +439,9 @@ export class MindnetSettingTab extends PluginSettingTab { // Adopt confirm mode new Setting(containerEl) .setName("Adopt confirm mode") - .setDesc("When to show adoption confirmation: always, onlyLowConfidence (skip for high-confidence), or never") + .setDesc( + "Wann die Übernahme-Bestätigung angezeigt wird: 'Always ask' (immer fragen), 'Only for low confidence' (nur bei niedriger Konfidenz, überspringt bei hoher Konfidenz), oder 'Never ask' (nie fragen, automatisch übernehmen)." + ) .addDropdown((dropdown) => dropdown .addOption("always", "Always ask") @@ -368,7 +459,9 @@ export class MindnetSettingTab extends PluginSettingTab { // High confidence window new Setting(containerEl) .setName("High confidence window (ms)") - .setDesc("Time window in milliseconds for high-confidence adoption (default: 3000)") + .setDesc( + "Zeitfenster in Millisekunden für die hohe Konfidenz-Übernahme. Notizen, die innerhalb dieses Zeitfensters nach einem Klick erstellt wurden, werden mit hoher Konfidenz als Übernahme-Kandidaten betrachtet." + ) .addText((text) => text .setPlaceholder("3000") @@ -382,13 +475,21 @@ export class MindnetSettingTab extends PluginSettingTab { }) ); - // Semantic Mapping Builder section - containerEl.createEl("h2", { text: "Semantic Mapping Builder" }); + // ============================================ + // 7. Semantic Mapping Builder + // ============================================ + containerEl.createEl("h3", { text: "🕸️ Semantic Mapping Builder" }); + containerEl.createEl("p", { + text: "Einstellungen für den Semantic Mapping Builder, der automatisch Mapping-Blöcke in Notizen erstellt.", + cls: "setting-item-description", + }); // Wrapper callout type new Setting(containerEl) .setName("Mapping wrapper callout type") - .setDesc("Callout type for the mapping wrapper (e.g., 'abstract', 'info', 'note')") + .setDesc( + "Callout-Typ für den Mapping-Wrapper (z.B. 'abstract', 'info', 'note'). Bestimmt das visuelle Erscheinungsbild des Mapping-Blocks." + ) .addText((text) => text .setPlaceholder("abstract") @@ -402,7 +503,9 @@ export class MindnetSettingTab extends PluginSettingTab { // Wrapper title new Setting(containerEl) .setName("Mapping wrapper title") - .setDesc("Title text for the mapping wrapper callout") + .setDesc( + "Titel-Text für den Mapping-Wrapper-Callout. Wird als Überschrift des Mapping-Blocks angezeigt." + ) .addText((text) => text .setPlaceholder("🕸️ Semantic Mapping") @@ -416,7 +519,9 @@ export class MindnetSettingTab extends PluginSettingTab { // Wrapper folded new Setting(containerEl) .setName("Mapping wrapper folded") - .setDesc("Start with mapping wrapper callout folded (collapsed)") + .setDesc( + "Startet mit dem Mapping-Wrapper-Callout eingeklappt (collapsed). Reduziert visuellen Lärm in der Notiz." + ) .addToggle((toggle) => toggle .setValue(this.plugin.settings.mappingWrapperFolded) @@ -426,24 +531,12 @@ export class MindnetSettingTab extends PluginSettingTab { }) ); - // Default edge type - new Setting(containerEl) - .setName("Default edge type") - .setDesc("Default edge type for unmapped links (if unassignedHandling is 'defaultType')") - .addText((text) => - text - .setPlaceholder("") - .setValue(this.plugin.settings.defaultEdgeType) - .onChange(async (value) => { - this.plugin.settings.defaultEdgeType = value; - await this.plugin.saveSettings(); - }) - ); - // Unassigned handling new Setting(containerEl) .setName("Unassigned handling") - .setDesc("How to handle links without existing mappings: prompt (interactive), none, defaultType, or advisor") + .setDesc( + "Wie Links ohne bestehende Mappings behandelt werden: 'Prompt (interactive)' (interaktive Auswahl), 'None (skip unmapped)' (überspringen), 'Use default edge type' (Standard-Typ verwenden), oder 'Use advisor' (zukünftig: E1-Engine)." + ) .addDropdown((dropdown) => dropdown .addOption("prompt", "Prompt (interactive)") @@ -459,10 +552,28 @@ export class MindnetSettingTab extends PluginSettingTab { }) ); + // Default edge type + new Setting(containerEl) + .setName("Default edge type") + .setDesc( + "Standard-Edge-Typ für nicht zugeordnete Links. Wird nur verwendet, wenn 'Unassigned handling' auf 'Use default edge type' gesetzt ist." + ) + .addText((text) => + text + .setPlaceholder("") + .setValue(this.plugin.settings.defaultEdgeType) + .onChange(async (value) => { + this.plugin.settings.defaultEdgeType = value; + await this.plugin.saveSettings(); + }) + ); + // Allow overwrite existing mappings new Setting(containerEl) .setName("Allow overwrite existing mappings") - .setDesc("If enabled, will prompt to confirm before overwriting existing edge type assignments") + .setDesc( + "Wenn aktiviert, wird vor dem Überschreiben bestehender Edge-Typ-Zuordnungen eine Bestätigung angefordert. Wenn deaktiviert, werden bestehende Mappings immer beibehalten." + ) .addToggle((toggle) => toggle .setValue(this.plugin.settings.allowOverwriteExistingMappings) @@ -472,16 +583,26 @@ export class MindnetSettingTab extends PluginSettingTab { }) ); - // Default notes folder + // ============================================ + // 8. Debug & Development + // ============================================ + containerEl.createEl("h3", { text: "🐛 Debug & Development" }); + containerEl.createEl("p", { + text: "Einstellungen für Debugging und Entwicklung.", + cls: "setting-item-description", + }); + + // Debug logging new Setting(containerEl) - .setName("Default notes folder") - .setDesc("Default folder for new notes (vault-relative path, empty for root). Profile defaults take precedence.") - .addText((text) => - text - .setPlaceholder("") - .setValue(this.plugin.settings.defaultNotesFolder) + .setName("Debug logging") + .setDesc( + "Aktiviert ausführliches Debug-Logging für das Unresolved-Link-Handling. Logs erscheinen in der Browser-Konsole (F12). Nützlich für die Fehlersuche." + ) + .addToggle((toggle) => + toggle + .setValue(this.plugin.settings.debugLogging) .onChange(async (value) => { - this.plugin.settings.defaultNotesFolder = value || ""; + this.plugin.settings.debugLogging = value; await this.plugin.saveSettings(); }) );