diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 51d7dd419ed..cb06d2c3907 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -31,6 +31,8 @@ pnpm typecheck # typecheck all packages **Styling** — Tailwind only, semantic tokens (`bg-muted`, `text-foreground-light`), no hardcoded colors. +**Language** — Use U.S. English everywhere. + ## Studio Pages router. Co-locate sub-components with parent. Avoid barrel re-export files. diff --git a/.claude/skills/studio-ui-patterns/SKILL.md b/.claude/skills/studio-ui-patterns/SKILL.md index 85acab8a146..2a67de2bee4 100644 --- a/.claude/skills/studio-ui-patterns/SKILL.md +++ b/.claude/skills/studio-ui-patterns/SKILL.md @@ -34,7 +34,7 @@ Docs: `apps/design-system/content/docs/ui-patterns/forms.mdx` - Use `react-hook-form` + `zod` - Use `FormItemLayout` instead of manually composing `FormItem`/`FormLabel`/`FormMessage`/`FormDescription` -- Wrap inputs with `FormControl_Shadcn_`; use `_Shadcn_` imports from `ui` for primitives +- Wrap inputs with `FormControl`; use `_Shadcn_` imports from `ui` for primitives Layout selection: diff --git a/.github/instructions/studio-telemetry.instructions.md b/.github/instructions/studio-telemetry.instructions.md index 3892a6fde6b..0a9897dce61 100644 --- a/.github/instructions/studio-telemetry.instructions.md +++ b/.github/instructions/studio-telemetry.instructions.md @@ -1,5 +1,5 @@ --- -applyTo: "apps/studio/**,packages/common/telemetry*" +applyTo: 'apps/studio/**,packages/common/telemetry*' --- # Studio Telemetry Review Rules @@ -11,8 +11,8 @@ All comments are **advisory** — suggest, do not request changes. Use judgment — not every PR needs telemetry. But **always flag** when: 1. **Changes to `packages/common/telemetry-constants.ts`** — validate event naming, property conventions, and JSDoc accuracy. -2. **PostHog feature flags without measurement.** If a PR uses `usePHFlag` or PostHog-backed hooks like `useDataApiGrantTogglesEnabled` to gate behavior, the flag state should be captured in a telemetry event so the rollout can be measured. Flag if the flag value isn't included in a relevant `track()` call. (Note: `useFlag` from `common` reads ConfigCat flags, not PostHog — different system, different guidance.) -3. **Feature-flagged rollouts without outcome tracking.** If a flag gates new behavior, there should be telemetry on both the flag state *and* how users respond to the new behavior (e.g., toggle clicks, opt-in actions). +2. **PostHog feature flags without measurement.** If a PR uses `usePHFlag` or PostHog-backed hooks like `useDataApiRevokeOnCreateDefaultEnabled` to gate behavior, the flag state should be captured in a telemetry event so the rollout can be measured. Flag if the flag value isn't included in a relevant `track()` call. (Note: `useFlag` from `common` reads ConfigCat flags, not PostHog — different system, different guidance.) +3. **Feature-flagged rollouts without outcome tracking.** If a flag gates new behavior, there should be telemetry on both the flag state _and_ how users respond to the new behavior (e.g., toggle clicks, opt-in actions). 4. **Growth-oriented components adding user interactions without tracking** — onboarding flows, setup wizards, upgrade CTAs, A/B experiment variants. When tracking is missing, comment: _"This adds a user interaction (or feature flag) that may benefit from tracking."_ Then propose an event name and `useTrack()` call. @@ -52,6 +52,7 @@ Flag: unapproved verbs (`saved`, `viewed`, `pressed`), wrong order (`click_produ ```typescript import { useTrack } from 'lib/telemetry/track' + const track = useTrack() track('product_card_clicked', { productType: 'database', planTier: 'pro' }) ``` diff --git a/.github/workflows/self-host-tests-smoke.yml b/.github/workflows/self-host-tests-smoke.yml index 9f3782ed5f4..1727558d181 100644 --- a/.github/workflows/self-host-tests-smoke.yml +++ b/.github/workflows/self-host-tests-smoke.yml @@ -31,4 +31,4 @@ jobs: cd docker cp .env.example .env yq -i '.services.supavisor.environment.RLIMIT_NOFILE=1024' docker-compose.yml - docker compose up --wait --wait-timeout 180 + docker compose up --quiet-pull --wait --wait-timeout 180 diff --git a/.github/workflows/studio-e2e-test.yml b/.github/workflows/studio-e2e-test.yml index cf3ecc38199..be170f07d38 100644 --- a/.github/workflows/studio-e2e-test.yml +++ b/.github/workflows/studio-e2e-test.yml @@ -83,18 +83,30 @@ jobs: if: steps.filter.outputs.studio == 'true' run: rm -rf supabase && pnpm exec supabase init && mkdir supabase/functions + - name: Pre-start diagnostics + run: | + docker ps -a + sudo ss -tlnp | grep 5432 || echo "5432 free" + - name: Start supabase if: steps.filter.outputs.studio == 'true' run: SKIP_ASSET_UPLOAD=1 pnpm run e2e:setup:cli + - name: Failure diagnostics + if: failure() + run: | + docker ps -a + sudo ss -tlnp | grep 5432 + docker logs $(docker ps -aq) 2>&1 || true + - name: Build studio if: steps.filter.outputs.studio == 'true' run: SKIP_ASSET_UPLOAD=1 NODE_ENV=test NODE_OPTIONS="--max-old-space-size=4096" pnpm run build:studio - - name: 🚀 Run Playwright tests against Vercel Preview + - name: 🚀 Run Playwright tests against local studio build if: steps.filter.outputs.studio == 'true' id: playwright - run: pnpm e2e --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} + run: PWTEST_SHARD_WEIGHTS=62:38 pnpm e2e --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} - name: Upload blob report to GitHub Actions Artifacts if: always() && steps.filter.outputs.studio == 'true' diff --git a/.prettierignore b/.prettierignore index 5f74f6bc0d8..e1ba10c8806 100644 --- a/.prettierignore +++ b/.prettierignore @@ -8,6 +8,9 @@ apps/**/out **/supabase/migrations/*.sql apps/www/schema.sql apps/www/public/images/* +# Generated by apps/www/scripts/generateStaticContent.mjs (GitHub discussion bodies) +apps/www/public/changelog.md +apps/www/public/changelog/*.md apps/www/.generated/* apps/docs/**/generated/* apps/docs/examples/* diff --git a/DEVELOPERS.md b/DEVELOPERS.md index d228ea7b169..6bf8f3c41db 100644 --- a/DEVELOPERS.md +++ b/DEVELOPERS.md @@ -192,7 +192,7 @@ We support "federating" docs, meaning doc content can come directly from externa Federated docs work using Next.js's build pipeline. We use `getStaticProps()` to fetch remote documentation (ie. markdown) at build time which is processed and passed to the respective page within the docs. -See the [Vecs Python source code](https://github.com/supabase/supabase/tree/master/apps/docs/app/guides/ai/python/%5Bslug%5D to see how we do this for [`supabase/vecs`](https://github.com/supabase/vecs). Use this as a starting point for federating other docs. +See the [Vecs Python source code](https://github.com/supabase/supabase/tree/master/apps/docs/app/guides/ai/python/%5Bslug%5D) to see how we do this for [`supabase/vecs`](https://github.com/supabase/vecs). Use this as a starting point for federating other docs. Some things to consider: diff --git a/apps/design-system/__registry__/default/block/chart-composed-metrics.tsx b/apps/design-system/__registry__/default/block/chart-composed-metrics.tsx index 361c35a9a45..deab28e4ee2 100644 --- a/apps/design-system/__registry__/default/block/chart-composed-metrics.tsx +++ b/apps/design-system/__registry__/default/block/chart-composed-metrics.tsx @@ -71,7 +71,7 @@ export default function ChartComposedMetrics() { } + loadingState={} > @@ -89,7 +89,7 @@ export default function ChartComposedMetrics() { } + loadingState={} > diff --git a/apps/design-system/__registry__/index.tsx b/apps/design-system/__registry__/index.tsx index 61ccda9e6b0..5b69704eecc 100644 --- a/apps/design-system/__registry__/index.tsx +++ b/apps/design-system/__registry__/index.tsx @@ -2568,6 +2568,17 @@ export const Index: Record = { subcategory: "undefined", chunks: [] }, + "multi-select-in-dialog": { + name: "multi-select-in-dialog", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/multi-select-in-dialog")), + source: "", + files: ["registry/default/example/multi-select-in-dialog.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, "tree-view-demo": { name: "tree-view-demo", type: "components:example", diff --git a/apps/design-system/app/Providers.tsx b/apps/design-system/app/Providers.tsx index a7fe031c76b..46dce708544 100644 --- a/apps/design-system/app/Providers.tsx +++ b/apps/design-system/app/Providers.tsx @@ -1,20 +1,19 @@ 'use client' +import { ThemeProvider } from 'common' import { Provider as JotaiProvider } from 'jotai' -import { ThemeProvider as NextThemesProvider } from 'next-themes' -import { ThemeProviderProps } from 'next-themes/dist/types' import { TooltipProvider } from 'ui' import { MobileSidebarProvider } from '@/context/mobile-sidebar-context' -export function ThemeProvider({ children, ...props }: ThemeProviderProps) { +export function Providers({ children }: { children: React.ReactNode }) { return ( - + {children} - + ) } diff --git a/apps/design-system/app/globals.css b/apps/design-system/app/globals.css deleted file mode 100644 index f7f07cd6431..00000000000 --- a/apps/design-system/app/globals.css +++ /dev/null @@ -1,29 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -/* :root { - --foreground-rgb: 0, 0, 0; - --background-start-rgb: 214, 219, 220; - --background-end-rgb: 255, 255, 255; -} - -@media (prefers-color-scheme: dark) { - :root { - --foreground-rgb: 255, 255, 255; - --background-start-rgb: 0, 0, 0; - --background-end-rgb: 0, 0, 0; - } -} */ - -body { - /* color: rgb(var(--foreground-rgb)); - background: linear-gradient(to bottom, transparent, rgb(var(--background-end-rgb))) - rgb(var(--background-start-rgb)); */ -} -/* -@layer utilities { - .text-balance { - text-wrap: balance; - } -} */ diff --git a/apps/design-system/app/layout.tsx b/apps/design-system/app/layout.tsx index a7d6c82e2dd..69176828eb9 100644 --- a/apps/design-system/app/layout.tsx +++ b/apps/design-system/app/layout.tsx @@ -1,10 +1,10 @@ +import 'react-data-grid/lib/styles.css' import '@/styles/globals.css' -import '../../studio/styles/typography.css' import type { Metadata, Viewport } from 'next' import { customFont, sourceCodePro } from './fonts' -import { ThemeProvider } from './Providers' +import { Providers } from './Providers' import { Toaster } from './toaster' const className = `${customFont.variable} ${sourceCodePro.variable}` @@ -131,16 +131,12 @@ export default async function Layout({ children }: RootLayoutProps) { /> - +
{children}
-
+ ) diff --git a/apps/design-system/components/class-label.tsx b/apps/design-system/components/class-label.tsx index 6575c2f4373..a779b1d353e 100644 --- a/apps/design-system/components/class-label.tsx +++ b/apps/design-system/components/class-label.tsx @@ -5,7 +5,7 @@ const ClassLabel = React.forwardRef {children} diff --git a/apps/design-system/components/code-block-wrapper.tsx b/apps/design-system/components/code-block-wrapper.tsx index 2a6c81ce03e..d4be5c110d3 100644 --- a/apps/design-system/components/code-block-wrapper.tsx +++ b/apps/design-system/components/code-block-wrapper.tsx @@ -36,7 +36,7 @@ export function CodeBlockWrapper({
diff --git a/apps/design-system/components/code-fragment.tsx b/apps/design-system/components/code-fragment.tsx index 4e688bf9c28..ccf33703720 100644 --- a/apps/design-system/components/code-fragment.tsx +++ b/apps/design-system/components/code-fragment.tsx @@ -51,7 +51,7 @@ export function CodeFragment({ return (

Code fragment{' '} - + {name} {' '} not found in registry. @@ -94,10 +94,10 @@ export function CodeFragment({ )} > {showGrid && ( -

+
)} {showDottedGrid && ( -
+
)}
{ComponentPreview}
diff --git a/apps/design-system/components/colors.tsx b/apps/design-system/components/colors.tsx index d7ba3a364c6..5a0660ac63a 100644 --- a/apps/design-system/components/colors.tsx +++ b/apps/design-system/components/colors.tsx @@ -70,7 +70,7 @@ const Colors = ({ onClick={() => handleCopy(x, i)} > - + {copiedIndex === i ? 'Copied!' : x} diff --git a/apps/design-system/components/command-menu.tsx b/apps/design-system/components/command-menu.tsx index a2dd7b3de58..fbd26bea2e8 100644 --- a/apps/design-system/components/command-menu.tsx +++ b/apps/design-system/components/command-menu.tsx @@ -56,7 +56,7 @@ export function CommandMenu({ ...props }: DialogProps) { diff --git a/apps/design-system/components/component-preview.tsx b/apps/design-system/components/component-preview.tsx index b6c5005fcb1..0189c7ee1ed 100644 --- a/apps/design-system/components/component-preview.tsx +++ b/apps/design-system/components/component-preview.tsx @@ -55,7 +55,7 @@ export function ComponentPreview({ return (

Component{' '} - + {name} {' '} not found in registry. @@ -99,10 +99,10 @@ export function ComponentPreview({ )} > {showGrid && ( -

+
)} {showDottedGrid && ( -
+
)}
{ComponentPreview}
{/*
*/} @@ -144,10 +144,10 @@ export function ComponentPreview({ })} > {showGrid && ( -
+
)} {showDottedGrid && ( -
+
)}
{ComponentPreview}
@@ -164,12 +164,12 @@ export function ComponentPreview({ px-4 py-4 border border-r group - data-[state=closed]:rounded-bl-md data-[state=closed]:rounded-br-md + data-closed:rounded-bl-md data-closed:rounded-br-md `} > View code diff --git a/apps/design-system/components/grid.tsx b/apps/design-system/components/grid.tsx index 659117a7737..23ca11ac432 100644 --- a/apps/design-system/components/grid.tsx +++ b/apps/design-system/components/grid.tsx @@ -47,8 +47,8 @@ const GridItem = forwardRef>( transition group-hover:border group-hover:border-foreground-muted - group-data-[state=open]:border - group-data-[state=open]:border-foreground-muted + group-data-open:border + group-data-open:border-foreground-muted " > {children} diff --git a/apps/design-system/components/icons.tsx b/apps/design-system/components/icons.tsx index e94f408759d..ce07e959a04 100644 --- a/apps/design-system/components/icons.tsx +++ b/apps/design-system/components/icons.tsx @@ -18,11 +18,8 @@ function Icons() { - - + + {icon.name} diff --git a/apps/design-system/components/mdx-components.tsx b/apps/design-system/components/mdx-components.tsx index 5e44875ed9e..6d260d75c57 100644 --- a/apps/design-system/components/mdx-components.tsx +++ b/apps/design-system/components/mdx-components.tsx @@ -92,10 +92,7 @@ const components = { /> ), p: ({ className, ...props }: React.HTMLAttributes) => ( -

+

), ul: ({ className, ...props }: React.HTMLAttributes) => (

    @@ -127,7 +124,7 @@ const components = { th: ({ className, ...props }: React.HTMLAttributes) => ( ) => ( ) => ( ) => ( { const [mounted, setMounted] = useState(false) @@ -25,7 +25,7 @@ const ThemeSettings = () => { function SingleThemeSelection() { return (
    - { className="flex flex-wrap gap-3" > {singleThemes.map((theme: Theme) => ( - + - + ))} - +
    ) } diff --git a/apps/design-system/components/theme-switcher-dropdown.tsx b/apps/design-system/components/theme-switcher-dropdown.tsx index ffd0e320075..86aec9f5b2f 100644 --- a/apps/design-system/components/theme-switcher-dropdown.tsx +++ b/apps/design-system/components/theme-switcher-dropdown.tsx @@ -33,7 +33,7 @@ const ThemeSwitcherDropdown = () => { return null } - const iconClasses = 'text-foreground-lighter group-data-[state=open]:text-foreground' + const iconClasses = 'text-foreground-lighter group-data-open:text-foreground' return ( <> diff --git a/apps/design-system/components/top-navigation.tsx b/apps/design-system/components/top-navigation.tsx index 0af6b28d06b..232167a8528 100644 --- a/apps/design-system/components/top-navigation.tsx +++ b/apps/design-system/components/top-navigation.tsx @@ -13,7 +13,7 @@ export const TopNavigation = () => { const { toggle } = useMobileSidebar() return ( -
    +