Conversation
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
c4ea74d to
86f84fc
Compare
- 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.
Wire up DeveloperChat panel and ChatToggle button to the cloud edit pages, matching the same layout pattern used in web-local.
…ng-mvp # Conflicts: # admin/server/deployment.go # web-common/src/features/canvas/CanvasPreviewCTAs.svelte
- Gate `EditButton` behind `$cloudEditing` feature flag (was `true`) - Restore `@apply ui-copy-number` in vega.css (was accidentally commented out) - Restore `generatingCanvas` overlay and `resource`/`remoteContent` props in `WorkspaceDispatcher` (dropped during extraction from web-local) - Remove invalid `branch` prop passed to `ProjectOverview` - Suppress `a11y_autofocus` warnings in `EditButton` - Add missing cloud editing routes: 8 connector table previews and graph
…feature flag test - Extract `cancelAsErrored` and promote `isNonRetryable` to methods on `ReconcileDeploymentWorker` to deduplicate error handling - Fix branch permissions in `GetProject`: split read/write so viewers get dashboard access (`ReadInstance`, `ReadOLAP`, `ReadResolvers`) and only `ManageDev` editors get full dev access (`ReadProfiling`, `ReadRepo`, `EditRepo`, `EditTrigger`) - Add `cloudEditing` to feature flags test expectations - Extract `GraphWorkspace` into `web-common` to share between web-local and web-admin
…ng-mvp # Conflicts: # web-local/src/routes/(application)/(workspace)/files/[...file]/+page.svelte
The module is imported across ~30 features (sources, connectors, entity-management, models, metrics-views, file-explorer, resource-graph, etc.), not just workspaces. Relocate it alongside the other cross-cutting navigation helpers and rename to `editor-routing` since it covers the editor surface (local + cloud edit session), not "edit mode" only.
…outePrefix` Align symbol names with the `editor-routing.ts` filename, and clarify that the helper just prepends the editor route prefix.
The cloud editing surface at `web-admin/[organization]/[project]/-/edit/` is supposed to mirror the editing routes in `web-local/src/routes/`, with shared components navigating via `editorRoutePrefix`. Nothing enforced that — the two trees could drift as the editing surface evolves. `scripts/check-edit-route-parity.js` walks both trees, compares logical paths symmetrically, and fails on unexpected divergence. Known intentional gaps are tracked in per-side allowlists with reason comments. Pattern mirrors `scripts/tsc-with-whitelist.sh`; wired into `scripts/web-test-code-quality.sh` and exposed as `npm run check:edit-route-parity` for local runs.
Fill in five routes that existed only in Rill Developer:
- `connector/{clickhouse,druid,duckdb,pinot}/+page.ts`: 307 redirect to
the edit home when the user hits a connector root without instance
params. Preserves the `@branch` segment via path splitting.
- `explore/[name]/+layout.svelte`: adds a `DeveloperChat` sidebar next
to the preview explore, matching the chat layout in Rill Developer.
Also tightens the parity-check allowlist: removes the five entries
above, groups the remaining AI citation fallback routes under a single
TODO about preserving edit-session context on citation navigation, and
keeps the legacy `/dashboard/[name]` redirect as a permanent local-only.
`web-local` mounts `DeveloperChat` once in `(workspace)/+layout.svelte`, but `web-admin/-/edit/` had it duplicated across `+page.svelte`, `files/[...file]/+page.svelte`, and `explore/[name]/+layout.svelte`, while `canvas`, `connector`, and `graph` routes had no chat at all. Hoist `DeveloperChat` into `-/edit/+layout.svelte` next to `<slot />` so every edit route gets it consistently, matching the `web-local` pattern. Also fix the `explore/[name]/+layout.svelte` divergence: `web-local` uses `DashboardChat` there (dashboard-scoped), not `DeveloperChat`. Mirror that.
AdityaHegde
left a comment
There was a problem hiding this comment.
File links from add-data are not replaced. ImportDataStatus.svelte and GenerateDashboardStatus.svelte need updating.
| private client = new SSEFetchClient(); | ||
|
|
||
| private autoCloseThrottler: Throttler | undefined; | ||
| private autoCloseDisabled = false; |
There was a problem hiding this comment.
How about calling this keepAlive?
There was a problem hiding this comment.
Honestly, this PR currently hacks the SSE client in various ways– the layers between abstractions are blurring together. Here is a standalone PR (WIP) for a proper refactor.
Route add-data and model CTA navigation through editor routing helpers so edit sessions stay scoped to /-/edit, and invalidate git status after push so commit UI reflects repo state immediately.
AdityaHegde
left a comment
There was a problem hiding this comment.
Another round of comments. Mainly on the backend.
There was a problem hiding this comment.
Will need @kaspersjo / @begelundmuller inputs on changes here.
- If we need to retry for resources availability(which I think we should) then just 4 minutes worth retry seems little less and retrying after 15s - 30s may be too aggressive.
- The
ErrNoCapacityseems to be only returned for static runtimes which are not used in production as of now.
There was a problem hiding this comment.
2 is not valid since dynamic provisioner is never out of capacity. But then it means we still want to wait for scale up in which case the retry time is insufficient (point no 1).
There was a problem hiding this comment.
My override to River's retry timing was an earlier effort to fast-fail when the deployment couldn't be provisioned due to hitting capacity with the static provisioner (in development). Since then, I've classified a few errors as "non-retryable" to fast-fail immediately. So I just removed that "NextRetry" override, to just use the River default for now.
AdityaHegde
left a comment
There was a problem hiding this comment.
- Changing project while in edit should not keep the
-/editpath, it can lead to unwanted edit session. - Creating a dev branch on self managed git kept failing for me. I got
repo is not watchableerror through SSE. - Another missing link update in
web-common/src/components/ErrorPage.svelte. Might need to update once #9268 is merged.
Couldnt really check more since the edit session kept erroring out for me.
| const filePath = resource?.meta?.filePaths?.[0]; | ||
| if (filePath) { | ||
| await navigateToFile( | ||
| filePath.startsWith("/") ? filePath : `/${filePath}`, |
There was a problem hiding this comment.
Better to continue using removeLeadingSlash. Will be easy to fix if and when we normalise all sources of paths.
| </Button> | ||
| </div> | ||
| {:else} | ||
| <!-- Raw button (not DropdownMenu.Item) so clicking doesn't close the menu --> |
There was a problem hiding this comment.
How about using a Popover instead?
MVP — merging behind the
cloud_editingfeature flag (default off) so we can test on cloud infrastructure.Cloud Editing lets users edit Rill projects directly in the browser. Click "Edit" on a project, a dev deployment spins up on a branch, and you get the same file explorer, code editor, and workspace views as Rill Developer — running in the cloud.
What's in this PR
Edit session (new
/-/edit/route tree inweb-admin)Its own
RuntimeProvider, a persistent file/resource watcher, and workspace pages for files, explores, canvases, and the resource graph. Includes theEditButtonbranch picker,CommitPopoverfor committing + pushing, a session-timeout banner, and single-editor lock with loading / stopped / errored states.Shared routing abstraction (
web-common/layout/navigation/editor-routing.ts)Replaces hardcoded
/files/...paths with helpers (navigateToFile,navigateToHome,getFileHref, …) so the same components work in both local (/files/...) and cloud (/<org>/<project>/@<branch>/-/edit/files/...) contexts.A new CI check (
scripts/check-edit-route-parity.js) enforces route-tree parity betweenweb-localandweb-admin/.../-/edit/: if you add a route on one side without mirroring it on the other (or explicitly allowlisting it with a reason), CI fails. This keeps the two surfaces from drifting as we add new route types.Backend
devSlotsreduced from 8 to 4Known gaps (before removing the feature flag)
Closes APP-174
Checklist:
Developed in collaboration with Claude Code