feat(desktop): localized JS application menu via @tauri-apps/api/menu (T1)#189
Conversation
Root-cause fix + detection unification. Tauri v2 injects `__TAURI_INTERNALS__` unconditionally but `__TAURI__` only when `app.withGlobalTauri` is enabled — and this app does not set it. The canonical `isTauriRuntime()` checked `__TAURI__` alone, so it returned FALSE inside the real desktop shell, silently dead-ending the JS desktop layer (storage→filesystem backend, Tauri JSONL log sink, native HTTP/CORS-bypass fetch for AI providers, desktop device profile, Ollama-localhost path, desktop-only provider UI). The bug was masked because the Rust-side menu works regardless of JS detection. - `isTauriRuntime()` now accepts `__TAURI_INTERNALS__` OR `__TAURI__` (matches the robust check already in register-sw.ts). Web stays false → zero PWA regression. - Unify all seven raw detection sites onto `isTauriRuntime()`: storageService, loraTrainingService (drops its local `__TAURI_INTERNALS__` helper), logger, ai/fetchAdapter, ai/localAiDeviceProfiler, aiProviderService (Ollama), settings/AiProviderCard. - Test: isTauriRuntime returns true when only `__TAURI_INTERNALS__` is present. (T0 foundation for the native-desktop plan. The `services/desktop/` layer + the `desktop` i18n module are introduced in T1 with their first consumers, to avoid shipping unused scaffold here.) typecheck/lint green; tauriRuntime/storageService/fetchAdapter/localAiDeviceProfiler/ loraTrainingService/aiProviderService/logger tests pass (120 across the touched set). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… (T1) Migrate the native menu from hardcoded-English Rust to a localized JS menu — the only way to localize labels, since there is no t() outside React (ADR-D1). - New `services/desktop/` layer: `desktopEvents.ts` (command-id contract) + `desktopMenu.ts` (`installDesktopMenu(t, runCommand)`), built with `@tauri-apps/api/menu` and gated by `isTauriRuntime()` (no-op on web). - Full localized menu: File (Export/Settings/Quit), Edit + Window (predefined OS-localized items, no wiring), View (Command Palette, Cmd/Ctrl+K), Help. Custom items route through `executeCommand` (ADR-D3). `setAsAppMenu()` overrides the minimal Rust menu, which stays as a pre-paint fallback (no Rust change, no flash). - Installed from `App.tsx` (rebuilds on language change). Falls back silently to the Rust menu if the API throws — never breaks startup. - New `desktop` i18n module (`desktop.menu.*`) across all 17 locales (5 core translated, Beta/RTL English-fallback) + registered in both i18n scripts; bundles rebuilt, i18n:check green (parity 17×). Deferred: dynamic **Recent Projects**. The app is single-active-project (switched only by importing a file via importProjectThunk); there is no runtime "open stored project by id → activate" path to wire menu items to. That needs a project-switch thunk (save-current/load-target + entity rehydration) — its own follow-up, not a menu sub-task. Tracked. Tests: desktopMenu builder (5 — structure, app-menu install, command routing, web no-op, error-safe). typecheck (validates the menu API) / lint / i18n:check / placeholder-guard green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…into feat/tauri-desktop-menu
Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
|
@CodeAnt-AI review |
Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
Sequence DiagramThis PR moves the desktop application menu into a localized JS layer using the Tauri menu API, installing it from the React App and routing menu actions into the existing command system. sequenceDiagram
participant User
participant DesktopApp
participant DesktopMenuService
participant TauriMenuAPI
participant CommandSystem
User->>DesktopApp: Open desktop app or change language
DesktopApp->>DesktopMenuService: installDesktopMenu(t, executeCommand)
DesktopMenuService->>TauriMenuAPI: Build localized menu and set as app menu
User->>TauriMenuAPI: Select menu item (Settings, Export, Help, Command Palette)
TauriMenuAPI->>DesktopMenuService: Invoke item action callback
DesktopMenuService->>CommandSystem: executeCommand(mapped desktop command id)
Generated by CodeAnt AI |
…f-guard rebuild (CodeAnt #189) - HIGH: desktop.json used a nested { "menu": { ... } } object, but build-i18n.mjs copies top-level keys verbatim and I18nContext.t() only does FLAT lookups, so t('desktop.menu.file') never resolved (menu labels would fall back to raw keys). Flattened all 17 locales to flat "desktop.menu.*" keys (matching the dashboard.* convention) and rebuilt bundles. - Removed the registerTauriMenuHandler effect: the localized JS menu (installDesktopMenu) already dispatches each action via its item callback, and the Rust `menu-action` bridge reused the SAME item ids — so every desktop menu click dispatched twice. The JS menu is now the single source of truth. - installDesktopMenu effect now holds executeCommand in a ref and depends only on [t], so the native menu rebuilds on language change instead of on every executeCommand identity change (it recreates whenever characters/worlds/settings/… change). i18n:check green (parity, 2725 keys/locale); tsgo clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
|
@CodeAnt-AI review |
Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
Sequence DiagramThis PR moves the desktop application menu into a localized JS layer, installs it on startup for Tauri runtimes, and routes native menu actions directly into the app command system. sequenceDiagram
participant App
participant JSMenu as Desktop menu service
participant MenuAPI as Tauri menu API
participant Commands as Command system
participant User
App->>JSMenu: installDesktopMenu(t, runCommand)
JSMenu->>JSMenu: Check desktop runtime
JSMenu->>MenuAPI: Build localized menus from translations
MenuAPI-->>JSMenu: Return menu structure
JSMenu->>MenuAPI: Set as application menu
User->>MenuAPI: Selects menu item
MenuAPI->>JSMenu: Trigger item action callback
JSMenu->>Commands: runCommand(commandId)
Commands-->>App: Execute mapped app action
Generated by CodeAnt AI |
… win (CodeAnt #189 wave-2) installDesktopMenu is async and re-runs on every language change; two overlapping calls raced and whichever finished setAsAppMenu() LAST won — even if it started earlier with a stale locale. Each call now captures a monotonic token (++menuInstallToken) at start and bails before setAsAppMenu if a newer call has since started, so only the latest-started install applies. New concurrency test asserts the superseded call never applies its menu. Covers both the App.tsx effect and desktopMenu threads (the guard lives at the service level, the single source of truth). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@CodeAnt-AI review |
Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
Sequence DiagramThis PR adds a JS-based localized desktop application menu for the Tauri runtime and wires menu item actions into the existing command execution system, rebuilding the menu on language changes while falling back to the Rust menu on failure. sequenceDiagram
participant User
participant DesktopShell as Desktop shell
participant App as React App
participant MenuService as Desktop menu service
participant Commands as Command system
App->>MenuService: installDesktopMenu(t, runCommand)
MenuService->>MenuService: Check desktop runtime and build localized menu
MenuService->>DesktopShell: Set menu as app menu
User->>DesktopShell: Click native menu item
DesktopShell-->>MenuService: Trigger item action callback
MenuService->>Commands: runCommand(mapped command id)
Commands-->>App: Execute command (navigate or export)
Generated by CodeAnt AI |
# Conflicts: # graphify-out/GRAPH_REPORT.md
Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
User description
Phase T1 — JS menu migration
Stacked on T0 (#188, base
feat/tauri-desktop-foundations). Native-desktop plan, Core+power. CodeAnt review deferred to the combined final pass perdocs/CODEANT-LOOP-RUNBOOK.md.What
services/desktop/layer:desktopEvents.ts(command-id contract) +desktopMenu.ts(installDesktopMenu(t, runCommand)), built with@tauri-apps/api/menu, gated byisTauriRuntime()→ no-op on web.t()outside React, ADR-D1): File (Export/Settings/Quit), Edit + Window (predefined OS-localized items, no wiring), View (Command Palette,Cmd/Ctrl+K), Help. Custom items route throughexecuteCommand(ADR-D3).setAsAppMenu()overrides the minimal Rust menu, which stays as a pre-paint fallback → no Rust change, no menuless flash.App.tsx(rebuilds on language change); silently falls back to the Rust menu if the API throws.desktopi18n module (desktop.menu.*) across all 17 locales (5 core translated, Beta/RTL English-fallback) + registered in both i18n scripts; bundles rebuilt,i18n:checkparity green.Deferred (honest scope): dynamic Recent Projects
The app is single-active-project — switched only by importing a file (
importProjectThunk); there is no runtime "open stored project by id → make active" path (loadProject(id)exists but only feeds backup/dataset extraction). Wiring Recent-Projects menu items needs a project-switch thunk (save-current / load-target + entity-adapter rehydration + image handling) — a real feature with state-handoff risk, not a menu sub-task. Tracked for a dedicated follow-up.Tests / gates
tests/unit/desktopMenu.test.ts(5): menu structure,setAsAppMenuinstall, command routing, web no-op, error-safe.typecheck(validates the menu API),lint,i18n:check(17× parity), placeholder-guard.tauri-build.ymldispatch needed this phase.Zero PWA regression
installDesktopMenuisisTauriRuntime()-gated; web returns early. Web build markup unchanged.🤖 Generated with Claude Code
CodeAnt-AI Description
Add a localized native menu for the desktop app and stop duplicate menu actions
What Changed
Impact
✅ Localized desktop menus✅ Fewer double-triggered menu actions✅ Clearer native app navigation💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.