+ {[0, 1, 2, 3].map(i => (
+
i ? styles.stepDotDone : '',
+ !visibleSteps.includes(i) ? styles.stepDotHidden : '',
+ ].join(' ')}
+ >
+ {state.step > i ? : i + 1}
+
+ ))}
+
+
+
+ {/* ---- Step 0: Connector ---- */}
+ {state.step === 0 && (
+
+
Anbieter wählen
+
Welchen Dienst möchtest du verbinden?
+
+ {(['google', 'msft', 'clickup'] as ConnectorType[]).map(type => (
+ setConnector(type)}
+ >
+ {CONNECTOR_ICONS[type]}
+ {CONNECTOR_LABELS[type]}
+
+ ))}
+
+
+ )}
+
+ {/* ---- Step 1: Consent ---- */}
+ {state.step === 1 && (
+
+
+
Wissensdatenbank
+
+ Möchtest du Inhalte aus dieser Verbindung in deine persönliche
+ Wissensdatenbank aufnehmen, damit die KI beim Antworten auf Informationen
+ aus{' '}
+ {state.connector ? CONNECTOR_LABELS[state.connector] : 'diesem Dienst'}{' '}
+ zurückgreifen kann?
+
+
+ Du kannst diese Einstellung später in den Verbindungsdetails ändern.
+
+
+ setKnowledgeEnabled(true)}
+ >
+ Ja, aufnehmen
+
+ setKnowledgeEnabled(false)}
+ >
+ Nein, überspringen
+
+
+
+ setStep(0)}>
+ Zurück
+
+
+
+ )}
+
+ {/* ---- Step 2: Preferences ---- */}
+ {state.step === 2 && (
+
+
Einstellungen
+
+ Steuere, welche Inhalte und in welcher Form sie indexiert werden.
+
+
+
+
+
+ Anonymisierung vor dem Indexieren
+ updatePref('neutralizeBeforeEmbed', e.target.checked)}
+ className={styles.prefCheck}
+ />
+
+
+ Persönliche Daten (Namen, E-Mail-Adressen) werden vor dem Speichern ersetzt.
+
+
+
+ {(state.connector === 'google' || state.connector === 'msft') && (
+ <>
+
+
+ E-Mail-Inhalt
+ updatePref('mailContentDepth', e.target.value as any)}
+ className={styles.prefSelect}
+ >
+ Nur Metadaten (Betreff, Absender, Datum)
+ Vorschautext (ca. 250 Zeichen)
+ Vollständiger Text
+
+
+
+
+
+ E-Mail-Anhänge indexieren
+ updatePref('mailIndexAttachments', e.target.checked)}
+ className={styles.prefCheck}
+ />
+
+
+ >
+ )}
+
+ {state.connector === 'clickup' && (
+
+
+ Aufgaben-Inhalt
+ updatePref('clickupScope', e.target.value as any)}
+ className={styles.prefSelect}
+ >
+ Nur Aufgabentitel
+ Titel + Beschreibung
+ Titel + Beschreibung + Kommentare
+
+
+
+ )}
+
+
+
+ Zeitfenster (Tage)
+ updatePref('maxAgeDays', parseInt(e.target.value, 10) || 0)}
+ className={styles.prefNumber}
+ />
+
+
0 = kein Limit
+
+
+
+ setStep(1)}>
+ Zurück
+
+ setStep(3)}>
+ Weiter
+
+
+
+ )}
+
+ {/* ---- Step 3: Summary ---- */}
+ {state.step === 3 && (
+
+
Zusammenfassung
+
+
+ Anbieter
+
+ {CONNECTOR_ICONS[state.connector!]}
+ {state.connector ? CONNECTOR_LABELS[state.connector] : '—'}
+
+
+
+ Wissensdatenbank
+
+ {state.knowledgeEnabled ? '✓ Aktiv' : '✗ Nicht aktiv'}
+
+
+ {state.knowledgeEnabled && (
+ <>
+
+ Anonymisierung
+
+ {state.prefs.neutralizeBeforeEmbed ? 'Ja' : 'Nein'}
+
+
+ {(state.connector === 'google' || state.connector === 'msft') && (
+
+ E-Mail-Tiefe
+
+ {{ metadata: 'Nur Metadaten', snippet: 'Vorschautext', full: 'Volltext' }[
+ state.prefs.mailContentDepth ?? 'full'
+ ] ?? state.prefs.mailContentDepth}
+
+
+ )}
+ {state.connector === 'clickup' && (
+
+ Aufgaben-Inhalt
+
+ {{
+ titles: 'Nur Titel',
+ title_description: 'Titel + Beschreibung',
+ with_comments: 'Titel + Beschreibung + Kommentare',
+ }[state.prefs.clickupScope ?? 'title_description'] ?? state.prefs.clickupScope}
+
+
+ )}
+
+ Zeitfenster
+
+ {state.prefs.maxAgeDays ? `${state.prefs.maxAgeDays} Tage` : 'Unbegrenzt'}
+
+
+ >
+ )}
+
+
+ {/* Cost estimate — only shown when knowledge ingestion is enabled */}
+ {state.knowledgeEnabled && (() => {
+ const est = computeCostEstimate(state.connector, state.prefs);
+ if (!est) return null;
+ return (
+
+
+
+
Geschätzte Kosten (erster Sync)
+
+
+
+ Embedding
+
+ {est.embeddingLow} – {est.embeddingHigh}
+
+
+ {est.neutralizationLow && (
+
+ Anonymisierung (Private LLM)
+
+ {est.neutralizationLow} – {est.neutralizationHigh}
+
+
+ )}
+
+
+ {est.neutralizationLow && (
+
+ ⚠ Anonymisierung ist der Hauptkostentreiber (CHF 0.01 pro LLM-Aufruf, on-premise).
+
+ )}
+
{est.note}
+
+
+ );
+ })()}
+
+
+ setStep(state.knowledgeEnabled ? 2 : 1)}
+ >
+ Zurück
+
+
+ {isConnecting ? 'Verbinden…' : `Mit ${state.connector ? CONNECTOR_LABELS[state.connector] : '…'} verbinden`}
+ {!isConnecting && }
+
+
+
+ )}
+
+