Skip to content

[codex] gate offline host workspaces#4672

Merged
Kitenite merged 1 commit into
mainfrom
gate-offline-host-worktre
May 17, 2026
Merged

[codex] gate offline host workspaces#4672
Kitenite merged 1 commit into
mainfrom
gate-offline-host-worktre

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented May 17, 2026

Summary

  • Gate remote V2 workspace routes when the owning host is marked offline.
  • Add a dedicated offline-host state instead of mounting workspace children against an unreachable host service.
  • Include a responsive Host ID row plus links to host settings and the V2 workspaces list.

Why

Remote workspaces already depend on host availability. When a host is offline, the workspace detail route should behave like the existing missing-worktree gate: explain why terminals and file actions are unavailable and avoid downstream host-service queries.

Validation

  • bunx biome check --write --unsafe apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/layout.tsx apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/hooks/useRemoteHostStatus/useRemoteHostStatus.ts apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/components/WorkspaceHostOfflineState/WorkspaceHostOfflineState.tsx apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/components/WorkspaceHostOfflineState/index.ts
  • bun run --cwd apps/desktop typecheck
  • bun run lint -- apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/layout.tsx apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/hooks/useRemoteHostStatus/useRemoteHostStatus.ts apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/components/WorkspaceHostOfflineState/WorkspaceHostOfflineState.tsx apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/components/WorkspaceHostOfflineState/index.ts
  • git diff --check

Open in Stage

Summary by cubic

Gates V2 workspace routes when the host is offline and shows a clear offline state. This avoids unreachable host calls and explains why terminals and file actions are unavailable.

  • New Features
    • Detect offline hosts via isOnline and return an offline status; skip remote host.info queries when offline.
    • Render a dedicated offline state with host name, Host ID, and links to host settings and the V2 workspaces list.
    • Prevent terminals and file actions from mounting when the host is offline, matching the missing-worktree gate.

Written for commit 2ef0f21. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

Release Notes

  • New Features
    • Added offline host state display for workspaces. When a host is unavailable, users now see a dedicated interface showing the host information with options to navigate to host settings or browse other workspaces.

Review Change Stack

@capy-ai
Copy link
Copy Markdown

capy-ai Bot commented May 17, 2026

Capy auto-review is paused for this organization because the monthly auto-review limit has been reached. Increase the limit or turn it off in billing settings to resume automatic reviews.

@stage-review
Copy link
Copy Markdown

stage-review Bot commented May 17, 2026

Ready to review this PR? Stage has broken it down into 3 individual chapters for you:

Title
1 Define offline status in remote host hook
2 Create WorkspaceHostOfflineState component
3 Integrate offline state into workspace layout
Open in Stage

Chapters generated by Stage for commit 2ef0f21 on May 17, 2026 5:49pm UTC.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 17, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1623b8b4-a79c-46a3-805f-04d93f8a801b

📥 Commits

Reviewing files that changed from the base of the PR and between 395b5b1 and 2ef0f21.

📒 Files selected for processing (4)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/components/WorkspaceHostOfflineState/WorkspaceHostOfflineState.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/components/WorkspaceHostOfflineState/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/hooks/useRemoteHostStatus/useRemoteHostStatus.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/layout.tsx

📝 Walkthrough

Walkthrough

The PR adds offline host detection and UI display to the v2 workspace layer. It extends RemoteHostStatus with an "offline" variant, updates the useRemoteHostStatus hook to read isOnline from the host row and return offline status immediately when detected, implements a new WorkspaceHostOfflineState component to render the offline message, and integrates offline rendering into the layout before the loading state handler.

Changes

Offline Host Detection and Rendering

Layer / File(s) Summary
RemoteHostStatus offline variant contract
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/hooks/useRemoteHostStatus/useRemoteHostStatus.ts
RemoteHostStatus union type gains an "offline" variant carrying hostId and hostName, defining the shape of offline host data passed through the application.
useRemoteHostStatus offline detection logic
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/hooks/useRemoteHostStatus/useRemoteHostStatus.ts
Hook now reads isOnline from the host row, conditionally gates the host info query only when the host is online, and returns early with { status: "offline" } when isOnline === false.
WorkspaceHostOfflineState component
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/components/WorkspaceHostOfflineState/WorkspaceHostOfflineState.tsx, apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/components/WorkspaceHostOfflineState/index.ts
New React component renders an offline state UI with host name and ID (with truncated/tooltip displays), explanatory text, and two navigation links to host settings and v2 workspaces browse page.
Layout offline status rendering
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/layout.tsx
Layout imports WorkspaceHostOfflineState and adds a conditional branch to render it when remote host status is "offline", placed before the existing "loading" handler in the status check sequence.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • superset-sh/superset#4581: Main PR's changes to the v2 remote host status pipeline (useRemoteHostStatus/RemoteHostStatus and layout.tsx rendering for offline/unavailable states) directly build on the retrieved PR's refactor that introduced remoteHostStatusPolicy and a layout branch for host unavailability.

Poem

🐰 A host goes quiet, offline and still,
We sense it swift with one isOnline nil,
A message kind appears on screen so bright,
With buttons to guide and settings in sight! 🌟

✨ 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 gate-offline-host-worktre

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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.

@Kitenite Kitenite merged commit 7ec5ee1 into main May 17, 2026
9 of 10 checks passed
@Kitenite Kitenite deleted the gate-offline-host-worktre branch May 17, 2026 17:51
@github-actions
Copy link
Copy Markdown
Contributor

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 17, 2026

Greptile Summary

This PR adds an offline-host gate to the v2 workspace detail route. When the synced host row has isOnline === false, the layout now renders a dedicated WorkspaceHostOfflineState UI instead of mounting WorkspaceProvider and attempting downstream host-service calls.

  • Hook change (useRemoteHostStatus): a new \"offline\" variant is added to RemoteHostStatus; the offline check is inserted before the infoQuery.isSuccess path so cached stale data is never mistakenly read as "incompatible" while the host is down. The infoQuery.enabled guard also gains && isReady && hostRow?.isOnline !== false, preventing relay requests from firing before the live query has hydrated.
  • Layout change: the \"offline\" case is rendered as an early return before WorkspaceProvider is mounted, matching the same pattern used for \"incompatible\".
  • New component (WorkspaceHostOfflineState): displays host name, host ID, and action links to host settings and the workspace list; consistent in structure with existing error-state components in the same folder.

Confidence Score: 4/5

Safe to merge — the offline gate is correctly inserted before WorkspaceProvider mounts, preventing relay calls to downed hosts, and the new component follows established patterns in the codebase.

The core logic is sound: isOnline === false short-circuits both the relay network request and the WorkspaceProvider render. Two observations worth tracking: the infoQuery.enabled guard now serialises what was previously a parallel fetch (minor timing change, no user-visible impact in practice), and a workspace whose host row is entirely absent bypasses the offline gate and falls through to a silent ready state on query failure — pre-existing but leaves a gap the new gate does not address.

The hook file (useRemoteHostStatus.ts) has the most behavioural surface area — the isReady addition to infoQuery.enabled and the strict === false offline check both warrant a second look.

Important Files Changed

Filename Overview
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/hooks/useRemoteHostStatus/useRemoteHostStatus.ts Adds "offline" status variant; disables infoQuery when host is offline and also gates it behind isReady, which is a behavioural change worth noting
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/layout.tsx Adds offline guard rendering WorkspaceHostOfflineState before WorkspaceProvider is mounted; guard ordering is safe since hook returns only one status at a time
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/components/WorkspaceHostOfflineState/WorkspaceHostOfflineState.tsx New offline-state UI component; clean implementation with host name/ID display and action links to host settings and workspace list
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/components/WorkspaceHostOfflineState/index.ts Barrel export for WorkspaceHostOfflineState; no issues

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[V2WorkspaceLayout mounts] --> B{workspaceId / isReady / workspaces?}
    B -- no --> C[Empty loading div]
    B -- yes --> D{workspace row?}
    D -- no, creating --> E[WorkspaceCreatingState]
    D -- no, error --> F[WorkspaceCreateErrorState]
    D -- no --> G[WorkspaceNotFoundState]
    D -- yes --> H[useRemoteHostStatus]
    H --> I{workspace?}
    I -- no --> J[status: loading]
    I -- yes --> K{isLocal?}
    K -- yes --> L[status: skip]
    K -- no --> M{isReady?}
    M -- no --> N[status: loading]
    M -- yes --> O{hostRow?.isOnline === false?}
    O -- yes --> P[status: offline]
    O -- no --> Q{infoQuery.isSuccess?}
    Q -- yes, version too old --> R[status: incompatible]
    Q -- otherwise --> S[status: ready]
    P --> T[WorkspaceHostOfflineState]
    R --> U[WorkspaceHostIncompatibleState]
    S --> V[WorkspaceProvider + Outlet]
    J --> W[Empty loading div]
    N --> W
    L --> V
Loading
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/hooks/useRemoteHostStatus/useRemoteHostStatus.ts:69-70
**`isReady` added to `infoQuery.enabled` — intentional but worth documenting**

`isReady` was not previously part of the enabled guard, so this PR changes when the relay request fires: the host-info query now waits for the live query to hydrate before dispatching. This is the correct behavior (we need `hostRow?.isOnline` before deciding whether to hit the network), but it serialises what was a parallel fetch. In practice the delay is negligible since `!isReady` already returns `"loading"`, but it's a subtle side-effect of the offline gate worth a brief comment in the code.

### Issue 2 of 2
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/hooks/useRemoteHostStatus/useRemoteHostStatus.ts:78-84
**Missing host row is not treated as offline**

The offline gate triggers only when `hostRow?.isOnline === false` (strict boolean). If there is no host row at all (`hostRow === null`, e.g. the host was deleted or has not synced yet), `isOnline` is `undefined`, the check is `false`, and the query proceeds. This asymmetry means a workspace whose host row was deleted will attempt a relay connection instead of showing the offline screen, ultimately falling through to `{ status: "ready" }` on query failure. This is pre-existing behaviour rather than a regression introduced here, but the new offline gate handles only half the "host unreachable" space — worth a comment or, at minimum, a `TODO`.

Reviews (1): Last reviewed commit: "gate offline host workspaces" | Re-trigger Greptile

Comment on lines +69 to +70
enabled:
workspace != null && !isLocal && isReady && hostRow?.isOnline !== false,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 isReady added to infoQuery.enabled — intentional but worth documenting

isReady was not previously part of the enabled guard, so this PR changes when the relay request fires: the host-info query now waits for the live query to hydrate before dispatching. This is the correct behavior (we need hostRow?.isOnline before deciding whether to hit the network), but it serialises what was a parallel fetch. In practice the delay is negligible since !isReady already returns "loading", but it's a subtle side-effect of the offline gate worth a brief comment in the code.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/hooks/useRemoteHostStatus/useRemoteHostStatus.ts
Line: 69-70

Comment:
**`isReady` added to `infoQuery.enabled` — intentional but worth documenting**

`isReady` was not previously part of the enabled guard, so this PR changes when the relay request fires: the host-info query now waits for the live query to hydrate before dispatching. This is the correct behavior (we need `hostRow?.isOnline` before deciding whether to hit the network), but it serialises what was a parallel fetch. In practice the delay is negligible since `!isReady` already returns `"loading"`, but it's a subtle side-effect of the offline gate worth a brief comment in the code.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +78 to +84
if (hostRow?.isOnline === false) {
return {
status: "offline",
hostId,
hostName: hostRow.name,
};
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Missing host row is not treated as offline

The offline gate triggers only when hostRow?.isOnline === false (strict boolean). If there is no host row at all (hostRow === null, e.g. the host was deleted or has not synced yet), isOnline is undefined, the check is false, and the query proceeds. This asymmetry means a workspace whose host row was deleted will attempt a relay connection instead of showing the offline screen, ultimately falling through to { status: "ready" } on query failure. This is pre-existing behaviour rather than a regression introduced here, but the new offline gate handles only half the "host unreachable" space — worth a comment or, at minimum, a TODO.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/hooks/useRemoteHostStatus/useRemoteHostStatus.ts
Line: 78-84

Comment:
**Missing host row is not treated as offline**

The offline gate triggers only when `hostRow?.isOnline === false` (strict boolean). If there is no host row at all (`hostRow === null`, e.g. the host was deleted or has not synced yet), `isOnline` is `undefined`, the check is `false`, and the query proceeds. This asymmetry means a workspace whose host row was deleted will attempt a relay connection instead of showing the offline screen, ultimately falling through to `{ status: "ready" }` on query failure. This is pre-existing behaviour rather than a regression introduced here, but the new offline gate handles only half the "host unreachable" space — worth a comment or, at minimum, a `TODO`.

How can I resolve this? If you propose a fix, please make it concise.

Kitenite added a commit that referenced this pull request May 19, 2026
Reverts the layout wiring and useRemoteHostStatus offline branch from
7ec5ee1. Keeps WorkspaceHostOfflineState
component on disk (unused) for later use.
sazabi Bot pushed a commit that referenced this pull request May 20, 2026
sazabi Bot pushed a commit that referenced this pull request May 20, 2026
Reverts the layout wiring and useRemoteHostStatus offline branch from
7ec5ee1. Keeps WorkspaceHostOfflineState
component on disk (unused) for later use.
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