AI-assistentie verhuist naar Uitbreidingen; het eigen tabblad verschijnt pas als de module aan staat #731

Closed
opened 2026-07-23 11:44:53 +00:00 by brenno · 5 comments
Owner

Wat

AI-assistentie staat nu als vast tabblad in de zijbalk van het instellingenvenster, tussen functies die altijd gelden. Het hoort thuis waar de andere optionele functionaliteit woont: het tabblad Uitbreidingen. Daar komt een module-kaart "AI-assistentie" bij, naast Informatieveiligheid. Wie de module dáár inschakelt, krijgt het losse tabblad AI-assistentie in de zijbalk terug; wie hem uit laat, ziet er niets van.

Dit versterkt de bestaande belofte van de Uitbreidingen-tab letterlijk: "Optionele modules. Standaard uit; ze blijven verborgen tot u ze inschakelt." AI ís zo'n module — optioneel, standaard uit, en met een netwerkuitgang die je bewust aanzet — maar staat nu als enige optionele functie permanent in beeld.

Hoe

1. De schakelaar: hergebruik AiSettings.enabled, geen nieuwe voorkeursleutel.
Het AI-tabblad heeft nu zelf een schakelaar "AI-assistentie inschakelen" (_ai.enabledAiSettings.enabled). Die schakelaar verhuist in betekenis naar de module-kaart op Uitbreidingen: de kaart lees- en schrijft AiSettings.enabled via de bestaande settingsProvider-weg. Het AI-tabblad zelf houdt dan alleen de configuratie (backend, model, sleutel, bevestiging) en verliest zijn eigen aan/uit-schakelaar — één schakelaar, één plek, geen twee knoppen die bijna hetzelfde zeggen.

Dit geeft de migratie gratis: bestaande gebruikers die AI al aan hebben, hebben enabled=true op schijf staan en houden hun tabblad zonder dat er iets te migreren valt.

2. Zichtbaarheid van het tabblad: het checklists-patroon, niet kaal verbergen.
SettingsSection.navItems() in lib/widgets/dialogs/parts/settings_dialog_sections.dart krijgt er een parameter bij en gate't SettingsSection.ai zoals hij checklists al gate't: tonen zodra de module aan staat óf er al inhoud is (ai.enabled || ai.isConfigured). De tweede voorwaarde is de vaste projectregel uit #648: wie een backend en sleutel configureerde en daarna de module uitzet, moet zijn configuratie kunnen blijven zien en opruimen — anders maakt de schakelaar bestaand werk onbereikbaar. Aanroeper: settings_dialog_chrome.dart regel ~83.

3. De module-kaart op Uitbreidingen.
In settings_dialog_modules.dart naast _informationSecurityCard een tweede kaart, zelfde vorm: SwitchListTile met titel, ondertitel die eerlijk zegt wat aanzetten betekent (er wordt pas iets verstuurd na configuratie én bevestiging van een backend; desktop-only), en bij ingeschakelde staat een regel die naar het tabblad wijst. Op web: kaart tonen maar uitgeschakeld met de bestaande desktopmelding — dezelfde tekst die het AI-tabblad nu op web toont.

Let op de doc-kop van lib/state/info_safety_provider.dart: die zegt expliciet dat het reveal-patroon dáár géén herbruikbaar moduleframework is en dat "een tweede module een echt register nodig heeft". Die tweede module is dit níet: AI heeft al zijn eigen state (AiSettings), dus er komt geen tweede kopie van het infoSafety-patroon en ook nog geen register. Wel: werk die doc-kop bij, want de belofte "bouw het register wanneer er een tweede module komt" verdient bij deze PR een bewust genoteerd besluit (register uitgesteld omdat beide modules hun eigen bestaande state dragen).

4. Zoekindex.
De vier AI-zoekingangen in settings_dialog_search_index.dart (regels ~300–320) wijzen naar SettingsSection.ai. Verborgen tabblad = dode zoektreffer. Het bestaande mechanisme is infoSafetyOnly + de filter in settings_dialog_search.dart regel ~161; generaliseer dat (bijv. een visibleWhen/tab-zichtbaarheidstoets) of voeg een parallelle aiOnly-vlag toe. De ingang "AI-assistentie inschakelen" verhuist naar tab: SettingsSection.modules, zodat zoeken naar "ai" altijd íets vindt — namelijk de plek waar je hem aanzet.

5. Wat er expliciet níet verandert.
De functionele poort blijft ai.enabled && ai.isConfigured (alt_text_field, ai_suggest_field, image_carousel_picker_actions) — die raakt dit niet. Ook de uitgaande-verkeer-bevestiging en het keychain-gedrag van het AI-tabblad blijven onaangeroerd.

Keten en kosten

  • l10n: nieuwe zichtbare teksten (kaarttitel/ondertitel, verwijsregel) → make add-l10n, 31 vertalingen per string. Reken op 3–4 strings.
  • Tests: dit is een gedragswijziging, dus de borging is nieuw: (a) tabblad AI afwezig bij verse instellingen, (b) aanwezig zodra de module aan gaat, (c) aanwezig bij enabled=false maar geconfigureerde backend, (d) zoekingangen volgen de zichtbaarheid. Spiegel info_safety_settings_test.dart; werk settings_ai_tab_test.dart, settings_search_test.dart en settings_dialog_smoke_test.dart bij.
  • Docs: USER_GUIDE.md en docs/design/AI_ASSIST.md beschrijven de huidige plek van de instelling; CHANGELOG. Geen nieuw docsbestand, dus geen registratiepoort.
  • Ratchets: settings_dialog_modules.dart groeit; kans dat het klasseplafond tript → top-level helper in dezelfde library, niet de basislijn omhoog.
  • Geen wijziging aan bestandsformaat, opslag of afhankelijkheden.

Waarom dit past

De kernwaarde is dat alles wat naar buiten kan praten opt-in en zichtbaar-als-keuze is. Een AI-tabblad dat er altijd staat suggereert een vaste functie; een module die je bewust bijschakelt zegt wat het is: een uitbreiding met een netwerkgevolg. De verplaatsing maakt de instellingen-zijbalk bovendien een tabblad korter voor iedereen die AI niet gebruikt — de meerderheid, gegeven standaard-uit.

## Wat AI-assistentie staat nu als vast tabblad in de zijbalk van het instellingenvenster, tussen functies die altijd gelden. Het hoort thuis waar de andere optionele functionaliteit woont: het tabblad **Uitbreidingen**. Daar komt een module-kaart "AI-assistentie" bij, naast Informatieveiligheid. Wie de module dáár inschakelt, krijgt het losse tabblad AI-assistentie in de zijbalk terug; wie hem uit laat, ziet er niets van. Dit versterkt de bestaande belofte van de Uitbreidingen-tab letterlijk: *"Optionele modules. Standaard uit; ze blijven verborgen tot u ze inschakelt."* AI ís zo'n module — optioneel, standaard uit, en met een netwerkuitgang die je bewust aanzet — maar staat nu als enige optionele functie permanent in beeld. ## Hoe **1. De schakelaar: hergebruik `AiSettings.enabled`, geen nieuwe voorkeursleutel.** Het AI-tabblad heeft nu zelf een schakelaar "AI-assistentie inschakelen" (`_ai.enabled` → `AiSettings.enabled`). Die schakelaar verhuist in betekenis naar de module-kaart op Uitbreidingen: de kaart lees- en schrijft `AiSettings.enabled` via de bestaande settingsProvider-weg. Het AI-tabblad zelf houdt dan alleen de configuratie (backend, model, sleutel, bevestiging) en verliest zijn eigen aan/uit-schakelaar — één schakelaar, één plek, geen twee knoppen die bijna hetzelfde zeggen. Dit geeft de migratie gratis: bestaande gebruikers die AI al aan hebben, hebben `enabled=true` op schijf staan en houden hun tabblad zonder dat er iets te migreren valt. **2. Zichtbaarheid van het tabblad: het checklists-patroon, niet kaal verbergen.** `SettingsSection.navItems()` in `lib/widgets/dialogs/parts/settings_dialog_sections.dart` krijgt er een parameter bij en gate't `SettingsSection.ai` zoals hij checklists al gate't: **tonen zodra de module aan staat óf er al inhoud is** (`ai.enabled || ai.isConfigured`). De tweede voorwaarde is de vaste projectregel uit #648: wie een backend en sleutel configureerde en daarna de module uitzet, moet zijn configuratie kunnen blijven zien en opruimen — anders maakt de schakelaar bestaand werk onbereikbaar. Aanroeper: `settings_dialog_chrome.dart` regel ~83. **3. De module-kaart op Uitbreidingen.** In `settings_dialog_modules.dart` naast `_informationSecurityCard` een tweede kaart, zelfde vorm: SwitchListTile met titel, ondertitel die eerlijk zegt wat aanzetten betekent (er wordt pas iets verstuurd na configuratie én bevestiging van een backend; desktop-only), en bij ingeschakelde staat een regel die naar het tabblad wijst. Op web: kaart tonen maar uitgeschakeld met de bestaande desktopmelding — dezelfde tekst die het AI-tabblad nu op web toont. Let op de doc-kop van `lib/state/info_safety_provider.dart`: die zegt expliciet dat het reveal-patroon dáár géén herbruikbaar moduleframework is en dat "een tweede module een echt register nodig heeft". Die tweede module is dit níet: AI heeft al zijn eigen state (`AiSettings`), dus er komt geen tweede kopie van het infoSafety-patroon en ook nog geen register. Wel: werk die doc-kop bij, want de belofte "bouw het register wanneer er een tweede module komt" verdient bij deze PR een bewust genoteerd besluit (register uitgesteld omdat beide modules hun eigen bestaande state dragen). **4. Zoekindex.** De vier AI-zoekingangen in `settings_dialog_search_index.dart` (regels ~300–320) wijzen naar `SettingsSection.ai`. Verborgen tabblad = dode zoektreffer. Het bestaande mechanisme is `infoSafetyOnly` + de filter in `settings_dialog_search.dart` regel ~161; generaliseer dat (bijv. een `visibleWhen`/tab-zichtbaarheidstoets) of voeg een parallelle `aiOnly`-vlag toe. De ingang "AI-assistentie inschakelen" verhuist naar `tab: SettingsSection.modules`, zodat zoeken naar "ai" altijd íets vindt — namelijk de plek waar je hem aanzet. **5. Wat er expliciet níet verandert.** De functionele poort blijft `ai.enabled && ai.isConfigured` (alt_text_field, ai_suggest_field, image_carousel_picker_actions) — die raakt dit niet. Ook de uitgaande-verkeer-bevestiging en het keychain-gedrag van het AI-tabblad blijven onaangeroerd. ## Keten en kosten - **l10n:** nieuwe zichtbare teksten (kaarttitel/ondertitel, verwijsregel) → `make add-l10n`, 31 vertalingen per string. Reken op 3–4 strings. - **Tests:** dit is een gedragswijziging, dus de borging is nieuw: (a) tabblad AI afwezig bij verse instellingen, (b) aanwezig zodra de module aan gaat, (c) aanwezig bij `enabled=false` maar geconfigureerde backend, (d) zoekingangen volgen de zichtbaarheid. Spiegel `info_safety_settings_test.dart`; werk `settings_ai_tab_test.dart`, `settings_search_test.dart` en `settings_dialog_smoke_test.dart` bij. - **Docs:** USER_GUIDE.md en docs/design/AI_ASSIST.md beschrijven de huidige plek van de instelling; CHANGELOG. Geen nieuw docsbestand, dus geen registratiepoort. - **Ratchets:** `settings_dialog_modules.dart` groeit; kans dat het klasseplafond tript → top-level helper in dezelfde library, niet de basislijn omhoog. - Geen wijziging aan bestandsformaat, opslag of afhankelijkheden. ## Waarom dit past De kernwaarde is dat alles wat naar buiten kan praten opt-in en zichtbaar-als-keuze is. Een AI-tabblad dat er altijd staat suggereert een vaste functie; een module die je bewust bijschakelt zegt wat het is: een uitbreiding met een netwerkgevolg. De verplaatsing maakt de instellingen-zijbalk bovendien een tabblad korter voor iedereen die AI niet gebruikt — de meerderheid, gegeven standaard-uit.
Author
Owner

Halverwege, en ik leg hem terug. De code staat op tak feat/ai-als-module-731 (0ab89f23), analyseert schoon, maar de tests draaien niet. Ik kom er niet uit binnen redelijke tijd en laat hem liever zichtbaar liggen dan er nog uren in te steken.

Wat af is — alle vijf onderdelen uit je plan:

  1. Modulekaart op Uitbreidingen, naast Informatieveiligheid, met de web-uitgeschakelde variant.
  2. De schakelaar is weg uit het AI-tabblad; daar staat nu een verwijzing naar Uitbreidingen wanneer de module uit is.
  3. SettingsSection.navItems() gate't het AI-tabblad zoals hij de checklists al gate't.
  4. Zoekindex: de inschakel-ingang wijst naar SettingsSection.modules, de andere drie dragen aiOnly en volgen de zichtbaarheid.
  5. De doc-kop van info_safety_provider.dart draagt het uitgestelde-registerbesluit, met de reden en met wanneer het wél moet.

Twee dingen die het plan niet kon weten, en die ik anders heb gedaan:

AiSettings.isConfigured bevat zélf al enabled — de definitie is enabled && mode != none && baseUrl.isNotEmpty. De voorgestelde toets ai.enabled || ai.isConfigured is dus een tautologie: met de module uit is isConfigured onwaar, en zou het tabblad juist verdwijnen — precies wat #648 wil voorkomen. Er is nu een hasBackend die los van de schakelaar staat, en de toets is enabled || hasBackend.

De kaart kan niet rechtstreeks naar de provider schrijven. AiForm.save schrijft het hele formulier bij Opslaan weg, inclusief enabled; een kaart die meteen naar de voorkeuren schrijft wordt door die Opslaan teruggedraaid. De kaart bedient daarom hetzelfde formulierveld — één schakelaar, één opslagpad — en de zichtbaarheid leest het formulier, zodat het tabblad meteen verschijnt en niet pas na Opslaan.

Waar ik vastloop. test/settings_ai_tab_test.dart opende het AI-tabblad rechtstreeks; dat kan niet meer met de module uit. Ik heb de opstelling omgelegd — openen op Uitbreidingen, schakelaar om, dan naar het tabblad — en drie nieuwe toetsen geschreven die slagen:

  • met de module uit is er geen AI-tabblad;
  • aanzetten laat het verschijnen;
  • een ingestelde backend houdt het tabblad ook met de module uit, mét de uitleg erboven.

Maar élke toets die ná het omzetten op het tabblad tikt, hangt: meer dan zes minuten zonder resultaat. Het ligt niet aan het wachten (ook met begrensde pump-lussen in plaats van pumpAndSettle blijft het hangen), en niet aan ensureVisible (weggehaald). Tikken op het tabblad wérkt wanneer het al bij het openen bestond — alleen de combinatie omzetten-dán-tikken loopt vast. Ik heb de oorzaak niet gevonden.

Wat er dus nog moet: die hang uitzoeken, en daarna de resterende keten — l10n voor de drie à vier nieuwe strings, settings_search_test.dart en settings_dialog_smoke_test.dart bijwerken, en USER_GUIDE + AI_ASSIST + CHANGELOG.

Ik haal het in-progress-label eraf zodat een andere sessie hem kan oppakken.

**Halverwege, en ik leg hem terug.** De code staat op tak `feat/ai-als-module-731` (`0ab89f23`), analyseert schoon, maar de tests draaien niet. Ik kom er niet uit binnen redelijke tijd en laat hem liever zichtbaar liggen dan er nog uren in te steken. **Wat af is — alle vijf onderdelen uit je plan:** 1. Modulekaart op Uitbreidingen, naast Informatieveiligheid, met de web-uitgeschakelde variant. 2. De schakelaar is weg uit het AI-tabblad; daar staat nu een verwijzing naar Uitbreidingen wanneer de module uit is. 3. `SettingsSection.navItems()` gate't het AI-tabblad zoals hij de checklists al gate't. 4. Zoekindex: de inschakel-ingang wijst naar `SettingsSection.modules`, de andere drie dragen `aiOnly` en volgen de zichtbaarheid. 5. De doc-kop van `info_safety_provider.dart` draagt het uitgestelde-registerbesluit, met de reden en met wanneer het wél moet. **Twee dingen die het plan niet kon weten, en die ik anders heb gedaan:** **`AiSettings.isConfigured` bevat zélf al `enabled`** — de definitie is `enabled && mode != none && baseUrl.isNotEmpty`. De voorgestelde toets `ai.enabled || ai.isConfigured` is dus een tautologie: met de module uit is `isConfigured` onwaar, en zou het tabblad juist verdwijnen — precies wat #648 wil voorkomen. Er is nu een `hasBackend` die los van de schakelaar staat, en de toets is `enabled || hasBackend`. **De kaart kan niet rechtstreeks naar de provider schrijven.** `AiForm.save` schrijft het hele formulier bij Opslaan weg, inclusief `enabled`; een kaart die meteen naar de voorkeuren schrijft wordt door die Opslaan teruggedraaid. De kaart bedient daarom hetzelfde formulierveld — één schakelaar, één opslagpad — en de zichtbaarheid leest het formulier, zodat het tabblad meteen verschijnt en niet pas na Opslaan. **Waar ik vastloop.** `test/settings_ai_tab_test.dart` opende het AI-tabblad rechtstreeks; dat kan niet meer met de module uit. Ik heb de opstelling omgelegd — openen op Uitbreidingen, schakelaar om, dan naar het tabblad — en drie nieuwe toetsen geschreven die slagen: - met de module uit is er geen AI-tabblad; - aanzetten laat het verschijnen; - een ingestelde backend houdt het tabblad ook met de module uit, mét de uitleg erboven. Maar élke toets die ná het omzetten op het tabblad tikt, hangt: meer dan zes minuten zonder resultaat. Het ligt niet aan het wachten (ook met begrensde `pump`-lussen in plaats van `pumpAndSettle` blijft het hangen), en niet aan `ensureVisible` (weggehaald). Tikken op het tabblad wérkt wanneer het al bij het openen bestond — alleen de combinatie omzetten-dán-tikken loopt vast. Ik heb de oorzaak niet gevonden. **Wat er dus nog moet:** die hang uitzoeken, en daarna de resterende keten — l10n voor de drie à vier nieuwe strings, `settings_search_test.dart` en `settings_dialog_smoke_test.dart` bijwerken, en USER_GUIDE + AI_ASSIST + CHANGELOG. Ik haal het in-progress-label eraf zodat een andere sessie hem kan oppakken.
Author
Owner

Opgepakt (vervolg op het teruggelegde werk). Tak: feat/ai-als-module-731, verder vanaf 0ab89f23. Eerst de hangende tabtoetsen uitzoeken, dan l10n, settings_search_test/settings_dialog_smoke_test en de docs.

Opgepakt (vervolg op het teruggelegde werk). Tak: feat/ai-als-module-731, verder vanaf 0ab89f23. Eerst de hangende tabtoetsen uitzoeken, dan l10n, settings_search_test/settings_dialog_smoke_test en de docs.
Author
Owner

Opgepakt. Tak: feat/ai-als-module-731 (gerebased op main). De hang was zelfaanroep in de testhulp moduleAanEnNaarTab — hij riep zichzelf aan in plaats van de schakelaar te tikken; analyse ziet dat niet in een Future. Alle 11 toetsen in settings_ai_tab_test slagen. Rest van de keten volgt: l10n, settings_search_test, settings_dialog_smoke_test, USER_GUIDE + AI_ASSIST + CHANGELOG.

Opgepakt. Tak: feat/ai-als-module-731 (gerebased op main). De hang was zelfaanroep in de testhulp `moduleAanEnNaarTab` — hij riep zichzelf aan in plaats van de schakelaar te tikken; analyse ziet dat niet in een Future. Alle 11 toetsen in settings_ai_tab_test slagen. Rest van de keten volgt: l10n, settings_search_test, settings_dialog_smoke_test, USER_GUIDE + AI_ASSIST + CHANGELOG.
Author
Owner

Af, op main: 1e089969 (PR #752), daar geverifieerd. Alle vijf onderdelen uit het plan plus de twee afwijkingen die het teruggelegde werk al noemde (hasBackend i.p.v. de tautologie; de kaart bedient het formulier). De hang bleek oneindige recursie in de testhelper — moduleAanEnNaarTab riep op regel 100 zichzelf aan — dus geen Flutter-mysterie; de gerepareerde suite draait in 6 seconden. Verder: AiModuleCard/AiModuleOffNotice als losse widgets (klasseplafond mee omlaag naar 5989), sectie-anker op de zoekingang, 3 strings × 31 talen, docs bijgewerkt. Wat er níét in zat: niets uit de issue-tekst. Poort: make check groen (6.041 tests), check-secrets en sast schoon.

Af, op main: 1e089969 (PR #752), daar geverifieerd. Alle vijf onderdelen uit het plan plus de twee afwijkingen die het teruggelegde werk al noemde (hasBackend i.p.v. de tautologie; de kaart bedient het formulier). De hang bleek oneindige recursie in de testhelper — moduleAanEnNaarTab riep op regel 100 zichzelf aan — dus geen Flutter-mysterie; de gerepareerde suite draait in 6 seconden. Verder: AiModuleCard/AiModuleOffNotice als losse widgets (klasseplafond mee omlaag naar 5989), sectie-anker op de zoekingang, 3 strings × 31 talen, docs bijgewerkt. Wat er níét in zat: niets uit de issue-tekst. Poort: make check groen (6.041 tests), check-secrets en sast schoon.
Author
Owner

Nasleep gemerged: c5f1b487 (PR #757), op main geverifieerd. Vier losse einden die na 1e089969 bleven liggen — PRIVACY.md en FAQ.md wezen nog naar 'Settings → AI Assistant' (een tabblad dat er zonder de module niet meer is, en juist in de twee documenten over toestemming en uitgaand verkeer); de l10n-sleutel 'AI-assistentie inschakelen' was een wees in 31 talen; 'enabled || hasBackend' stond drie keer los en is nu AiForm.revealsTab; en drie regressietoetsen ontbraken — niets toetste de aiOnly-filter op de zoekingangen, en niets zette de twee modules tegen elkaar in. Beide mutaties één keer rood gezien.

Ter aantekening: ik werkte parallel aan dezelfde issue en vond de hang onafhankelijk (zelfaanroep in moduleAanEnNaarTab). Mijn eigen tak is weggegooid, niet als tweede PR ingediend; hierboven staat alleen wat main nog miste. De claimreacties stonden één minuut uit elkaar, dus het claimen hielp hier niet — we hadden allebei al gewerkt vóór we claimden. Iets om aan de werkwijze te wegen, geen bevinding over deze issue.

Poort: make check groen, check-secrets en sast schoon, gerebased op 159ebd9d en opnieuw getoetst. Het in-progress-label is eraf; de issue blijft dicht.

Nasleep gemerged: c5f1b487 (PR #757), op main geverifieerd. Vier losse einden die na 1e089969 bleven liggen — PRIVACY.md en FAQ.md wezen nog naar 'Settings → AI Assistant' (een tabblad dat er zonder de module niet meer is, en juist in de twee documenten over toestemming en uitgaand verkeer); de l10n-sleutel 'AI-assistentie inschakelen' was een wees in 31 talen; 'enabled || hasBackend' stond drie keer los en is nu AiForm.revealsTab; en drie regressietoetsen ontbraken — niets toetste de aiOnly-filter op de zoekingangen, en niets zette de twee modules tegen elkaar in. Beide mutaties één keer rood gezien. Ter aantekening: ik werkte parallel aan dezelfde issue en vond de hang onafhankelijk (zelfaanroep in moduleAanEnNaarTab). Mijn eigen tak is weggegooid, niet als tweede PR ingediend; hierboven staat alleen wat main nog miste. De claimreacties stonden één minuut uit elkaar, dus het claimen hielp hier niet — we hadden allebei al gewerkt vóór we claimden. Iets om aan de werkwijze te wegen, geen bevinding over deze issue. Poort: make check groen, check-secrets en sast schoon, gerebased op 159ebd9d en opnieuw getoetst. Het in-progress-label is eraf; de issue blijft dicht.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
LibreKAT/Ocideck#731
No description provided.