Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
19f6897
feat: add RuntimeClient, RuntimeProvider, and ConnectRPC proto gen (P…
ericpgreen2 Feb 24, 2026
ba367e8
feat: add TanStack Query hook code generator (Phase 2)
ericpgreen2 Feb 24, 2026
8cdc22d
feat: update invalidation and query matching for dual key formats (Ph…
ericpgreen2 Feb 24, 2026
3aaa80d
fix: resolve type errors in generated query hooks
ericpgreen2 Feb 24, 2026
366c809
fix: prevent reactive loop in runtime store bridge
ericpgreen2 Feb 24, 2026
13adf06
feat: add JSON bridge to v2 code generator (Phase 4)
ericpgreen2 Feb 24, 2026
243dd49
feat: add generic TData support to v2 query hooks for select transforms
ericpgreen2 Feb 24, 2026
a77cf00
fix: strip undefined values before proto fromJson in JSON bridge
ericpgreen2 Feb 24, 2026
369e0b5
fix: emit default values in proto toJson to match gRPC-Gateway output
ericpgreen2 Feb 24, 2026
301244f
fix: deep-strip undefined values in `stripUndefined` for nested reque…
ericpgreen2 Feb 24, 2026
840e757
feat: port request queue to ConnectRPC transport interceptor
ericpgreen2 Feb 25, 2026
ae800e0
refactor: migrate connectors and column-profile to v2 RuntimeClient
ericpgreen2 Feb 24, 2026
d760301
refactor: migrate more connectors components to v2 RuntimeClient
ericpgreen2 Feb 24, 2026
133a411
refactor: migrate column-profile, canvas, and remaining connectors to…
ericpgreen2 Feb 24, 2026
fafeda1
fix: restore select transforms now that v2 hooks support generic TData
ericpgreen2 Feb 24, 2026
46ae340
refactor: migrate chart providers and canvas leaf components to v2 Ru…
ericpgreen2 Feb 24, 2026
25a80d1
refactor: add runtimeClient to dashboard StateManagers and migrate co…
ericpgreen2 Feb 24, 2026
8392af2
refactor: migrate dashboard time-series and selector modules to v2 Ru…
ericpgreen2 Feb 24, 2026
b65d646
refactor: migrate dashboard Svelte components from runtime store to u…
ericpgreen2 Feb 24, 2026
e7bc93b
fix: update test infrastructure for v2 ConnectRPC hooks
ericpgreen2 Feb 24, 2026
2267e4d
refactor: migrate export and pivot-query modules from runtime store t…
ericpgreen2 Feb 24, 2026
d4e0b17
refactor: migrate time controls and time ranges from runtime store to…
ericpgreen2 Feb 24, 2026
bfe9b4b
refactor: migrate canvas, explores, and state-managers from runtime s…
ericpgreen2 Feb 24, 2026
5947503
refactor: thread `RuntimeClient` through `.ts` query factories and re…
ericpgreen2 Feb 24, 2026
fb10785
refactor: migrate web-common features from `runtime` store to `Runtim…
ericpgreen2 Feb 25, 2026
fe3b390
fix: update conversation tests to use mock `RuntimeClient`
ericpgreen2 Feb 25, 2026
2102ddd
refactor: migrate remaining `.ts` modules from runtime store to Runti…
ericpgreen2 Feb 25, 2026
8061a16
refactor: cleanup — migrate embed to v2 RuntimeProvider, delete old p…
ericpgreen2 Feb 25, 2026
2b11911
refactor: delete unused `StreamingQueryBatch` and fix `createDownload…
ericpgreen2 Feb 25, 2026
b777e09
refactor: migrate remaining legacy consumers + delete Orval gen and h…
ericpgreen2 Feb 25, 2026
63c62ba
fix: three UXQA bugs — empty GetFile path, missing TableCardinality p…
ericpgreen2 Feb 26, 2026
b1dd0f6
fix: resolve TypeScript and svelte-check errors from v2 migration
ericpgreen2 Feb 26, 2026
4ddc1d5
fix: provide RuntimeClient to TopNavigationBar via global store
ericpgreen2 Feb 26, 2026
def18ff
fix: prevent infinite SSE reconnection loop when server closes immedi…
ericpgreen2 Feb 26, 2026
3ade689
fix: pass JWT to SSE log connection and forward options to fetch client
ericpgreen2 Feb 26, 2026
4338016
fix: retarget barrel to v2/gen and fix remaining legacy imports
ericpgreen2 Feb 26, 2026
2192094
refactor: migrate all remaining consumers to v2 RuntimeClient signatures
ericpgreen2 Feb 26, 2026
6fa0bcb
fix: resolve all svelte-check and unit test errors from v2 migration
ericpgreen2 Feb 26, 2026
826b3dd
merge: resolve conflicts from main, migrate generateCanvas.ts to v2 R…
ericpgreen2 Feb 26, 2026
9c65c7b
fix: resolve remaining v2 RuntimeClient migration errors blocking build
ericpgreen2 Feb 26, 2026
9e022c6
fix: remove dead `instanceId` vars and fix remaining v2 call signatures
ericpgreen2 Feb 26, 2026
5213771
fix: remove unused `runtimeClient` in `NavFile`, fix `$lib` alias in …
ericpgreen2 Feb 26, 2026
a1ca2fd
fix: allow empty-string host in RuntimeProvider, fix `client` arg in …
ericpgreen2 Feb 26, 2026
3f2591f
fix: set `FileArtifacts` client synchronously to prevent undefined ac…
ericpgreen2 Feb 26, 2026
ca80172
fix: validate `RuntimeClient` constructor args, remove redundant temp…
ericpgreen2 Feb 26, 2026
5a3a103
fix: replace manual REST `fetch()` calls with v2 RPC, remove dead que…
ericpgreen2 Feb 27, 2026
7fa13bd
fix: update web-local for v2 RPC compatibility
ericpgreen2 Feb 27, 2026
0a02a6a
fix: handle ConnectRPC errors in REST-style error checks
ericpgreen2 Feb 27, 2026
12fec35
fix: replace REST-style error handling with ConnectRPC-compatible uti…
ericpgreen2 Feb 27, 2026
fc5e973
fix: update timeseries e2e test to match ConnectRPC URL pattern
ericpgreen2 Feb 27, 2026
23459c0
fix: guard `RuntimeProvider` mount until runtime connection props res…
ericpgreen2 Feb 27, 2026
cb82774
fix: use `runtimeClientStore` in `ProjectGlobalStatusIndicator` and e…
ericpgreen2 Feb 27, 2026
fe517ce
merge main, resolve conflict in `DeploymentSection.svelte`
ericpgreen2 Feb 27, 2026
a5ff1dc
fix: `Heap.delete` must try `moveUp` before `moveDown`
ericpgreen2 Mar 2, 2026
c244546
fix: `removeByName` must reject pending promises before deleting
ericpgreen2 Mar 2, 2026
d703a07
refactor: use `async/await` in generated base functions
ericpgreen2 Mar 2, 2026
3f2c517
fix: guard `runtimeClientStore` clear against stale identity
ericpgreen2 Mar 2, 2026
ef2e38f
chore: remove `frontend.md` from this branch
ericpgreen2 Mar 2, 2026
5a71e78
chore: restore `generate:runtime-client` script name, document Orval …
ericpgreen2 Mar 2, 2026
e8ef7ca
fix: add 60s timeout to `waitForFreshJwt`
ericpgreen2 Mar 2, 2026
e3d528c
fix: add `RequestQueue.clear()` and use it in `dispose()`
ericpgreen2 Mar 2, 2026
e7d4ac8
fix: tear down `featureFlags` subscription on RuntimeProvider unmount
ericpgreen2 Mar 2, 2026
da3fcd5
fix: remove unused `prioritiseColumn` from `RequestQueue`
ericpgreen2 Mar 2, 2026
a9b85ed
fix: skip generating hooks for instance-management methods
ericpgreen2 Mar 2, 2026
4974e52
chore: move query hooks generator into `runtime-client/v2/`
ericpgreen2 Mar 2, 2026
04fccc4
refactor: adopt `ConnectError` as the TanStack Query error type
ericpgreen2 Mar 2, 2026
b1f0e97
fix: update `smartRefetchIntervalFunc` and `useCanvas` to use `Connec…
ericpgreen2 Mar 2, 2026
ff41139
chore: standardize import paths to use runtime-client barrel
ericpgreen2 Mar 2, 2026
674d583
fix: use extractErrorMessage in RenameAssetModal
ericpgreen2 Mar 2, 2026
fc5c049
test: add tests for query hooks code generator
ericpgreen2 Mar 2, 2026
2411e80
merge main, resolve conflicts from MeasureChart refactor (#8752)
ericpgreen2 Mar 3, 2026
c380c52
fix: convert Luxon DateTimes to UTC before `.toISO()` for proto Times…
ericpgreen2 Mar 3, 2026
765c697
fix: detect empty time range from access controls with ConnectRPC
ericpgreen2 Mar 3, 2026
3598037
fix: unit test failures in DashboardStateManager
ericpgreen2 Mar 3, 2026
300b6a9
merge main, resolve conflicts from generateCanvas feature flag removal
ericpgreen2 Mar 4, 2026
15583f7
refactor: unify runtime client access with cached `getRuntimeClient()…
ericpgreen2 Mar 4, 2026
ed2a019
refactor: eliminate `RuntimeContextBridge` and `runtimeClientStore`
ericpgreen2 Mar 4, 2026
34e71b7
fix: header border on project page and duplicate share button on dash…
ericpgreen2 Mar 5, 2026
4d1fb74
fix: avatar flicker during header transitions and redundant `GetCurre…
ericpgreen2 Mar 5, 2026
75c3d47
merge main, resolve conflicts from codegen and connector form changes
ericpgreen2 Mar 6, 2026
dc1e5fe
remove old generate-query-hooks files replaced by codegen/
ericpgreen2 Mar 6, 2026
054fba2
fix review issues: header height, avatar reactivity, types, and templ…
ericpgreen2 Mar 6, 2026
d75224a
extract shared breadcrumb selectors with `select` transforms
ericpgreen2 Mar 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 47 additions & 6 deletions web-admin/src/features/authentication/AvatarButton.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
<script context="module" lang="ts">
// Navigating between org and project pages swaps OrgHeader for ProjectHeader
// (and vice versa). Both headers render an AvatarButton, but the old one
// unmounts before the new one mounts. A normal <img> would be destroyed and
// recreated, forcing the browser to re-decode the photo — causing a visible
// flicker or broken-image flash.
//
// To avoid this, we keep a single <img> element at module scope. Each
// AvatarButton instance adopts it via appendChild on mount and detaches it
// on unmount. The browser retains the decoded image data, so it paints
// instantly with no flash.
let sharedImg: HTMLImageElement | null = null;
</script>

<script lang="ts">
import { onMount } from "svelte";
import { page } from "$app/stores";
import { redirectToLogout } from "@rilldata/web-admin/client/redirect-utils";
import * as DropdownMenu from "@rilldata/web-common/components/dropdown-menu";
Expand All @@ -14,9 +29,40 @@
const user = createAdminServiceGetCurrentUser();
let imgContainer: HTMLElement;
let primaryMenuOpen = false;
let subMenuOpen = false;
onMount(() => {
const photoUrl = $user.data?.user?.photoUrl;
if (!sharedImg) {
sharedImg = document.createElement("img");
sharedImg.className = "h-7 w-7 rounded-full";
sharedImg.referrerPolicy = "no-referrer";
sharedImg.alt = "avatar";
}
if (photoUrl && sharedImg.src !== photoUrl) {
sharedImg.src = photoUrl;
}
imgContainer.appendChild(sharedImg);
return () => {
// Only detach if we're still the owner; a newer instance may have
// already adopted the element via appendChild.
if (sharedImg?.parentNode === imgContainer) {
sharedImg.remove();
}
};
});
// Keep src in sync if the user query resolves or changes after mount
$: if (
sharedImg &&
$user.data?.user?.photoUrl &&
sharedImg.src !== $user.data.user.photoUrl
) {
sharedImg.src = $user.data.user.photoUrl;
}
$: if ($user.data?.user) {
// Actions to take when the user is known
posthogIdentify($user.data.user.id, {
Expand All @@ -34,12 +80,7 @@

<DropdownMenu.Root bind:open={primaryMenuOpen}>
<DropdownMenu.Trigger class="flex-none">
<img
src={$user.data?.user?.photoUrl}
alt="avatar"
class="h-7 inline-flex items-center rounded-full"
referrerpolicy="no-referrer"
/>
<div bind:this={imgContainer} class="h-7 w-7" />
</DropdownMenu.Trigger>
<DropdownMenu.Content>
{#if params.organization && params.project}
Expand Down
1 change: 1 addition & 0 deletions web-admin/src/features/authentication/checkUserAccess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export async function redirectToLoginIfNotLoggedIn() {
const userQuery = await queryClient.fetchQuery<V1GetCurrentUserResponse>({
queryKey: getAdminServiceGetCurrentUserQueryKey(),
queryFn: () => adminServiceGetCurrentUser(),
staleTime: 5 * 60 * 1000, // 5 minutes; prevents refetches on every navigation/hover
});
const isLoggedIn = !!userQuery.user;
if (isLoggedIn) {
Expand Down
103 changes: 103 additions & 0 deletions web-admin/src/features/navigation/breadcrumb-selectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import type { PathOption } from "@rilldata/web-common/components/navigation/breadcrumbs/types";
import {
createAdminServiceListOrganizations,
createAdminServiceListProjectsForOrganization,
type V1Organization,
} from "../../client";

/**
* Query selector for organization breadcrumb paths.
*
* Uses `select` to transform the raw org list into a PathOption map, and
* `placeholderData` so the viewingOrg fallback is available immediately
* (before the query resolves or when the user isn't logged in).
*/
export function useBreadcrumbOrgPaths(
userLoggedIn: boolean,
viewingOrg: string | undefined,
planDisplayName: string | undefined,
) {
return createAdminServiceListOrganizations(
{ pageSize: 100 },
{
query: {
enabled: userLoggedIn,
retry: 2,
refetchOnMount: true,
placeholderData: {},
select: (data) =>
buildOrgPathMap(
data.organizations ?? [],
viewingOrg,
planDisplayName,
),
},
},
);
}

/**
* Query selector for project breadcrumb paths.
*/
export function useBreadcrumbProjectPaths(
organization: string | undefined,
readProjects: boolean,
) {
return createAdminServiceListProjectsForOrganization(
organization ?? "",
{ pageSize: 100 },
{
query: {
enabled: !!organization && readProjects,
retry: 2,
refetchOnMount: true,
placeholderData: {},
select: (data) => buildProjectPathMap(data.projects ?? []),
},
},
);
}

/**
* Builds a PathOption map for the organization breadcrumb segment.
*
* The viewingOrg fallback ensures the active org always appears in the
* breadcrumb, even when the list-orgs response hasn't loaded yet or
* doesn't include it (e.g. the user has direct project access but
* isn't a member of the org).
*/
function buildOrgPathMap(
organizations: V1Organization[],
viewingOrg: string | undefined,
planDisplayName: string | undefined,
): Map<string, PathOption> {
const pathMap = new Map<string, PathOption>();

organizations.forEach(({ name, displayName }) => {
if (!name) return;
pathMap.set(name.toLowerCase(), {
label: displayName || name,
pill: planDisplayName,
});
});

if (!viewingOrg) return pathMap;

if (!pathMap.has(viewingOrg.toLowerCase())) {
pathMap.set(viewingOrg.toLowerCase(), {
label: viewingOrg,
pill: planDisplayName,
});
}

return pathMap;
}

function buildProjectPathMap(
projects: { name?: string }[],
): Map<string, PathOption> {
return projects.reduce((map, { name }) => {
if (!name) return map;
return map.set(name.toLowerCase(), { label: name, preloadData: false });
}, new Map<string, PathOption>());
}
59 changes: 59 additions & 0 deletions web-admin/src/features/organizations/OrgHeader.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<script lang="ts">
import { page } from "$app/stores";
import Breadcrumbs from "@rilldata/web-common/components/navigation/breadcrumbs/Breadcrumbs.svelte";
import Header from "@rilldata/web-common/layout/header/Header.svelte";
import HeaderLogo from "@rilldata/web-common/layout/header/HeaderLogo.svelte";
import { createAdminServiceGetCurrentUser } from "../../client";
import {
useBreadcrumbOrgPaths,
useBreadcrumbProjectPaths,
} from "../navigation/breadcrumb-selectors";
import AvatarButton from "../authentication/AvatarButton.svelte";
import SignIn from "../authentication/SignIn.svelte";
import { isOrganizationPage } from "../navigation/nav-utils";

export let readProjects: boolean;
export let planDisplayName: string | undefined;
export let organizationLogoUrl: string | undefined;

const user = createAdminServiceGetCurrentUser();

$: ({
params: { organization, project },
} = $page);

$: onOrgPage = isOrganizationPage($page);

$: loggedIn = !!$user.data?.user;
$: rillLogoHref = !loggedIn ? "https://www.rilldata.com" : "/";

$: orgPathsQuery = useBreadcrumbOrgPaths(
loggedIn,
organization,
planDisplayName,
);
$: projectPathsQuery = useBreadcrumbProjectPaths(organization, readProjects);

$: pathParts = [
{ options: $orgPathsQuery.data ?? new Map() },
{ options: $projectPathsQuery.data ?? new Map() },
];
$: currentPath = [organization, project];
</script>

<Header borderBottom={!onOrgPage}>
<HeaderLogo href={rillLogoHref} logoUrl={organizationLogoUrl} />
{#if organization}
<Breadcrumbs {pathParts} {currentPath} />
{/if}

<div class="flex gap-x-2 items-center ml-auto">
{#if $user.isSuccess}
{#if $user.data?.user}
<AvatarButton />
{:else}
<SignIn />
{/if}
{/if}
</div>
</Header>
Loading
Loading