Skip to content

Cloud editing MVP#8912

Draft
ericpgreen2 wants to merge 36 commits intomainfrom
ericgreen/cloud-editing-mvp
Draft

Cloud editing MVP#8912
ericpgreen2 wants to merge 36 commits intomainfrom
ericgreen/cloud-editing-mvp

Conversation

@ericpgreen2
Copy link
Contributor

@ericpgreen2 ericpgreen2 commented Feb 23, 2026

This is an MVP / work-in-progress. Not ready for production. Sharing for visibility.

Cloud editing lets users edit Rill projects directly in the browser. Clicking "Edit" on a project spins up a dev deployment on a branch, and the user gets the same file explorer, code editor, and workspace views they'd see in Rill Developer — but running in the cloud.

Builds on #9011 (branch deployment previews via @branch path segments).

Editing:

  • "Edit" button creates a dev deployment and opens the cloud editor
  • Native shared components from web-common (file explorer, code editor, workspace views)
  • Single-editor lock prevents concurrent editing on the same branch
  • SSE connection kept alive, given we don't have the same connection management quotas that we have on local

Status page improvements:

  • New "Deployments" sub-page showing all deployments (production + dev branches) with status and slot allocation
  • Status Overview "Deployment" card reflects the currently viewed branch
  • Branch-aware resource, table, and log views
  • Project-scoped pages (Settings, Deployments list) show info banners clarifying they apply to the entire project

Known gaps:

  • Branch deploy review workflow (propose → approve → merge)
  • AI generation and source import modals don't use workspaceRoute yet
  • No automated tests for edit session flows

Checklist:

  • Covered by tests
  • Ran it and it works as intended
  • Reviewed the diff before requesting a review
  • Checked for unhandled edge cases
  • Linked the issues it closes
  • Checked if the docs need to be updated. If so, create a separate Linear DOCS issue
  • Intend to cherry-pick into the release branch
  • I'm proud of this work!

Developed in collaboration with Claude Code

@ericpgreen2 ericpgreen2 changed the title WIP: Cloud editing MVP — native editing surface WIP: Cloud editing MVP Feb 23, 2026
Add a branch selector chip to the project header that lets admins
switch between branch deployments directly in the cloud UI. Gated
on `readDev` permission.

- New `BranchSelector` component (chip + dropdown, modeled after `ViewAsUserChip`)
- Read `?branch=X` query param in project layout, pass to `GetProject` API
- Warning banner when viewing a non-production branch deployment
- Branch param preserved across tab navigation via `branchSearchSuffix`
- "Start deployment" button for stopped branch deployments
- Deduplicates `ListDeployments` by branch; live status from `GetProject`
- "View As" composes with branch context
Move `BranchSelector` from a standalone header chip into the avatar
button dropdown as a submenu (like "View as"), reducing visual clutter
when viewing branch deployments. Replace `ProjectAccessControls` wrapper
in `AvatarButton` with a `projectPermissions` prop passed from
`ProjectHeader`, eliminating a redundant `GetProject` query. Clean up
branch-related props from `SlimProjectHeader` and `ProjectHeader`.
…ments

Replace `?branch=X` query params with `@branch` path segments for branch
deployment previews (e.g., `/org/project/@feature-x/explore/dashboard`).

- Add `reroute` hook to strip `@branch` before route matching
- Add `beforeNavigate` hook to inject `@branch` into branch-unaware links
- Add `branch-utils.ts` with path manipulation helpers
- Use `~` encoding for `/` in branch names (git disallows `~` in refs)
- Branch menu items render as `<a>` tags for href preview on hover
- Back/forward browser history works correctly (skip injection on popstate)
- Rewrite BranchSelector from avatar dropdown submenu to standalone
  dropdown styled as a compact pill (matching the Chip component's
  dimension style) positioned after the project breadcrumb
- Add `after-project` slot to Breadcrumbs component for the pill
- Remove the yellow branch preview banner (redundant with the pill)
- Show branch selector on all project pages, not just Home
- Branch-centric labels: trigger shows truncated branch name,
  dropdown shows branch names with "production" suffix for primary
- Gate on `readDev` permission
- Add TTL-based auto-expiry (500ms) to skip-branch-injection flag to
  prevent stale flags from leaking across navigations
- Extract stopped deployment UI into `BranchDeploymentStopped` component
  using the project's Button and CTA layout patterns
- Show spinner for STOPPING state instead of the "Start deployment" button
- Move `startDeploymentMutation` into the extracted component so it is
  not instantiated on every project page load
- Replace hardcoded "main" fallback with `primaryBranch` from the
  project query
- Add clarifying comments for ISO 8601 string comparison and breadcrumb
  depth assumption
Move branch-related files into a dedicated feature directory and
centralize logic that was scattered across the codebase:

- Move BranchSelector, BranchDeploymentStopped, branch-utils to features/branches/
- Extract `getBranchRedirect` from the project layout's beforeNavigate hook
- Reuse `removeBranchFromPath` in hooks.ts reroute (removes duplicate regex)
Move the beforeNavigate branch injection logic into a single testable
function in branch-utils.ts. The layout's callback becomes a one-liner
that delegates to the feature module.
- Replace BranchSelector's `getStatusColor` with shared `getStatusDotClass`
- Remove duplicate `GetProject` query from BranchSelector; accept
  `primaryBranch` as a prop threaded from the layout
- Change `getBranchRedirect` to accept a `URL` object instead of three
  string parameters
- Reorder `handleBranchNavigation` guards so `activeBranch` is checked
  before consuming the skip flag
- Simplify `consumeSkipBranchInjection` to always-clear-on-read
- Replace redundant integration tests with a search+hash test and add
  prefix-collision edge case for `getBranchRedirect`
`SlimProjectHeader` is rendered when the deployment isn't running.
Without the `BranchSelector`, users on a stopped branch deployment
had no way to switch back to production or another branch.
…r lock

- Add edit session feature in web-admin with iframe-based Rill Developer embed
- Add "Edit" tab to ProjectTabs (gated on `manageDev` permission)
- Add `/<org>/<project>/-/edit/` route for the edit session view
- Add single-editor lock in `CreateDeployment` to prevent concurrent edit sessions
- Edit session auto-creates a dev deployment, polls for readiness, fetches
  credentials, and embeds web-local in an iframe
- Toolbar provides "Push to production" (git push) and "End session" (teardown)
- Timeout warning banner shown 10 minutes before session expiry
- Create workspace routing abstraction (`workspaceRoutePrefix` store) so
  shared web-common components build correct paths in both web-local and
  web-admin edit sessions
- Extract `WorkspaceDispatcher` component (resource kind to workspace mapping)
  from web-local into web-common for reuse
- Update ~15 web-common navigation/file-explorer files to use routing helpers
  instead of hardcoded paths
- Add SvelteKit routes for edit session: files, explore, canvas
- Refactor edit layout to render Navigation sidebar + WorkspaceDispatcher
  instead of iframe
- Skip parent RuntimeProvider on edit routes to prevent runtime store conflicts
  between production and dev deployment credentials
- Fix concurrent map write crash in `auth/claims.go` (copy Attrs map instead
  of mutating shared instance)
- Add `ReadInstance` permission to dev deployment JWTs so Data Explorer works
- Fix `ProjectGlobalStatusIndicator` crash from dev deployment response shape
- Defer file content fetch until runtime credentials are available (fixes 404
  on full page refresh)
- Replace the "Edit" tab in `ProjectTabs` with a session-aware "Edit"
  button in `ProjectHeader` (shows "Resume editing" / "Editing locked"
  based on session state)
- Add "Dev Environments" tab to the Status page left nav with a table
  of dev deployments (branch, status, last updated, actions via
  three-dot menu)
- Migrate edit session pages from legacy runtime store to
  `RuntimeProvider` / `useRuntimeClient`
- Fix race condition where `FileArtifact` objects created during
  `+page.ts` load received an undefined client; `setClient()` now
  propagates to existing artifacts
- Guard `useResource` / `useResourceV2` against undefined client
@ericpgreen2 ericpgreen2 force-pushed the ericgreen/cloud-editing-mvp branch from c4ea74d to 86f84fc Compare March 11, 2026 13:31
- Edit layout extracts branch from `@branch` URL segment and looks up
  deployment by branch name instead of "first active deployment"
- EditButton navigates to `/@branch/-/edit` using the deployment's branch
- DevEnvironmentsSection links use `@branch` for Resume and adds Preview
- EditSessionToolbar shows branch name and navigates to production on end
- Edit layout shows 403 error page when visiting another user's edit URL
  with a "Preview this branch" link
- Add `useDevDeploymentByBranch` and export `isActiveDeployment` from
  use-edit-session
Cherry-pick d8c165f (reset retries on client-initiated pause) plus
reset retryAttempts in start() so that switching to a new endpoint
(e.g. entering a cloud edit session) doesn't inherit stale retry counts
from a previous connection.
The project layout now renders ProjectHeader for edit pages when the
deployment is available. This gives edit sessions the same breadcrumbs,
branch selector, and navigation as other project pages. The EditButton
is hidden when on an edit page since the user is already editing.
Replace the two-row header (ProjectHeader + EditSessionToolbar) with a
single header row. The edit layout publishes session state via an
`editSessionState` store; ProjectHeader reads it to render "End session"
and "Push to production" buttons in place of Share/EditButton when in
edit mode. The redundant "EDITING ON branch" label is removed since the
branch selector already shows the active branch.
The ProjectParser resource stays RUNNING indefinitely on dev/branch
deployments (it watches for file changes). `smartRefetchIntervalFunc`
saw this in the unfiltered `ListResources` response and polled forever.

Add `createSmartRefetchInterval(predicate)` factory so callers can
scope polling to only the resources they display. Apply it to
`useDashboards` (canvas/explore only) and `useResources` on the
status page (visible, non-internal kinds only).
FileAndResourceWatcher never passed a JWT to its SSE connection.
In cloud, the SSE endpoint requires authentication, causing an
infinite reconnect loop. Pass `getJwt` callback and add a URL
idempotency guard to prevent redundant reconnections.
`lineMarkerChange` had `effectPresent || update` where `update` is
always truthy, causing gutter markers to be destroyed and recreated
on every view update (scroll, hover, focus). Check `docChanged`,
`selectionSet`, or lineStatus effects instead.
When showFooterLinks was false, Footer rendered an empty bordered
strip. Instead, don't render Footer at all and remove the prop;
Footer now always shows its full content when rendered.
Replace the edit layout's inline header with the real ProjectHeader
for visual parity (breadcrumbs, BranchSelector, dropdowns). Add
`editContext` prop to ProjectHeader so it renders EditActions instead
of EditButton/ShareProjectPopover when in an edit session.

- Edit layout fetches its own GetProject({branch}) for metadata
- Remove `editSessionState` global store; pass props directly
- Exclude edit routes from `isProjectPage` in nav-utils
- Project layout renders only `<slot />` for edit pages
Use `window.location.href` instead of `goto()` when ending an edit
session to avoid a race where `useRuntimeClient()` is called before the
layout's RuntimeProvider remounts. Also fix the "Start deployment"
button in BranchDeploymentStopped which used `on:click` instead of the
Button component's `onClick` prop.
The BranchSelector's ListDeployments query (keyed with `{}` params) was
never invalidated when deployments changed — only the dev-scoped query
(`{ environment: "dev" }`) was. This caused stale green dots for stopped
branches.

Three changes:
1. Add refetchInterval to BranchSelector that polls every 2s while any
   deployment is in a transitional state (pending/updating/stopping).
2. Invalidate all ListDeployments queries (using base key without
   params) when the layout detects a deployment status change via
   GetProject polling.
3. Rename `invalidateDevDeployments` → `invalidateDeployments` and
   broaden its key to match all deployment queries, not just dev-scoped.
Extract the repeated `<div class="h-36"><Spinner size="7rem" ...></div>`
pattern into a shared `LoadingSpinner` component (3rem, h-16) used
across 13 files. Also add a `branch` prop to `ProjectBuilding` so it
shows "Starting branch deployment..." instead of the generic deploy
message when viewing a non-production branch.
- Replace EditButton with branch picker popover (list active sessions,
  create new branches by name, show deployment status dots)
- Close editor navigates to branch preview instead of main
- Remove single-editor lock; keep per-branch uniqueness
- Remove "New edit session" from Dev Environments (header Edit is primary)
- Deduplicate ListDeployments queries: useAllDeployments shares cache key
  with BranchSelector; BranchSelector only polls while dropdown is open
- Edit layout reads deployment data from GetProject instead of separate
  ListDeployments + GetDeployment calls
- Parent layout skips aggressive polling on edit pages; edit layout owns
  its own 2s poll while PENDING/UPDATING
- Surface provisioning errors in statusMessage so frontend can display them
- Show error UI with "Go back" when provisioning fails, instead of spinner
- Mark deployment as ERRORED on last River retry attempt
- Sort Dev Environments table by updatedOn to prevent reordering on refetch
- Reduce `ReconcileDeployment` max attempts from 25 (~3 weeks) to 5 (~4 min)
  with custom exponential backoff (15s, 30s, 60s, 120s)
- Detect non-retryable errors (no available slots, invalid environment/version)
  and immediately cancel the job via `river.JobCancel`, marking the deployment
  as ERRORED
- Show `SlimProjectHeader` with branch selector on edit session error/403/404
  pages so users can navigate back to main
- Optimistically remove deleted deployments from Dev Environments table
- Simplify `EditSessionLoading` by removing `statusMessage`-based error
  detection (errors now surface via ERRORED status instead)
Delete EditSession.svelte and EditSessionToolbar.svelte, which were
superseded by the native RuntimeProvider approach in the edit layout.
Remove unused exports (useActiveDevDeployment, useDevDeploymentByBranch)
and the now-unnecessary Readable import from use-edit-session.ts.
- Add ReadRepo and EditRepo to JWTs issued by GetProject for branch
  deployments when the user has ManageDev permission; fixes 403 on
  ListFiles/GetFile/PutFile in the native cloud editor.
- Add confirmation dialog before deleting a dev environment; navigate
  to production when deleting the currently viewed branch.
- Fix blank page on editor landing by guarding auto-navigate to fire
  only once, preferring rill.yaml as the default file.
- Render "Close editor" and "Open editor" as <a> tags so the
  destination URL is visible on hover.
The SSE auto-close (2 min idle timeout) exists to manage the browser's
6-connection-per-host limit on localhost. In the cloud editor, each
deployment has its own host, so this limit isn't a concern. Disabling
auto-close prevents a race where PutFile succeeds but the SSE event
confirming the write is lost because the connection was paused.
- Switch EditButton from Popover to DropdownMenu for visual consistency
  with the BranchSelector chip
- Add "Your branches" / "Create a branch" labels to the Edit dropdown
- Add "All branches" label to the BranchSelector dropdown
- Show the Edit button on explore and canvas dashboard pages (not just
  project/status pages)
- Always label the button "Edit" instead of toggling to "Open editor"
- Rename "Dev Environments" to "Deployments" and include the production
  deployment in the table alongside dev branches
- Add slot usage cards showing production and dev branch allocations
- Add Slots column to the deployments table
- Deduplicate deployments by branch (keep most recent per branch)
- Show slots only for active deployments; inactive show "—"
- Fix `projToDTO` to include `DevSlots` in the API response
- Move Deployments tab to second position in status nav
- Rename route from /status/dev to /status/deployments
- Rename edit action buttons to "Done" (with tooltip) + "Merge to production"
- Add fallback content to edit root page when auto-navigate doesn't fire
Settings and Deployments pages are project-wide but the branch selector
injects @Branch into their URLs. Add info callouts so users understand
these pages aren't scoped to the active branch.
The Deployment card on Status > Overview always showed the production
deployment because `useProjectDeployment` and the direct `GetProject`
call in `DeploymentSection` never passed the branch param. Thread the
active branch from the URL through to both API calls so the card
reflects the deployment the user is actually viewing.
@ericpgreen2 ericpgreen2 changed the title WIP: Cloud editing MVP Cloud editing MVP Mar 13, 2026
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