diff --git a/docs/CODEX_EXECUTION_LOG.md b/docs/CODEX_EXECUTION_LOG.md index f81fcb03..d867a96f 100644 --- a/docs/CODEX_EXECUTION_LOG.md +++ b/docs/CODEX_EXECUTION_LOG.md @@ -12195,4 +12195,26 @@ Open: - Production smoke passed: container healthy, PostGIS 3.6, Alembic `202607260001 (head)`, frontend/API/icon runtime verification green. - Mobile production route at 415 x 899 verified: selecting the work area does not start analysis; `Analyseer selectie` remains disabled until a theme/model is chosen; one chosen theme yields `1/1 uitgelezen`; the slide-out results drawer opens and closes through its accessible toggle. - Layout acceptance: document horizontal overflow `0`; theme-panel horizontal overflow `0`; browser console errors and warnings `0`. -- Corrected a global `button:active` transform collision that moved the mobile drawer toggle between pointer-down and pointer-up. \ No newline at end of file +- Corrected a global `button:active` transform collision that moved the mobile drawer toggle between pointer-down and pointer-up. +## 2026-08-01 - Sprint 236 platformbrede UI/UX-herwerking + +### Gewijzigd +- Centrale `ModelSelector` met native dialoog, eenvoudige aanbevolen keuze, geavanceerde concrete modellen, echte runtimebeschikbaarheid en optionele technische details. +- AI-vragen bewaren een versiegebonden voorkeur; een verdwenen model valt veilig terug op de beschikbare serverstandaard zonder een ongeldige model-ID te verzenden. +- Detectie en segmentatie gebruiken hetzelfde selectiepatroon en behouden hun bestaande API-contracten en `not_configured`-gedrag. +- Kaartwerkruimte kreeg themazoeken, een bredere leesbare configuratiekolom, rustigere contextbalk en responsive panelafmetingen. +- Interactieve elementen zijn semantisch gescheiden; focus, Escape, native dialoogfocus, reduced motion en mobiele bottom-sheetpresentatie zijn voorzien. + +### Getest +- Frontend: 16 testbestanden, 51 tests geslaagd. +- Frontend: TypeScript- en Vite-productiebuild geslaagd; `git diff --check` geslaagd. +- Backend: 1.178 tests geslaagd; 19 bestaande stringgebaseerde contracttests falen op eerder gewijzigde repositoryverwachtingen. Meerdere verwachten opnieuw automatische kaartanalyse en mogen daarom niet worden hersteld zonder de actuele expliciete-startbeslissing te breken. + +### Open / beperking +- Visuele browseracceptatie en productie-uitrol volgen op de gecommitte wijziging tegen de echte serverruntime; de lokale frontend kan zonder backend-sessie alleen de voorbereidingsstatus tonen. +### Visuele acceptatie +- Echte serverdata via de lokale frontendpreview gevalideerd op 1920x1080, 1024x768 en 390x844. +- Desktop, tablet en mobiel: documentoverflow `0`; themapaneeloverflow `0`. +- Mobiele hoofdflow: thema zoeken, kiezen, volledig werkgebied selecteren, expliciet analyseren, resultatenlade openen en sluiten geslaagd. +- Browserconsole: `0` waarschuwingen en `0` fouten. +- Bewijsbeelden: `docs/screenshots/ui-ux-map-desktop-2026-08-01.jpg` en `docs/screenshots/ui-ux-map-mobile-results-2026-08-01.jpg`. \ No newline at end of file diff --git a/docs/TODO.md b/docs/TODO.md index 8a6a2434..b858e39f 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -1054,4 +1054,15 @@ This file now starts with the current implementation status. Older preparation/b - [x] Beperk de analysequery tot uitsluitend de gekozen thema’s. - [x] Herstel Inzichten als open- en sluitbare lade boven de kaart. - [x] Verkort bronteksten en voorkom overflow in de themakolom. -- [x] Verifieer TypeScript-build, frontend-unitset en responsive runtime visueel. \ No newline at end of file +- [x] Verifieer TypeScript-build, frontend-unitset en responsive runtime visueel. +## Sprint 236 - Platformbrede UI/UX-herwerking (2026-08-01) + +- [x] Eén herbruikbare taakgerichte modelselector voor lokale AI, detectie en segmentatie. +- [x] Automatisch aanbevolen lokale assistentkeuze met persistente, gevalideerde voorkeur en runtimefallback. +- [x] Alleen werkelijk door backend/runtime gerapporteerde modellen en metadata tonen. +- [x] Loading-, empty-, unavailable- en errorstates plus toetsenbord- en dialogbediening. +- [x] Zoekbare en bredere kaartthemalijst met volledig leesbare labels. +- [x] Compacte analysecontextbalk en rustige desktop/tablet/mobiele hiërarchie. +- [x] Uitschuifbare inzichten behouden; analyse blijft uitsluitend expliciet na themakeuze. +- [x] 51 frontendtests en productiebuild groen. +- [ ] 19 verouderde broncode-stringtests herijken; meerdere eisen daarin (automatische analyse) conflicteren bewust met de actuele productbeslissing. \ No newline at end of file diff --git a/docs/screenshots/ui-ux-map-desktop-2026-08-01.jpg b/docs/screenshots/ui-ux-map-desktop-2026-08-01.jpg new file mode 100644 index 00000000..6493a3ae Binary files /dev/null and b/docs/screenshots/ui-ux-map-desktop-2026-08-01.jpg differ diff --git a/docs/screenshots/ui-ux-map-mobile-results-2026-08-01.jpg b/docs/screenshots/ui-ux-map-mobile-results-2026-08-01.jpg new file mode 100644 index 00000000..0e59322b Binary files /dev/null and b/docs/screenshots/ui-ux-map-mobile-results-2026-08-01.jpg differ diff --git a/frontend/src/components/assistant/GeoAssistantPanel.tsx b/frontend/src/components/assistant/GeoAssistantPanel.tsx index df703c59..71494b0d 100644 --- a/frontend/src/components/assistant/GeoAssistantPanel.tsx +++ b/frontend/src/components/assistant/GeoAssistantPanel.tsx @@ -1,5 +1,6 @@ import { useState } from 'react' import { useGeoAssistant } from '../../hooks/useGeoAssistant' +import { ModelSelector, type ModelSelectionOption } from '../models/ModelSelector' import type { VectorSelectionBBox } from '../../types' interface GeoAssistantPanelProps { @@ -9,6 +10,32 @@ interface GeoAssistantPanelProps { selectionBbox: VectorSelectionBBox | null } + +function friendlyModelName(name: string): string { + const base = name.split(':')[0].replace(/[-_]+/g, ' ') + return base.replace(/\b\w/g, (character) => character.toUpperCase()) +} + +function toAssistantModelOption(model: import('../../types').AssistantModelRead): ModelSelectionOption { + const parameterText = model.parameter_size?.toLowerCase() ?? '' + const parameterCount = Number.parseFloat(parameterText) + const tone = Number.isFinite(parameterCount) && parameterCount <= 9 ? 'fast' : 'analytical' + return { + id: model.name, + name: friendlyModelName(model.name), + description: model.parameter_size ? `Lokaal taalmodel van ${model.parameter_size}.` : 'Lokaal beschikbaar taalmodel.', + recommendation: tone === 'fast' ? 'Voor vlotte samenvattingen en gerichte gebiedsvragen.' : 'Voor uitgebreidere interpretatie van meerdere bronnen.', + status: 'available', + statusLabel: 'Beschikbaar', + tone, + provider: 'Ollama', + environment: 'Lokale uitvoering', + speed: tone === 'fast' ? 'Vlot' : undefined, + capability: tone === 'analytical' ? 'Grondig' : 'Gebalanceerd', + technicalName: model.name, + details: [model.parameter_size ? `Omvang: ${model.parameter_size}` : '', model.quantization_level ? `Quantisatie: ${model.quantization_level}` : ''].filter(Boolean), + } +} const SUGGESTIONS = [ 'Vat de belangrijkste gebiedsmetingen samen.', 'Hoe evolueerden bevolking en bosoppervlakte?', @@ -27,6 +54,8 @@ export function GeoAssistantPanel({ status, models, selectedModel, + selectedModelChoice, + defaultModel, messages, loading, loadingModels, @@ -65,20 +94,27 @@ export function GeoAssistantPanel({ Context {scopeLabel} - - + void loadModels()} + advancedLabel="Geavanceerde modelkeuze" + /> {!selectedProjectId ? ( diff --git a/frontend/src/components/detection/DetectionLab.tsx b/frontend/src/components/detection/DetectionLab.tsx index 96ee5930..e004b1f8 100644 --- a/frontend/src/components/detection/DetectionLab.tsx +++ b/frontend/src/components/detection/DetectionLab.tsx @@ -14,6 +14,8 @@ import type { DetectionCalibrationRunRow, DetectionWorkflowStage } from '../../h import { DETECTION_OPERATOR_PROFILES, type DetectionOperatorProfile } from './detectionProfiles' import { DetectionModelManagement, detectionModelLabel } from './DetectionModelManagement' import { AiPipelineIllustration } from './AiPipelineIllustration' +import { ModelSelector } from '../models/ModelSelector' +import { toAnalysisModelOption } from '../models/modelOptions' const DETECTION_PAGE_SIZE_OPTIONS = [25, 50, 100] as const const DEFAULT_DETECTION_PAGE_SIZE = 50 @@ -461,16 +463,15 @@ export function DetectionLab({ ))} - +