Commit graph

18 commits

Author SHA1 Message Date
flemming-it
f90d8cc7a7 feat(studio): typed run-flow form, file picker, copyable errors (v0.41.0)
The free-form key=value run-flow dialog produced two
unhelpful failures every time an operator hit Run:

  1. Submit empty → "step references missing value
     '\$inputs.document'" from the hub. Studio sent a zero-
     entry inputs map because nothing told the operator the
     flow declared a required input.
  2. Type `document=@/path/to/file` → "path not found".
     Dart's `File()` doesn't expand `~`, and on macOS
     sandboxed Studio can't read arbitrary paths anyway.

Both failure modes are gone. The dialog is now a typed form:

- On open, fetches `getFlowDefinition(name)` (new SDK
  v0.15.0 wrapper around the v0.10.89 hub RPC). While that
  resolves, a small spinner shows
  "Loading inputs…"; on failure, an inline `FaiErrorBox`
  with the exact RPC error and a copy button replaces the
  spinner.
- Renders one form-field per declared input. The flow
  YAML's verbatim type tag drives the widget choice:
  `bytes` / `file` → "Choose file…" button + picked-file
  readout, plain TextField for everything else. The type
  tag is shown next to the input name as a pill so a flow
  author who picks a less-common type still gets a hint.
- Bytes inputs route through `file_picker` with
  `withData: true`, which means the OS file dialog handles
  read access — sandboxed Studio gets the bytes inline
  rather than a path it can't open. Falls back to
  `File(path).readAsBytes()` on Linux configs that don't
  honour `withData` for large files; failures show a
  copyable SnackBar.
- The Run button enables only when every declared input has
  a value (text non-empty / file picked). Empty submission
  is impossible; the cryptic hub-side
  "missing value" error stops surfacing.
- The run-result dialog's error path uses `FaiErrorBox`
  instead of the previous plain `SelectableText`, so any
  hub-side flow error (permission denied, module crash,
  whatever) is one click to clipboard.

11 new ARB keys cover the form's labels, the file-picker
states, the loading / failed-definition messages, the
"This flow declares no inputs" empty state, and the
run-error dialog title.

`file_picker: ^8.0.0` added to pubspec.yaml.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-09 10:18:08 +02:00
flemming-it
63e19974c0 feat(studio): @-syntax file inputs in flows, copyable doc errors, services-row overflow (v0.40.0)
Three concrete fixes against today's user feedback.

- Flows that take binary inputs (extract / extract-summarize /
  …) work from the Flows tab. The run-flow input dialog now
  accepts the same `@/path/to/file` syntax `fai run --input`
  uses on the CLI: any value beginning with `@` is read as
  bytes and sent as a binary Payload; plain values still flow
  through as text. The dialog hint copy and the example
  placeholder reflect the new syntax. File-read failures
  surface as a SnackBar before the run dialog opens, so a
  typo in the path doesn't reach the hub. Threaded through
  `_FlowRunDialog` and `HubService.runSavedFlow`, which both
  carry separate `textInputs` and `fileInputs` maps now and
  forward to the SDK's mixed-mode runSavedFlow (v0.14.0).

- The Welcome doc-reader's error path uses `FaiErrorBox` so
  the actual underlying error is selectable + copy-to-
  clipboard via the existing widget. Plus the loader throws
  a richer error string that names *both* attempted asset
  paths (`<slug>_<lang>.md` and the EN fallback) and the
  underlying exception each, so the operator can paste a
  diagnostic into a chat without us having to ship a
  separate "how to read Flutter asset errors" doc.

- Doctor's empty Services panel had a horizontal RenderFlex
  overflow at narrow widths because the long mono-spaced
  hint ("add to ~/.fai/config.yaml under services:") and
  the leading icon+text both demanded full intrinsic width
  in a single Row. Now wraps via a `Wrap` widget so the
  hint flows to a second line on narrow viewports and stays
  in the same row when there's space.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-09 02:07:31 +02:00
flemming-it
eb447c6ec0 fix(studio): Welcome layout exception, drop awkward header, Store at slot 2 (v0.39.1)
Three fixes against the v0.39.0 user feedback.

- Layout exception "BoxConstraints forces an infinite
  height". `_PillarRow`'s wide-window path used
  `Row(crossAxisAlignment: CrossAxisAlignment.stretch)`
  inside a `Column` inside a `SingleChildScrollView` — Row
  inherits unbounded height, can't stretch to anything,
  Flutter throws. Wrapped the Row in `IntrinsicHeight` so
  the Row's height is bounded to the tallest child first.
  Same shape `_DocsRow`'s narrow-window path was triggering
  with `Wrap` + `SizedBox(width: double.infinity)` — replaced
  with a plain `Column` for that path; the wide path keeps
  the Wrap with the proper finite cardWidth.

- Dropped the "WIE ES ZUSAMMENPASST" / "HOW IT FITS
  TOGETHER" section header. Operator-feedback was that the
  label sounded like a question without an answer. The hero
  already establishes the page; the three Hub/Module/Flow
  cards are self-explaining beneath it. Header was visual
  clutter and the underlying ARB keys are gone.

- Reordered the sidebar: Welcome, **Store**, Doctor, Flows,
  Audit, Approvals. Store is the operator's daily-use
  surface and belongs above Doctor (which is a diagnostics
  page). Welcome stays slot 0 as the first-launch landing.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-09 00:42:39 +02:00
flemming-it
930e246649 feat(studio): Welcome page Phase C — live getting-started checklist (v0.39.0)
Final slice of the Welcome surface. Four steps that prove
the operator has the basic loop wired up; each step is
a live probe against the running hub, no manual ticks.

The four checked signals:

  1. System AI configured
     → `HubService.systemAiStatus().enabled`
  2. Public capability source added
     → `listMcpClients()` returns at least one entry
  3. Text module installed
     → `listModules()` contains a name starting with `text.`
  4. Saved flow run
     → any `flow.completed` event in the last 100 audit
       events

All four probes fire in parallel from `_OnboardingChecklist`'s
`_refresh()`. Failures stay false (catchError) so a hub that
is briefly unreachable doesn't blank the whole row — the
operator hits the explicit Refresh icon to retry.

UX:

- Renders between hero and pillars so the actionable path
  beats the educational content for screen real estate.
- Each row: status icon (○ pending / ✓ done) + title +
  one-line hint pointing the operator at the right Studio
  surface + status pill.
- Done rows strike-through the title and dim it; pending
  rows stay full-strength.
- When all four flip to done, an "All four steps complete"
  footer appears with a `Hide checklist` button. Clicking
  persists `welcome.checklist.dismissed = true` via
  SharedPreferences; the section is gone for good (we don't
  re-nag operators who chose a non-default path).

15 new ARB keys for the section header, body, four rows
plus done/pending pills, all-done footer, dismiss /
refresh / refreshing button labels.

Three-phase plan from `docs/landing-page-design.md` is now
fully shipped: Phase A scaffolding (v0.37.0), Phase B
embedded doc reader (v0.38.0), Phase C live checklist
(v0.39.0).

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-09 00:28:41 +02:00
flemming-it
3b07d340d5 feat(studio): Welcome page Phase B — embedded doc reader (v0.38.0)
Second slice of the Welcome surface. Operator-facing
documentation now lives inside Studio as bundled assets and
renders inline via a modal sheet — no browser, no external
link, air-gap-tauglich.

- Four operator-readable explainers under `assets/docs/`,
  each with an EN + DE pair:
    architecture[_de].md  — Hub / Module / Flow + how they fit
    security[_de].md       — sandbox model, declared perms,
                              operator ceiling
    audit[_de].md          — hash-chained log, WORM-1 mechanics,
                              `fai admin verify-events`
    flows[_de].md          — flow YAML, templating reference,
                              extract→summarize example
  These are short (≈ 300-500 words each), operator-shaped
  prose. Not copies of the architecture docs in
  fai_platform/docs/architecture/ — those are
  contributor-dense.

- pubspec.yaml declares `assets/docs/` so the markdown ships
  inside the Studio binary. Air-gap deployments read them
  with no network access.

- New `_DocReaderSheet` modal: 85 %-of-viewport bottom sheet,
  drag handle + title bar with the doc icon and close button,
  scrollable Markdown body styled to match Studio chrome.
  Loads `assets/docs/<slug>_<locale>.md` first, falls back to
  the EN file. Locale comes from
  `Localizations.localeOf(context)`.

- `_DocsRow` on the Welcome page sits below the trust-posture
  deck. Two-column grid on ≥ 640 dp, single column below.
  Each card is icon + title + one-line blurb + chevron;
  click opens the reader sheet for that slug.

- 12 new ARB keys for the docs section (header, blurb, four
  card titles + blurbs, close button, error message).
- 4 new icons reused: `account_tree_outlined` (architecture),
  `shield_outlined` (security), `verified_outlined` (audit),
  `alt_route_outlined` (flows).

Implements Phase B of `docs/landing-page-design.md`. Phase C
(live getting-started checklist with persistent state) is the
last remaining slice.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-09 00:24:31 +02:00
flemming-it
3a7d0e74ad feat(studio): Welcome page — Phase A scaffolding (v0.37.0)
First slice of the new sidebar destination outlined in
docs/landing-page-design.md. Static content only — embedded
docs (Phase B) and the live getting-started checklist
(Phase C) follow.

Phase A:

- New `WelcomePage` at `lib/pages/welcome.dart`, registered
  as sidebar slot 0 above Doctor. Default selectedIndex stays
  0, so a fresh launch lands on Welcome.
- Hero card: gradient backdrop matching the Today-Hero in the
  store, F∆I Platform headline, subtitle taken from CLAUDE.md
  ("deterministic workflow engine for AI-assisted document
  processing in regulated environments").
- Three-pillar row "Hub / Module / Flow" — operator-readable
  prose, not architecture-doc dense. Stacks to a column under
  640 dp window width so card text never gets cropped.
- Trust-posture deck — "Sandbox by default", "Tamper-evident
  audit log", "Air-gap ready". Same content that used to
  rotate as carousel slides in the store; reading them as a
  single deck with full prose works better than rotating
  through fragments.
- AppBar follows the same `titleSpacing: FaiSpace.xl`
  alignment as the Store so the title sits flush with the
  body padding.
- 13 new ARB keys for the page content (EN + DE).

Smoke test now expects "Welcome" in the navigation rail; the
existing `Doctor / Store / Flows / Audit / Approvals`
expectations stay unchanged.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-09 00:17:54 +02:00
flemming-it
a7e2eb101a feat(studio): drop Modules tab, fold its content into Store detail (v0.35.0)
Modules-as-a-tab was redundant with the Store after the
"Installed" filter and the federation work landed. Two pieces
of unique content kept it alive: the per-module declared
permissions list and the on-disk module directory. Both now
live inside the Store detail sheet.

Changes:

- Sidebar nav loses the Modules entry. `_pages` no longer
  carries a `'modules'` slot. The unused `import
  'pages/modules.dart'` is dropped from main.dart. Smoke test
  updated to skip the Modules-text expectation.

- Store detail sheet (`_StoreDetailSheet`) gains two new
  sections, rendered only when the entry is installed and the
  hub returned `ModuleDetail` for it:

    Declared permissions  →  same icon-prefixed list the
                              old Modules sheet shipped
                              (`net:`, `fs.read:`, `fs.write:`,
                              `env:`, `hub:`).
    Module directory      →  selectable mono path so the
                              operator can paste it into a
                              shell.

  An async `moduleInfo` fetch fires from `initState` only when
  `widget.item.installed` is true, so the regular
  not-installed detail-sheet path takes no extra round-trip.
  Failures stay silent — the sections just hide.

- The `FaiModuleSheet` widget stays intact. Cmd+K still uses
  it as a quick-info modal for installed modules; the
  longer-form Store detail sheet covers the same data plus
  the description, screenshots, and docs that operators
  reach for in the Store.

Three new ARB keys: `storeSectionPermissions`,
`storeSectionDirectory`, `storeSectionPermissionsNone`.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 14:57:51 +02:00
flemming-it
3b5fb027c3 feat(studio): de-jargonize, reveal-in-OS, copyable errors, today carousel, AppBar alignment, F∆I window title (v0.34.0)
Sweeping pass against six user reports collected this session.

1. "Capabilities ist nicht deutsch, Chain auch nicht."
   The DE locale still leaked English vocabulary. Replaced
   "Capabilities" → "Fähigkeiten" and "Chain" / "Hash-Chain"
   → "Kette" / "Hash-Kette" everywhere — store search hint,
   recommended-source body, federated toast, doctor summary
   chain row, modules panel summary, MCP / n8n hints, the
   approvals history blurb. Wire-level identifiers
   (`chain.reset`) stay as code.

2. "Bei Fehlern unten muss man die auch ins clipboard
   kopieren können." New `FaiErrorBox` widget: selectable
   monospace block with a small copy-to-clipboard icon
   button that flips to a checkmark for two seconds after
   click. Applied to the Doctor update banner output and
   the Settings channel toast — the two places long
   stderr / stdout lands.

3. "Öffnen bei Log kann es nicht öffnen. Audit-DB auch
   nicht. PID auch nicht."
   Cause: `SystemActions.openInOs` shells out to `open` /
   `xdg-open` on file paths the OS has no default handler
   for (SQLite DB, PID file, log without an .ext that
   binds). New `revealInOs` uses `open -R` on macOS,
   `explorer /select,` on Windows, and the parent
   directory via `xdg-open` on Linux. Doctor's path rows
   carry an `isDirectory` flag that routes through the new
   `openOrReveal` so files reveal in Finder / Explorer
   instead of failing silently.

4. "Oben im Store könnte man diesen Redaktionshinweis auch
   so bauen, dass man mit pfeil nach rechts links auch
   weitere anzeigen kann."
   The Today-Hero became a carousel. Curated fallback
   list grew from one entry to four (public sources, the
   sandbox-by-default permission story, the hash-chained
   audit story, the air-gap-ready single-binary pitch).
   Hero gets prev / next chevrons plus a dot indicator
   when the current snapshot has more than one slide.
   Operator-accepted stories stay single — the carousel
   collapses when there's only one to show.

5. "Ich fände es schöner wenn rechts und links im Store
   die Abstände konsistent sind, das Reload-Symbol rechts
   ist zu weit rechts und Store links auch nicht bündig."
   AppBar now has `titleSpacing: FaiSpace.xl` so the
   title's left edge sits flush with the body's left
   padding (24 dp), and the trailing `SizedBox` after the
   reload icon shrunk so the icon's outer edge meets the
   right edge of the rightmost grid card.

6. "Oben der Titel zeigt fai_studio an, das sollte F∆I
   Studio sein." The OS window title was the
   pubspec-derived "fai_studio". Macos/Linux/Windows
   runners now hard-code "F∆I Studio" (with the U+2206
   triangle escape so the C++ source stays ASCII). macOS
   bundle name and display name lifted out of the
   PRODUCT_NAME variable for the same reason.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 14:48:33 +02:00
flemming-it
22a851b7e2 fix(studio): doctor i18n + light-mode AppBar contrast (v0.33.1)
Two reports:

1. "In Diagnose ist viel nicht übersetzt, wie pending, chain
   etc." The Doctor summary strip (Modules / Approvals / Audit
   / Services tiles) and the modules panel still rendered
   English wire labels: "pending", "chain", "declared",
   "loaded", "empty", "attention", "No pending approvals",
   "No host services declared", and the matching "{n} modules
   · {m} capabilities" / "{n} approvals awaiting review"
   strings.

   Fix: 13 new ARB keys covering the summary tiles, modules
   panel, and services panel; doctor.dart now reads them via
   AppLocalizations. German operators no longer see English
   labels on Diagnose.

2. "Im Light mode ist der kontrast zur überschrift falsch,
   store ist weiß auf weiß." The AppBar title rendered
   white-on-white in light mode.

   Cause: `appBarTheme.titleTextStyle = textTheme.headlineSmall`
   passed a TextStyle built fresh from GoogleFonts.inter(...)
   with `color: null`. Material's "merge foregroundColor at
   draw time" path didn't always populate it — depended on
   build configuration. The colour fell through to whatever
   the surrounding DefaultTextStyle had, which on the
   light-mode AppBar was the surface colour.

   Fix: bake the foreground colour straight into the title
   style via `copyWith(color: scheme.onSurface)`. Also pin
   `iconTheme: IconThemeData(color: scheme.onSurface)` so
   actions-row icons get the same treatment defensively.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 13:43:17 +02:00
flemming-it
de22791e86 feat(studio): plain-language store, bottom-anchored ask bar (v0.33.0)
The store had three structural problems flagged in user
feedback:

1. "Lernkurve zu hoch — alle bridge, debug, alpha, planned,
   keiner weiß was das heißt." Wire-level enum values bled
   through into the UI: `bridge`, `debug`, `published`,
   `alpha`, `planned`. Operators don't share the data model.

2. "Filter / Kategorien sollten oben in die Leiste neben Store
   zum ausklappen, der Body soll übersichtlicher werden." A
   chip-row plus category strip plus result-count line ate a
   full row of viewport on every screen.

3. "Suche passt besser an den unteren Bildschirmrand." The
   chat-style ask bar belongs at the bottom — Claude / ChatGPT
   / Slack pattern — not at the top where it competes with
   the Today hero.

Plus: "Es gibt noch ganz viele overflows in den Beschreibungen."

Changes:

- Plain-language display names. New ARB keys for category
  labels (Connectors / Sample modules / AI models / Storage /
  Channels / Authentication / Orchestration / …) and updated
  status values (stable / experimental / coming soon). Wire
  ids stay in StoreEntry, RPCs, seed.yaml — only the rendered
  pills and dropdowns get translated. Helpers
  `_categoryDisplayName` and `_statusDisplayName` keep the
  mapping in one place.

- Toolbar moves into the AppBar. The new `_CategoryDropdown`
  hosts the category picker as a popup-menu with localised
  labels; the existing `_FilterButton` lives next to it; the
  reload icon stays where it always was. The body no longer
  carries any chip strip or result-count line.

- Bottom-anchored `_AskBar`. The Scaffold body becomes a
  Column of `Expanded(scrollable content)` plus a pinned
  composer row at the foot of the viewport, with a top
  divider matching the chat-input pattern of modern AI
  assistants. AI answers now render at the top of the scroll
  (above the Today-Hero) so the operator sees them right
  after submitting the question at the bottom.

- Overflow sweep on descriptions. Today-Hero header row
  becomes a Wrap (badge + deck flow naturally on narrow
  windows), the title is bound to 3 lines, the body to 6.
  Card category text gets `maxLines: 1, ellipsis` in both
  StoreCard and FeaturedTile. Recommended-source card title
  gets the same treatment.

- Better toast for the "added but zero capabilities" path.
  When MCP discovery succeeds but returns no tools (typical
  Streamable-HTTP servers without Mcp-Session-Id support, or
  servers that need `notifications/initialized`), the toast
  now explains the situation in plain language and points
  the operator at Settings → MCP Clients to retry. Old
  pluralised toast still fires when N > 0.

Hub-side `notifications/initialized` for HTTP MCP and
Mcp-Session-Id support are out of scope for this commit;
tracked as a separate fai_hub follow-up.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 13:37:35 +02:00
flemming-it
c7869870c4 feat(studio): plain-language ask bar + collapsible filter + AI search (v0.32.0)
Three changes against the user feedback "der text ist zu
zerhackt, die filter-leiste nimmt zu viel sicht weg, llm-suche
wenn das geht":

1. Today-Hero copy rewritten in flowing prose. The fallback
   story drops the code-fence templates ("`mcp.<server>.<tool>`")
   and reads as a single arc per language. Same trust model,
   gentler register.

2. Filter row collapses behind a single `_FilterButton` with a
   "Filter · N active" count badge. Status / Source / Installed
   chips now live inside `_FilterDialog` — invisible until the
   operator wants them, recovers a full row of viewport. The
   category strip stays inline because category is the most
   common cut and benefits from being one click away.

3. New `_AskBar` replaces the old single-line `_SearchField`:

   - Multi-line input (1-4 lines auto-grow) so questions don't
     overflow horizontally.
   - Cmd+Enter / Ctrl+Enter submits; bare Enter inserts a
     newline so the operator can write multi-line questions
     naturally.
   - Heuristic question detector (ends in `?` or ≥4 words)
     routes the submit to the System-AI's askAi RPC instead of
     the substring search. Live keystrokes still keyword-search
     for short queries; question-shaped input holds the grid
     steady until submit so the visible result set doesn't
     wipe with every space.
   - The LLM is asked for a strict-JSON ranking of up to 5
     modules with a one-phrase reason each. Unknown module
     names are dropped silently — operators must not see
     hallucinated entries.
   - The new `_AiAnswerCard` renders the LLM's answer plus the
     ranked match list above the grid; the grid filters to
     just those names so the answer and the visible cards
     stay coherent. Clearing the question collapses everything
     back.
   - Falls back to plain keyword search when System AI is off
     (with an explanatory hint instead of the AI hint).

The AI path uses the System-AI the operator already configured
in Settings; same privacy mode, same audit-log trail. Nothing
new leaves the hub.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 13:21:40 +02:00
flemming-it
fe933a713f feat(studio): editorial Today hero on the store (v0.30.0)
App-store research shows that the most loved discovery
surfaces — Apple's Today tab being the canonical example —
work because editors tell stories instead of stacking
algorithmic recommendations. F∆I has no surveillance budget
and no monetization pressure, so we lean fully into editorial
curation.

This commit adds `_StoreTodayHero`, the first surface a
browsing operator sees:

- Single curated story per release, kept const in
  [_kCurrentTodayStory] so the narrative is reviewable in code
  review and ships in the audit log via the binary hash. No
  CMS, no network, no surveillance.
- Bilingual content shipped inline (`titleEn`/`titleDe`,
  `bodyEn`/`bodyDe`) so KRITIS deployments don't need a
  translation backend.
- Gradient backdrop with hero icon, deck, narrative paragraph,
  optional CTA. Visual treatment matches Apple Today's
  hierarchy: badge → headline → body → action.
- Auto-hides whenever a filter is active so a purposeful
  search isn't pushed below the fold.
- Per-session dismiss button — no permanent suppression, the
  next Studio launch shows it again so a release-bumped story
  has a chance to be seen.

Current story (Studio v0.30.x) directs operators to the new
recommended-sources strip, closing the loop between editorial
context and one-click action.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 12:44:39 +02:00
flemming-it
581ebbeaf7 feat(studio): store-side source filter, provenance pills, one-click recommended sources (v0.29.0)
The Store is now the centre of capability discovery — provider
configuration moves out of Settings into the Store itself.
Three changes work together:

1. Source filter chips next to the existing status chips:
   All sources / Native / MCP / n8n. Applied client-side after
   the hub returns results so toggling is instant. The result
   count and the "Clear filters" reset both account for the
   source filter too.

2. Per-card provenance pill (`_ProvenancePill`): shows whether
   each entry is native, mcp · <provider>, or n8n · <provider>
   so the operator can triage the source at a glance — same
   role the "verified" badge plays in commercial app stores.

3. `_RecommendedSourcesStrip` replaces the older
   `_FederationNudge`. Renders curated public MCP servers
   (DeepWiki, Semgrep) as one-click cards with an inline
   `[+ Add]` button — no Settings detour, no form. Both servers
   are HTTPS Streamable-HTTP, no API key, no subprocess.
   Useful AI was considered but its 340+ tools would drown the
   index — kept out of the curated list. The strip auto-hides
   the moment any federated entry exists.

Removed the now-orphaned storeFederationNudge* ARB keys.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 12:25:59 +02:00
flemming-it
b5a4c74c4b feat(studio): Flows + Module sheet + System-AI editor i18n (v0.28.0)
- Localize Flows page: app-bar title and reload tooltip,
  hub-unreachable / no-saved-flows empty states, run-flow input
  dialog (title with flow name, description, hint, Cancel /
  Run), running dialog (title, "Flow running…" status, no-output
  message, Close button), flow-card Run button.
- Localize the module-sheet bottom sheet: failed-to-load text,
  Capabilities and "Declared permissions" section headers,
  no-permissions placeholder copy.
- Localize the System-AI configuration dialog: title, intro
  paragraph, provider dropdown label, endpoint label, API-key
  env-var label (required vs optional) and disclaimer, privacy
  mode header and three options (Off / Redacted / Full) plus
  their descriptions, test-result panel ("Connection ok" /
  "Connection failed", "Reply: …" prefix), model picker (label,
  hint fallback, helper text with Ollama variant, Refresh /
  Pull / Pulling… buttons, list errors and empty states),
  hardware banner ("Detected: …" + " · curation reviewed …"
  suffix), suitability legend (recommended / balanced / small /
  large / huge / unknown), cache row with pluralized count and
  Clear button, cache cleared / clear-failed toasts, pull-empty
  / pull-failed errors. Suitability label moved off a getter
  onto a `labelFor(BuildContext)` method so it can read the
  current locale.

Provider preset descriptions and modelHint strings stay in
English in `_ProviderPreset.all` — they're tightly coupled to
the wire-protocol identifiers and would require a runtime
factory rebuild rather than a const list.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 02:59:08 +02:00
flemming-it
e2b2639a86 feat(studio): Store + Cmd+K palette i18n (v0.27.0)
- Localize Store page: search hint, category and status filter
  chips (All / Published / Alpha / Planned / Installed),
  pluralized result count, hub-unreachable / no-matches empty
  states, featured strip header, store-card pills (installed /
  update / version), Install / Update / Details / Read docs /
  Uninstall / Not installable buttons, install-progress dialog,
  uninstall confirm dialog, install / uninstall toasts,
  open-browser failure toast.
- Localize detail-sheet sections: Tags, Required capabilities,
  Required host services, Screenshots, Documentation, Source.
- Localize docs panel: Load documentation button, fetching
  spinner copy, Open repository in browser button, friendly
  error mapping (not_found / no_docs / auth / network / parse).
- Localize Cmd+K palette: search hint, group labels (Pages /
  Modules / Store / Flows), keyboard hint footer, indexing /
  no-matches states, dynamic-hit copy ("installed module ·
  v{version}", "saved flow", "uncategorized"). Static page
  hits now flow through the localized "Pages" group; Settings
  entry uses the localized label and hint.

Status pill values ("published", "alpha", "planned") stay as
data-derived English strings since they map directly to the
store-index `status:` enum.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 02:49:18 +02:00
flemming-it
d25b4c87ae feat(studio): MCP suggestions + Approvals/Audit/Settings i18n (v0.26.0)
- Add curated catalogue of 9 official Anthropic MCP servers as
  click-to-prefill chips in the Add-MCP-server dialog. Operator
  still confirms via "Add + discover"; nothing is auto-spawned,
  preserving the regulated-environment trust model.
- Localize Approvals page: pending/history empty states, status
  pills, payload preview, approve/reject toasts, reject dialog,
  history detail dialog, expires-in pill.
- Localize Audit page: filter chips, clear-log dialog and toasts,
  no-events / hub-unreachable empty states, live-status bar with
  pluralized event count, hash-chain-verified badge, System AI
  panel (cached pill, latency, regenerate tooltip, asking
  state), event-detail dialog actions.
- Localize Settings dialog: hub-endpoint section, channel
  blurb + popup-menu items, System AI panel headers and
  off-blurb, MCP/N8N panel headers + pluralized counts +
  refresh/add/remove tooltips, Add-MCP and Add-n8n dialogs
  (intro, suggestions label, all field labels and hints, save
  buttons, toasts).

Field labels that map directly to JSON keys (event_id, flow,
step, module, provider, endpoint, model) stay English by design
— they're technical identifiers, not UI copy.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 02:38:11 +02:00
flemming-it
349619d68e feat(studio): Doctor + Modules localized + sparse-store federation nudge (v0.25.0)
Two threads.

Translation expansion: every visible string on the Doctor
page (section headers, status text, button labels, daemon-
control card, daemon-files panel, update banner) and the
Modules page (recent-activity strip, capabilities label,
uninstall dialog + toast) flips between DE and EN with the
sidebar toggle. Adds ~50 ARB keys split between
`app_en.arb` / `app_de.arb`. Pluralised + parametrised
strings (`{n} events verified`, `Running on {name}: {endpoint}`)
use the standard ICU placeholder syntax so future locales
slot in without code changes.

Sparse-store federation nudge: the Store page renders an
inline banner above the grid when the operator has zero
federated entries — single biggest store-fullness lever is
configuring an MCP server / n8n endpoint, so the banner
says exactly that and the button opens Settings straight
to the editor. Banner dismisses automatically the next
render after a federated entry appears.

Coverage stand for translation: Doctor + Modules + sidebar
+ page titles + nav + Cmd+K labels are bilingual. Settings
dialog, Approvals cards, Audit drilldown, MCP/n8n editors,
Store search hint + filter chips remain English-literal.
The infrastructure (ARB plumbing, generator hookup,
locale-notifier) means each follow-up surface is a
one-line ARB edit + one call-site swap.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 01:39:42 +02:00
flemming-it
ee83eb851a feat(studio): app-wide i18n via flutter_localizations (v0.24.0)
Replaces the Store-only DE/EN toggle with an app-wide one
parked in the sidebar footer next to the theme button.
Pressing it flips every translated string at once: nav
labels, page titles, common buttons, the bilingual
store-index content.

Implementation:
- Adds `flutter_localizations` + `intl` to pubspec, plus
  `flutter.generate: true` so `flutter gen-l10n` runs in the
  build pipeline.
- ARB sources at `lib/l10n/app_en.arb` and `app_de.arb`. The
  EN file is the template; DE carries the German strings.
  Initial coverage: navigation, common buttons, page titles,
  channels / store / audit / modules / approvals headers,
  hub-unreachable copy, MCP + n8n panel headers + hints.
  Rest of the UI strings are still English-literal — those
  fall in incrementally as we touch each surface.
- Generated `AppLocalizations` lives at
  `lib/l10n/app_localizations*.dart` (regenerated via
  `flutter gen-l10n` on every ARB edit).
- `StudioAppState` gains `localeNotifier` alongside
  `modeNotifier`; persisted via SharedPreferences key
  `locale.code`.
- Sidebar `_LanguageToggle` reads/writes through the
  notifier. The Store's per-page locale state is gone:
  `_locale` now reads `Localizations.localeOf(context)
  .languageCode`, so the bilingual store-index content
  follows the global setting without a second toggle.
- `_NavPage.label` becomes `_NavPage.id` + `labelOf(context)`;
  Cmd+K palette and Sidebar both read the localized label.

Out of scope this iteration: localizing the remaining
~80% of UI strings (Settings dialog labels, Store search
hint, error messages). Those land incrementally — the i18n
infrastructure now means each is a one-line ARB edit + one
call-site swap.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-05-08 01:19:32 +02:00