Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 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
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
149 changes: 149 additions & 0 deletions .claude/rules/frontend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
---
paths: *.svelte, *.ts
---

# Frontend Style Guide

This is a living document that captures frontend conventions and best practices for the Rill web applications.

## TypeScript

- File names use kebab-case
- Boolean variables: `isX` (e.g., `isConversationLoading`)
- Functions use `function` keyword, not arrow functions
- Prefer options objects over multiple parameters for optional configuration
- Avoid too many layers of abstraction
- Prefer `null` over empty string `""` when representing "no value" — it's more semantically clear

## Naming Conventions

| Type | Convention | Example |
| ------------------- | ---------------- | ------------------------- |
| TypeScript files | kebab-case | `user-management.ts` |
| Svelte components | PascalCase | `ProjectCard.svelte` |
| Directories | kebab-case | `user-management/` |
| Variables/functions | camelCase | `getProjectPermissions()` |
| True constants | UPPER_SNAKE_CASE | `MAX_FILE_SIZE` |
| Interfaces/types | PascalCase | `ProjectPermissions` |

## Svelte

- Keep components small and focused
- Do not use `createEventDispatcher` (deprecated in Svelte 5) — use callback props instead
- Use SuperForms for form handling
- Prefer idiomatic Svelte over patterns from other frameworks
- Use semantic HTML
- Lean into the existing design system — don't custom-build modals, popovers, dropdowns
- In script blocks, place function declarations at the bottom
- Break long reactive statement sequences into logical groups with comments

### Styles

- Default to component-scoped `<style lang="postcss">` blocks
- Use semantic classes with Tailwind v3 via `@apply`
- Break long `@apply` statements into multiple lines, grouped logically
- Use Tailwind theme colors; rarely use custom colors
- Prefer global styles over inline overrides — check `app.css` first

## TanStack Query

### Core Principles

- Lean into TanStack Query paradigms
- Put Query Observers in the component that needs the data, not in TypeScript files
- Use `select` to transform data rather than wrapping with `derived` stores
- Components must handle `isLoading` and `isError` states
- Prefer direct cache updates over query invalidation when complexity allows

### Query Key Pattern

Create query keys using Orval-generated functions:

```typescript
getRuntimeServiceGetResourceQueryKey(...)
```

### Observer Naming

Name observers like `queryNameQuery`:

```typescript
const getConversationQuery = createQuery(...)
```

### Recommended Pattern

```svelte
<script lang="ts">
import { createQuery } from "@tanstack/svelte-query";
import { derived } from "svelte/store";
import { getRuntimeServiceGetConversationQueryOptions } from ".../runtime-client";
import { runtime } from ".../runtime-client/runtime-store";

// Reactive QueryOptions store
const getConversationQueryOptionsStore = derived(
[runtime, currentConversation],
([$runtime, $currentConversation]) =>
getRuntimeServiceGetConversationQueryOptions(
$runtime.instanceId,
$currentConversation?.id || "",
undefined, // Use undefined for unused optional params, not {}
{
query: {
enabled: !!$currentConversation?.id,
},
},
),
);

const getConversationQuery = createQuery(getConversationQueryOptionsStore);
</script>
```

## State Management Patterns

| Pattern | Use When | Example |
| ------------------------ | -------------------------------------------------- | ------------------------ |
| Direct TanStack Query | Single component, simple data (1-2 queries) | Query in component |
| TypeScript Query Factory | Complex query logic, reusable across components | `useFilteredTableData()` |
| ES6 Classes | Client state + server coordination, business logic | `ChatStateManager` |

**Key principle**: TanStack Query owns server state. Classes own client state and coordinate between them.

### URL as Source of Truth

When state can be represented in the URL, it should be:

- Shareable links that restore exact state
- Browser back/forward works intuitively
- Bookmarkable views

**URL-appropriate**: filters, time ranges, tabs, search queries, pagination
**Not URL-appropriate**: loading states, hover/focus, sensitive data, rapidly changing state

## File Organization

- Organize by semantic features (user flows), not file types
- Each sub-feature contains all layers (UI, logic, state) for that flow
- Use `shared/` for cross-cutting concerns
- Co-locate documentation with code (`README.md` in each sub-feature)
- Target ~8 files per directory maximum
- `web-common/src/lib/` is for low-level, domain-agnostic utilities only

```
features/my-feature/
├── user-flow-1/ # Everything for flow 1
├── user-flow-2/ # Everything for flow 2
└── shared/ # Shared utilities

# NOT this:
features/my-feature/
├── components/ # UI layer
├── lib/ # Logic layer
└── utils/ # Utility layer
```

## General

- Comments communicate to other developers, not to AI assistants
- Our app is an SPA — no need for `if (browser)` blocks in `+page.ts`
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ proto.generate:
cd proto && buf generate --exclude-path rill/ui
cd proto && buf generate --template buf.gen.openapi-admin.yaml --path rill/admin
cd proto && buf generate --template buf.gen.openapi-runtime.yaml --path rill/runtime
cd proto && buf generate --template buf.gen.runtime.yaml --path rill/runtime
cd proto && buf generate --template buf.gen.local.yaml --path rill/local
cd proto && buf generate --template buf.gen.ui.yaml
go run -ldflags="-X main.Version=$(shell git describe --tags $(shell git rev-list --tags --max-count=1))" \
Expand All @@ -65,5 +66,6 @@ proto.generate:
scripts/convert-openapi-v2-to-v3/convert.go --force --public-only \
proto/gen/rill/admin/v1/admin.swagger.yaml proto/gen/rill/admin/v1/public.openapi.yaml
npm run generate:runtime-client -w web-common
npm run generate:query-hooks -w web-common
npm run generate:client -w web-admin

71 changes: 0 additions & 71 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions proto/buf.gen.runtime.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version: v2
managed:
enabled: true
override:
- file_option: go_package_prefix
value: github.com/rilldata/rill/proto/gen
disable:
- module: buf.build/googleapis/googleapis
file_option: go_package_prefix
- module: buf.build/envoyproxy/protoc-gen-validate
file_option: go_package_prefix
plugins:
- remote: buf.build/connectrpc/es:v1.4.0
out: ../web-common/src/proto/gen
opt:
- target=ts
6 changes: 3 additions & 3 deletions web-admin/src/features/alerts/CreateAlert.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import AlertForm from "@rilldata/web-common/features/alerts/AlertForm.svelte";
import { useMetricsViewValidSpec } from "@rilldata/web-common/features/dashboards/selectors";
import { getStateManagers } from "@rilldata/web-common/features/dashboards/state-managers/state-managers";
import { runtime } from "@rilldata/web-common/runtime-client/runtime-store";
import { useRuntimeClient } from "@rilldata/web-common/runtime-client/v2";
import { BellPlusIcon } from "lucide-svelte";

const {
Expand All @@ -22,9 +22,9 @@
dashboardStore,
} = getStateManagers();

$: ({ instanceId } = $runtime);
const runtimeClient = useRuntimeClient();

$: metricsView = useMetricsViewValidSpec(instanceId, $metricsViewName);
$: metricsView = useMetricsViewValidSpec(runtimeClient, $metricsViewName);
$: hasTimeDimension = !!$metricsView?.data?.timeDimension;

let open = false;
Expand Down
Loading
Loading