Skip to content

fix(desktop): stop silently routing electronTrpc font-settings query through host-service#3394

Merged
saddlepaddle merged 2 commits into
mainfrom
relay-ping-not-right
Apr 13, 2026
Merged

fix(desktop): stop silently routing electronTrpc font-settings query through host-service#3394
saddlepaddle merged 2 commits into
mainfrom
relay-ping-not-right

Conversation

@saddlepaddle
Copy link
Copy Markdown
Collaborator

@saddlepaddle saddlepaddle commented Apr 13, 2026

Summary

@trpc/react-query uses a module-level singleton React context when createTRPCReact() is called without an explicit context. Both electronTrpc (apps/desktop/src/renderer/lib/electron-trpc.ts) and workspaceTrpc (packages/workspace-client/src/workspace-trpc.ts) do this, so nesting <workspaceTrpc.Provider> inside the v2 workspace layout overrides that singleton — and every electronTrpc.*.useQuery(...) call rendered under it silently routes through the workspace HTTP link instead of the Electron IPC link.

The visible symptom was a recurring TRPCError: No procedure found on path "settings.getFontSettings" coming from host-service.js whenever v2 workspace panes mounted (Terminal, WorkspaceDiff, FilePane code/markdown renderers).

Rather than introduce a new React context and re-test v2's provider wiring, this PR matches the pattern v2 already uses everywhere else — the imperative electronTrpcClient proxy — and wraps the query in a plain @tanstack/react-query useQuery. That bypasses trpc-react-query's shared context entirely.

Files touched:

  • useTerminalAppearance — v2 terminal font/theme hook
  • WorkspaceDiff — v2 diff pane
  • CodeEditor (v1, reused in v2's FilePane code/markdown renderers)

Terminal.tsx and LightDiffViewer.tsx also use the React hook form, but neither is rendered inside v2's WorkspaceTrpcProvider, so they're left alone.

Test plan

  • bun run typecheck (desktop) passes
  • bun run lint:fix clean
  • bun test apps/desktop — same baseline as main (1 pre-existing fail in trpc-storage/useOrderedSections, unrelated)
  • Manually open a v2 workspace, mount a terminal pane, a diff pane, and a file pane with a code file; confirm no settings.getFontSettings 404s in logs and that editor/terminal font settings still apply

Summary by cubic

Fix v2 panes routing font settings queries through the workspace HTTP link. Switch to electronTrpcClient wrapped in @tanstack/react-query useQuery so font settings go through Electron IPC and apply correctly in Terminal, Diff, and CodeEditor.

  • Bug Fixes
    • Replaced electronTrpc.settings.getFontSettings.useQuery with useQuery({ queryKey: ["electron","settings","getFontSettings"], queryFn: () => electronTrpcClient.settings.getFontSettings.query(), staleTime: 30_000 }).
    • Updated useTerminalAppearance, WorkspaceDiff, and CodeEditor; removed inline comments from this workaround.
    • Avoids @trpc/react-query shared context bleed from nested workspaceTrpc.Provider, preventing host-service 404s/TRPCError on settings.getFontSettings.

Written for commit 03f3c3d. Summary will update on new commits.

Summary by CodeRabbit

  • Refactor
    • Standardized how font settings are loaded across workspace editor, terminal, and code editor so font choices and sizes remain consistent and more reliable across the app.

…client

@trpc/react-query falls back to a module-level singleton React context
when createTRPCReact is called without an explicit context. In the v2
workspace, nesting <workspaceTrpc.Provider> overrides that singleton and
silently routes electronTrpc.*.useQuery calls through the workspace
HTTP link, producing "No procedure found on path settings.getFontSettings"
against host-service.

Switch the three v2 render paths (useTerminalAppearance, WorkspaceDiff,
and v1 CodeEditor which is reused in v2's FilePane renderers) to use
electronTrpcClient.settings.getFontSettings.query() wrapped in a plain
@tanstack/react-query useQuery, matching the rest of v2.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 13, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3f89e02a-1f66-47ba-87ab-bc86258620cb

📥 Commits

Reviewing files that changed from the base of the PR and between b244843 and 03f3c3d.

📒 Files selected for processing (3)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/DiffPane/components/WorkspaceDiff/WorkspaceDiff.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/TerminalPane/hooks/useTerminalAppearance/useTerminalAppearance.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/components/CodeEditor/CodeEditor.tsx

📝 Walkthrough

Walkthrough

Replaced three usages of electronTrpc.settings.getFontSettings.useQuery(...) with explicit @tanstack/react-query useQuery calls that use a fixed query key and call electronTrpcClient.settings.getFontSettings.query(); kept staleTime and downstream theming logic unchanged.

Changes

Cohort / File(s) Summary
Font Settings Query Refactor
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/DiffPane/components/WorkspaceDiff/WorkspaceDiff.tsx, apps/desktop/src/renderer/.../TerminalPane/hooks/useTerminalAppearance/useTerminalAppearance.ts, apps/desktop/src/renderer/screens/main/components/WorkspaceView/components/CodeEditor/CodeEditor.tsx
Replaced electronTrpc.settings.getFontSettings.useQuery() with direct useQuery using ["electron","settings","getFontSettings"] as queryKey and electronTrpcClient.settings.getFontSettings.query() as queryFn. Preserved staleTime: 30_000. Updated imports (removed electronTrpc, added useQuery/electronTrpcClient).

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I hopped through three files, tidy and neat,
Swapped hooks for queries with a steady beat,
Keys set in order, staleTime kept true,
A clean little change — from me to you! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: fixing font-settings queries being incorrectly routed through the workspace HTTP service instead of Electron IPC.
Description check ✅ Passed The description is comprehensive and follows the template structure with clear sections on summary, root cause, fix, files touched, and test plan. All key information about the bug and solution is provided.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch relay-ping-not-right

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 13, 2026

Greptile Summary

This PR fixes a silent routing bug in v2 workspace panes: because @trpc/react-query stores its React context in a module-level singleton, nesting a workspaceTrpc.Provider inside the v2 layout overwrote that singleton and caused every electronTrpc.*.useQuery() call rendered under it to route through the host-service HTTP link instead of Electron IPC. The fix replaces the three affected electronTrpc.*.useQuery() call sites with plain @tanstack/react-query useQuery calls backed by the imperative electronTrpcClient proxy, which bypasses the shared React context entirely.

Key points:

  • The root-cause diagnosis and fix are correct — using electronTrpcClient (IPC-linked proxy) inside a vanilla useQuery avoids the singleton collision.
  • All three sites (useTerminalAppearance, WorkspaceDiff, CodeEditor) use the identical query key [\"electron\", \"settings\", \"getFontSettings\"], so they share one cache entry — that deduplication is intentional and correct.
  • Cache-key mismatch with tRPC invalidation: FontSettingSection.tsx calls utils.settings.getFontSettings.invalidate() after each setFontSettings mutation. That utility targets the tRPC-generated cache key (a nested structure), not the plain key [\"electron\", \"settings\", \"getFontSettings\"]. As a result, after a user saves font settings, the terminal, diff pane, and code editor will not react to the change until the 30 s staleTime expires and a natural refetch fires. This is a reactivity regression that should be addressed alongside (or shortly after) this fix.
  • Terminal.tsx and LightDiffViewer.tsx are intentionally left on the React hook form since they aren't rendered inside WorkspaceTrpcProvider — that decision is documented and correct.

Confidence Score: 4/5

Safe to merge — the core bug fix is correct — but the cache-key mismatch means font-setting changes won't propagate immediately to the patched components; this should be addressed soon.

The PR correctly identifies and fixes the singleton React context collision that caused 404 errors in v2 workspace panes. The imperative-client approach is consistent with how the rest of v2 already calls electronTrpcClient. The one concrete issue is that the new plain query key ["electron", "settings", "getFontSettings"] is invisible to utils.settings.getFontSettings.invalidate() in FontSettingSection, so saving font settings will not immediately update the terminal/editor/diff panes. This is a noticeable UX regression but not a crash or data-loss risk, and it doesn't affect the primary bug being fixed (the 404 routing errors).

All three changed files share the same cache-key mismatch; FontSettingSection.tsx (unchanged) will also need a follow-up to invalidate the new query key after mutations.

Important Files Changed

Filename Overview
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/TerminalPane/hooks/useTerminalAppearance/useTerminalAppearance.ts Switches from electronTrpc.settings.getFontSettings.useQuery() to vanilla useQuery with a plain query key — fixes the IPC routing bug but introduces a cache-key mismatch that prevents tRPC's invalidate() from propagating font-setting changes to this hook.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/DiffPane/components/WorkspaceDiff/WorkspaceDiff.tsx Same cache-key mismatch as useTerminalAppearance; the font-settings query now bypasses tRPC's singleton context correctly but won't respond to utils.settings.getFontSettings.invalidate() calls from FontSettingSection.
apps/desktop/src/renderer/screens/main/components/WorkspaceView/components/CodeEditor/CodeEditor.tsx Same cache-key mismatch as the other two files; plain query key ["electron", "settings", "getFontSettings"] won't be invalidated by tRPC's mutation utilities in FontSettingSection.

Sequence Diagram

sequenceDiagram
    participant App as App (React tree)
    participant WTRPC as workspaceTrpc.Provider (v2 layout)
    participant Hook as useTerminalAppearance / WorkspaceDiff / CodeEditor
    participant Client as electronTrpcClient (IPC proxy)
    participant IPC as Electron IPC
    participant Main as Main process (settings router)

    Note over App,WTRPC: Before this PR
    App->>WTRPC: renders workspaceTrpc.Provider
    Note over WTRPC: Overwrites @trpc/react-query module-level singleton context
    Hook->>WTRPC: electronTrpc.settings.getFontSettings.useQuery()
    WTRPC-->>Hook: routes through host-service HTTP link
    Hook--xMain: TRPCError: No procedure found on path settings.getFontSettings

    Note over App,Main: After this PR
    App->>WTRPC: renders workspaceTrpc.Provider
    Hook->>Client: useQuery -> electronTrpcClient.settings.getFontSettings.query()
    Client->>IPC: IPC link (bypasses React context entirely)
    IPC->>Main: settings.getFontSettings
    Main-->>IPC: FontSettings data
    IPC-->>Client: resolved
    Client-->>Hook: fontSettings
Loading

Reviews (1): Last reviewed commit: "fix(desktop): route font-settings query ..." | Re-trigger Greptile

Comment on lines +20 to +24
const { data: fontSettings } = useQuery({
queryKey: ["electron", "settings", "getFontSettings"],
queryFn: () => electronTrpcClient.settings.getFontSettings.query(),
staleTime: 30_000,
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Cache key divergence breaks reactivity when font settings change

The new queryKey: ["electron", "settings", "getFontSettings"] is a plain React Query key that does not match the internal key that @trpc/react-query generates for electronTrpc.settings.getFontSettings.useQuery(). tRPC generates a nested key structure like [["settings", "getFontSettings"], { input: undefined, type: "query" }].

FontSettingSection.tsx calls utils.settings.getFontSettings.invalidate() in its mutation's onSettled callback. That call targets only the tRPC-managed cache entry — it will not reach the vanilla useQuery entries in this hook, WorkspaceDiff, or CodeEditor. After a user saves new font settings, these three components will continue displaying the old values until the 30 s staleTime expires and a natural refetch fires (e.g. window focus or remount).

The same issue exists in WorkspaceDiff.tsx and CodeEditor.tsx.

One way to close the gap without restructuring provider wiring: add a matching queryClient.invalidateQueries call in FontSettingSection's onSettled alongside the existing utils call:

queryClient.invalidateQueries({ queryKey: ["electron", "settings", "getFontSettings"] });

Alternatively, use getQueryKey (exported from @trpc/react-query) to derive the exact tRPC-generated key and supply it to these vanilla useQuery calls, so that utils.settings.getFontSettings.invalidate() covers them automatically.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/DiffPane/components/WorkspaceDiff/WorkspaceDiff.tsx (1)

54-58: The hardcoded queryKey here is intentional—see the preceding comment explaining that imperative electronTrpcClient is required to avoid silent routing through the host-service HTTP link when workspaceTrpc.Provider nests the default @trpc/react-query context (a module-level singleton). This pattern is used consistently across three files (WorkspaceDiff.tsx, useTerminalAppearance.ts, CodeEditor.tsx).

The trade-off is that cache invalidations from utils.settings.getFontSettings.invalidate() in FontSettingSection.tsx won't reach these hardcoded-key queries. The 30-second staleTime mitigates staleness risk, but if faster consistency is needed, consider centralizing font-settings queries to a single cache-key strategy (though this would require first resolving the Provider nesting constraint).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/hooks/usePaneRegistry/components/DiffPane/components/WorkspaceDiff/WorkspaceDiff.tsx
around lines 54 - 58, The query in WorkspaceDiff.tsx (and the matching queries
in useTerminalAppearance.ts and CodeEditor.tsx) uses a hardcoded queryKey which
prevents cache invalidation calls from
utils.settings.getFontSettings.invalidate() from reaching them; fix by
introducing and importing a single shared constant (e.g.,
FONT_SETTINGS_QUERY_KEY) used by all three query usages and by the invalidate
call in FontSettingSection.tsx so invalidations target the same cache key
(alternatively, if Provider nesting cannot be changed yet, reduce staleTime or
call invalidate via the same imperative electronTrpcClient path but prefer the
shared query-key constant for consistency).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/hooks/usePaneRegistry/components/DiffPane/components/WorkspaceDiff/WorkspaceDiff.tsx:
- Around line 54-58: The query in WorkspaceDiff.tsx (and the matching queries in
useTerminalAppearance.ts and CodeEditor.tsx) uses a hardcoded queryKey which
prevents cache invalidation calls from
utils.settings.getFontSettings.invalidate() from reaching them; fix by
introducing and importing a single shared constant (e.g.,
FONT_SETTINGS_QUERY_KEY) used by all three query usages and by the invalidate
call in FontSettingSection.tsx so invalidations target the same cache key
(alternatively, if Provider nesting cannot be changed yet, reduce staleTime or
call invalidate via the same imperative electronTrpcClient path but prefer the
shared query-key constant for consistency).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ce32f4ea-d74c-49e3-8c19-3c354b694e07

📥 Commits

Reviewing files that changed from the base of the PR and between 77b68f1 and b244843.

📒 Files selected for processing (3)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/DiffPane/components/WorkspaceDiff/WorkspaceDiff.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/TerminalPane/hooks/useTerminalAppearance/useTerminalAppearance.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/components/CodeEditor/CodeEditor.tsx

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 3 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/DiffPane/components/WorkspaceDiff/WorkspaceDiff.tsx">

<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/DiffPane/components/WorkspaceDiff/WorkspaceDiff.tsx:55">
P2: Cache invalidation is broken for these vanilla `useQuery` calls. The `queryKey` here (`["electron", "settings", "getFontSettings"]`) doesn't match the tRPC-generated key structure (`[["settings", "getFontSettings"], { input: undefined, type: "query" }]`), so when `FontSettingSection` calls `utils.settings.getFontSettings.invalidate()` after saving, it won't invalidate these entries. Users will see stale font settings for up to 30 s (the `staleTime`) after changing them.

Two options:
1. Use `getQueryKey` from `@trpc/react-query` to derive the exact tRPC key and pass it here, so the existing `invalidate()` covers these entries automatically.
2. Add a matching `queryClient.invalidateQueries({ queryKey: ["electron", "settings", "getFontSettings"] })` in `FontSettingSection`'s `onSettled` callback alongside the existing `utils` call.

The same issue applies to `WorkspaceDiff.tsx` and `CodeEditor.tsx`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

// singleton — nesting workspaceTrpc.Provider overrides it and silently
// routes electronTrpc hooks through the host-service HTTP link.
const { data: fontSettings } = useQuery({
queryKey: ["electron", "settings", "getFontSettings"],
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Cache invalidation is broken for these vanilla useQuery calls. The queryKey here (["electron", "settings", "getFontSettings"]) doesn't match the tRPC-generated key structure ([["settings", "getFontSettings"], { input: undefined, type: "query" }]), so when FontSettingSection calls utils.settings.getFontSettings.invalidate() after saving, it won't invalidate these entries. Users will see stale font settings for up to 30 s (the staleTime) after changing them.

Two options:

  1. Use getQueryKey from @trpc/react-query to derive the exact tRPC key and pass it here, so the existing invalidate() covers these entries automatically.
  2. Add a matching queryClient.invalidateQueries({ queryKey: ["electron", "settings", "getFontSettings"] }) in FontSettingSection's onSettled callback alongside the existing utils call.

The same issue applies to WorkspaceDiff.tsx and CodeEditor.tsx.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/DiffPane/components/WorkspaceDiff/WorkspaceDiff.tsx, line 55:

<comment>Cache invalidation is broken for these vanilla `useQuery` calls. The `queryKey` here (`["electron", "settings", "getFontSettings"]`) doesn't match the tRPC-generated key structure (`[["settings", "getFontSettings"], { input: undefined, type: "query" }]`), so when `FontSettingSection` calls `utils.settings.getFontSettings.invalidate()` after saving, it won't invalidate these entries. Users will see stale font settings for up to 30 s (the `staleTime`) after changing them.

Two options:
1. Use `getQueryKey` from `@trpc/react-query` to derive the exact tRPC key and pass it here, so the existing `invalidate()` covers these entries automatically.
2. Add a matching `queryClient.invalidateQueries({ queryKey: ["electron", "settings", "getFontSettings"] })` in `FontSettingSection`'s `onSettled` callback alongside the existing `utils` call.

The same issue applies to `WorkspaceDiff.tsx` and `CodeEditor.tsx`.</comment>

<file context>
@@ -47,10 +47,15 @@ export const WorkspaceDiff = memo(function WorkspaceDiff({
+	// singleton — nesting workspaceTrpc.Provider overrides it and silently
+	// routes electronTrpc hooks through the host-service HTTP link.
+	const { data: fontSettings } = useQuery({
+		queryKey: ["electron", "settings", "getFontSettings"],
+		queryFn: () => electronTrpcClient.settings.getFontSettings.query(),
+		staleTime: 30_000,
</file context>
Fix with Cubic

@saddlepaddle saddlepaddle merged commit 6c79673 into main Apr 13, 2026
1 of 2 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ⚠️ Neon database branch
  • ⚠️ Electric Fly.io app

Thank you for your contribution! 🎉

MocA-Love pushed a commit to MocA-Love/superset that referenced this pull request Apr 13, 2026
…through host-service (superset-sh#3394)

* fix(desktop): route font-settings query via imperative electron tRPC client

@trpc/react-query falls back to a module-level singleton React context
when createTRPCReact is called without an explicit context. In the v2
workspace, nesting <workspaceTrpc.Provider> overrides that singleton and
silently routes electronTrpc.*.useQuery calls through the workspace
HTTP link, producing "No procedure found on path settings.getFontSettings"
against host-service.

Switch the three v2 render paths (useTerminalAppearance, WorkspaceDiff,
and v1 CodeEditor which is reused in v2's FilePane renderers) to use
electronTrpcClient.settings.getFontSettings.query() wrapped in a plain
@tanstack/react-query useQuery, matching the rest of v2.

* chore(desktop): drop explanatory comments from font-settings workaround
@Kitenite Kitenite deleted the relay-ping-not-right branch April 13, 2026 16:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant