mirror of
https://github.com/supabase/supabase.git
synced 2026-07-19 22:07:13 -04:00
create-pull-request/patch
158 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
4fa3169e8e |
test(logs): regression coverage for datepicker Invalid time value crash (#48027)
## Problem The database-report chart to logs flow could crash the logs date picker with "RangeError: Invalid time value" (react-day-picker formatting an Invalid Date), and there was no regression coverage for it. ## Fix Adds two Vitest tests that reproduce the crash path: - Logs.Datepickers.test.tsx: opening LogsDatePicker with an unparseable value (the legacy epoch-ms its/ite) must render the calendar instead of throwing. - LogsPreviewer.test.tsx (MSW): its/ite from the URL load into the picker and it opens without crashing, covering the chart-to-logs navigation end to end. Note: these tests depend on the fix in #48009. On master the crash-guard test fails with the exact "Invalid time value" error (that is the regression it catches), so CI here will be red until #48009 merges. ## How to test - Run: pnpm --filter studio exec vitest --run tests/features/logs/Logs.Datepickers.test.tsx tests/features/logs/LogsPreviewer.test.tsx - On master: the "unparseable date value" test fails with RangeError: Invalid time value. - With #48009 merged in: both pass. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Added coverage to ensure the logs date picker handles legacy or unparseable date values without crashing. * Added coverage verifying log preview date ranges are populated from URL parameters and can be opened successfully. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
b100272376 |
chore(sql-editor): remove Pretty Explain feature (#47981)
Removes the SQL Editor Pretty Explain feature — the Explain tab, the Run EXPLAIN ANALYZE action + shortcut, and its dead plumbing. It's been gated off behind the `DisablePrettyExplainOnSqlEditor` kill switch for weeks with no usage or complaints. `ExplainVisualizer` / `isExplainQuery` are kept — they're used independently by Query Insights, Query Performance, and the EditorPanel quick-runner. Manually-run `EXPLAIN` queries still render as raw rows in the Results tab. Typecheck, lint, and all affected unit tests pass. Closes FE-3930 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Changes** * Removed the SQL editor’s EXPLAIN execution workflow, including its toolbar action, keyboard shortcut, utility tab, and visual query-plan display. * Simplified query execution to focus on standard results and charts. * Improved result clearing when switching databases and refined execution error handling. * Updated SQL editor state and tests to reflect the streamlined experience. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
52a25c2ebb |
refactor(sql-editor): extract AI/diff + shortcuts hooks (decompose 5/6) (#47935)
## What Decompose step **5 of 6** for `SQLEditor.tsx`. Extracts the Assistant / diff cluster and the keyboard-shortcut wiring out of the `SQLEditorContent` monolith into two focused, individually-testable hooks: - **`useSqlEditorAi`** — SQL completion (`complete`), the ask-AI prompt flow (`handlePrompt`), accept/discard diff handlers, `onDebug` / `buildDebugPrompt` helpers, `handleDiffEditorMount`, and the fragile diff lifecycle effects (one-shot diff-request drain, diff-editor value sync, ask-AI widget visibility). - **`useSqlEditorShortcuts`** — the registered shortcuts (focus editor, new snippet, format, explain) plus the accept/discard/escape keydown handling. `SQLEditorContent` now composes these hooks alongside the execution/explain hooks landed in decompose 4. ## Behavior-preserving This is a pure extraction. The moved function bodies, effect logic, dependency arrays, and JSX are unchanged from the previous monolith (verified via `git diff` against the pre-decomposition source). In particular: - `useEffectEvent` is preserved for `drainDiffRequest` / `resetDiff`. - `editorMountCount` remains single-owner (passed into the AI hook to drive the one-shot drain). - The untrusted→safe SQL promotion (`acceptUntrustedSql`) continues to happen in the run/explain gesture and warning-modal handlers in `SQLEditorContent`, as close to the explicit user action as possible. The Phase-1 characterization suite (`SQLEditor.test.tsx`, 11 tests) remains green. ## Stack Part of the SQLEditor decomposition stack (1/6 … 6/6). Builds on decompose 4 (execution + explain hooks, #47923). Next: PR6 splits the JSX into panes + final cleanup. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Improved SQL editor AI assistance, including completion prompts, debugging support, and diff review controls. * Added keyboard shortcuts for accepting or discarding AI-generated SQL changes. * Added shortcuts for focusing the editor, creating snippets, formatting queries, and explaining SQL. * **Bug Fixes** * Prevented SQL execution while reviewing AI-generated differences. * Improved handling of AI diff state during editor loading and interaction. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
d453e57086 |
test(sql-editor): characterization tests for SQLEditor (decompose 1/6) (#47820)
## Summary Add some tests for the SQL editor so I can refactor it without regressions. Tests are not best practice because they are intended to be temporary and improving them would require refactoring first (currently they are over-mocking and asserting on internal details). Stacked on top of #47792 (`charislam/sql-editor-top-bar-controls`). ## What this adds `apps/studio/tests/components/SQLEditor/SQLEditor.test.tsx` (11 tests): - Run success → `addResult` + Results tab; EXPLAIN-shaped result auto-switches to the explain tab; a non-EXPLAIN run switches back. - Run error with `position` → error-highlight line math + `deltaDecorations` + `revealLineInCenter`; the next run clears the highlight. - Run button refocuses the editor; disabled + short-circuits while a diff is open. - Diff request queued before mount drains exactly once (one-shot; no re-apply on remount). - Ask-AI widget renders only while the prompt is open (render-time `editorRef.current` read). - Destructive query → warning modal → confirm forces the re-run; confirm-with-RLS appends enable-RLS statements. ## Test approach Real Monaco / DiffEditor are replaced with lightweight fakes exposing a controllable editor; child panels + orthogonal context hooks are stubbed; the execute mutation runs for real against an MSW-mocked `/platform/pg-meta/:ref/query`. Tests assert on public behavior so they survive the internal refactor unchanged. ## Verification - `pnpm --filter studio exec vitest run tests/components/SQLEditor/SQLEditor.test.tsx` — 11/11 pass (stable across repeated runs) - `pnpm --filter studio typecheck` — clean - `eslint` — 0 errors <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Added comprehensive coverage for SQL editor behavior, including query execution, result and explain views, error highlighting, editor focus, and diff mode. * Added validation for destructive-query confirmations, including RLS confirmation flows. * Added coverage for queued diff requests and conditional AI prompt display. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
7141b0ae2d |
test(studio): add MSW tests for project creation flow (#47790)
Adds 21 MSW component tests covering the project creation wizard's permutations (plan/region/compute/OrioleDB/security options/GitHub/blocking states/errors). Closes FE-3883; surfaced a real empty-region submit bug tracked in FE-3884. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Added a comprehensive UI/request test suite for the Studio project-creation wizard. * Validates paid vs. free plan behavior (including compute sizing rules) and that region selection submits the correct payload, including the “Recommended” option. * Covers blocking and warning states (project limits, overdue invoices with billing CTA, and feature-flagged disabled creation), plus error handling when regions fail to load. * Exercises confirmation modals, database/security option flows, client-side validation, GitHub gating/repo selection, and toast errors on API failures. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
09ea558d54 |
Vercel install layout (#47550)
Bring the Vercel install layout up to date with other connect screens. Resolves DEPR-615. | Before | After | | --- | --- | | <img width="1600" height="1200" alt="CleanShot 2026-07-03 at 10 51 59@2x" src="https://github.com/user-attachments/assets/6a8c2910-8c45-4c7d-8d38-8b80c5cf4c83" /> | <img width="1150" height="1318" alt="CleanShot 2026-07-03 at 11 56 17@2x" src="https://github.com/user-attachments/assets/3a5add5c-fea4-44f3-a368-5732257b27d9" /> | ## Testing - Open the deploy preview or staging URL for `/dashboard/integrations/vercel/install` with callback params from a real Vercel Marketplace install redirect (see _Vercel_ subheading below). - Confirm the install screen renders with the selected Supabase account, organization picker, and primary install CTA. - Remove required callback params such as `code`, `configurationId`, or `source` to verify the "Missing Vercel installation details" warning state. - Clicking "Install integration" with an expired or reused `code` can show `Creating Vercel integration failed: Failed to get Vercel access token`; that is expected for preview UI validation. A full successful install requires a fresh Vercel-generated code from the install flow. To reiterate; this won’t work because the code will be invalid. But it should show that everything is hooked up right for prod. ### Vercel 1. Go to Supabase. Open either org-level or project (settings) level integrations. 2. Tap "[Install Vercel Integration](https://vercel.com/integrations/supabase-local)". 3. Follow the install instructions from that Vercel page. This should open a browser window. 4. Copy the URL of that browser window. Take the params and paste them instead at the end of the deploy preview URL. Example of #4: ```txt Before: https://supabase.com/dashboard/integrations/vercel/install?code=jDhIBDlD58zzLVtuSNjJpUSu&configurationId=icfg_v3dKllQIniSOwdVI3gypnZh3&next=https%3A%2F%2Fvercel.com%2Ftest-5706s-projects%2F~%2Fintegrations%2Ficfg_v3dKllQIniSOwdVI3gypnZh3%2Finstalled&source=marketplace&teamId=team_mPkGQZjTLBEUXh15b03iVsTg After https://studio-staging-git-chore-install-layout-supabase.vercel.app/dashboard/integrations/vercel/install?code=jDhIBDlD58zzLVtuSNjJpUSu&configurationId=icfg_v3dKllQIniSOwdVI3gypnZh3&next=https%3A%2F%2Fvercel.com%2Ftest-5706s-projects%2F~%2Fintegrations%2Ficfg_v3dKllQIniSOwdVI3gypnZh3%2Finstalled&source=marketplace&teamId=team_mPkGQZjTLBEUXh15b03iVsTg ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Updated the installation experience with a cleaner, more guided layout. * Added clearer organization selection during setup, including visibility into which organizations are already installed. * **Bug Fixes** * Improved loading and error handling during installation. * Added clearer warnings for missing setup details, already-installed integrations, and cases with no available organizations. * Fixed routing behavior so organization selection is preserved more reliably. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Danny White <3104761+dnywh@users.noreply.github.com> |
||
|
|
804475fd3a |
fix: redirect urls (#47487)
## TL;DR fixes redirect url normalization.. ## PS: | Before | After | | --- | --- | | Broken: whitespace could make the same redirect URL appear as a separate entry and break delete behavior | Fixed: equivalent redirect URLs are normalized consistently, so display, save, and delete behavior stay in sync | | <img width="800" height="274" alt="Before redirect URLs behavior" src="https://github.com/user-attachments/assets/47dbb1ca-7c7d-482b-a67e-08c2eb2cd030" /> |  | ## ref: - closes https://github.com/supabase/supabase/issues/47478 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved redirect URL handling so saved and displayed URLs are consistently trimmed, normalized, deduplicated, and parsed from comma-separated allow lists. * Tightened redirect URL validation to better catch invalid formats and prevent duplicates both against the existing allow list and within a new submission. * Fixed redirect URL deletion to remove the exact set of URLs confirmed by the user. * **Tests** * Added/updated tests to cover redirect URL normalization and parsing behavior for stored comma-separated allow lists. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
0e3364bbad |
Chore/cleanup studio deps (#47399)
## Problem Knip reported some unused dependencies. Some are actually used in builds, etc but others are not. ## Solution Remove the really unused dependencies <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Cleaned up unused dependencies and removed some obsolete test/support files. * Updated project ignore rules to better match current app structure and generated files. * **Bug Fixes** * No user-facing behavior changed; this release is focused on maintenance and cleanup. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
affdcb35ff |
fix(studio): sum numeric-string columns in cumulative SQL charts (#47378)
Fixes: #47377 ## What is the current behavior? Enabling **Cumulative** on a results chart concatenates Y-axis values instead of summing them whenever the column is a `bigint`, `numeric`, `money`, or `count(*)` aggregate — which Postgres returns as JSON strings. For per-row values `10, 20, 30` the chart plots `10, 1020, 102030`. `getCumulativeResults` ran `(prev[yKey] || 0) + row[yKey]` on raw result rows. The Y-axis selector explicitly allows numeric-string columns, so this is a common, fully-supported path (e.g. any `count(*) ... group by`). ## What is the new behavior? Both operands are coerced with `Number()` before the addition, keeping the existing `|| 0` fallback for null/undefined/non-numeric values. The series now sums correctly: `10, 30, 60`. The cumulative logic was previously duplicated in `ChartConfig.tsx` and `QueryBlock.utils.ts` (which is how this bug slipped in twice). It is now a single shared, tested helper: `getCumulativeResults` lives in `QueryBlock.utils.ts`, and `ChartConfig.tsx` imports it instead of re-declaring its own copy. The shared helper's `ChartConfig` type import is `import type` to avoid a runtime circular dependency, and its signature accepts `readonly` rows so both call sites type-check. ## Additional context - Added regression tests for numeric-string inputs and for null/undefined/non-numeric fallback to `0`. The existing tests only covered literal `number` inputs, never the string form Postgres actually returns. - Verified the new tests fail against the old code (`y: '010'`, `'05undefined'`) and pass with the fix. Full `QueryBlock.utils.test.ts` suite: 18 passing. No migrations, no API changes, no infra changes. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Fixed cumulative chart calculations so numeric values are always added correctly, even when results arrive as strings. * Improved handling of empty or non-numeric values in cumulative totals so they are treated as zero instead of breaking the sum. * **Tests** * Added coverage for cumulative result calculations with numeric strings and missing values. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
c6fc456910 |
chore: cleanup duplicate exports studio (#47387)
## Problem Knip reports many duplicate exports (both named and default). Besides, we're moving away from default exports and even have an eslint rule to enforce it on new code. ## Solution - Cleanup those exports - Update imports when necessary No functional changes. If it builds, it's fine |
||
|
|
2aa1b52234 |
feat(studio): add feature to rewrite queries DEBUG-145 (#47266)
## Problem Moving the Logs Explorer to ClickHouse means users' saved BigQuery queries no longer run. <img width="2430" height="1010" alt="CleanShot 2026-06-29 at 11 36 04@2x" src="https://github.com/user-attachments/assets/ae0ab155-7d3d-4ae9-81c3-22bf3a88cf8c" /> ## Fix Rewrite the query with AI instead of a SQL transpiler. AI handles the long tail of nested fields and dialect differences far better than a rule-based rewriter, and it needs no extra runtime dependency. - `rewriteLogsSqlWithAI` posts the current query to `/api/ai/code/complete` with `dialect: 'clickhouse'`. The endpoint skips the Postgres schema and best-practices for that dialect and uses logs-specific instructions and model so the output is ClickHouse logs SQL (FROM `logs` + `source` filter, no `unnest` joins, nested fields read from `log_attributes['...']`). - The query's `source` is detected and its real `log_attributes` keys are fetched and passed to the model, so it maps to exact paths instead of guessing. - The rewrite runs in the background and is proposed as a side-by-side accept/discard diff in the editor. The AI Assistant panel is not opened. - Entry points: a banner shown only for legacy-looking queries (dismissal persisted), and a "Fix Query" button next to Field Reference. - The Field Reference drawers discover `log_attributes` keys from real data so the listed fields match what the source actually emits. ## Dependencies Built on top of #47265 (Logs Explorer -> OTEL endpoint) — that is the base branch of this PR. Merge #47265 first. Behind `otelLegacyLogs` (off by default). Part of DEBUG-145 (split from #47087). ## How to test - Open the Logs Explorer with a BigQuery logs query (the templates have some), click "Fix Query", and confirm the diff shows valid ClickHouse SQL. Accept it and confirm the applied query runs. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added an OTEL legacy logs workflow (behind a feature flag) with an interactive banner and a “Fix Query” ClickHouse rewrite action, including an accept/discard diff review overlay. * Introduced OTEL-aware field reference rendering with dynamic discovery of `log_attributes` keys and updated OTEL source insertion behavior. * Enabled dialect-aware SQL completion for ClickHouse logs, using logs-specific instructions and output constraints. * **Bug Fixes** * Improved rewrite flow validation and handling, including log source detection and cleanup of AI-generated SQL formatting. * **Tests** * Added Vitest coverage for rewrite prompt generation, detection/classification utilities, SQL fence stripping, OTEL field mapping, and OTEL log attribute key discovery. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Joshen Lim <joshenlimek@gmail.com> |
||
|
|
032bd09b0c |
feat(studio): use theme-aware OAuth requester logos (#47138)
## What kind of change does this PR introduce? Bug fix. - Follow-up work to FE-3640 - Contributes to DEPR-604 ## What is the current behavior? Known dynamic OAuth requesters on `/dashboard/authorize` relied on OAuth-specific hard-coded icon assets that were dark-mode only. Cursor did not have separate light/dark assets in the shared MCP icon registry, Perplexity only had a light tile asset with baked-in padding, and OpenAI used the older blossom mark. ## What is the new behavior? Known OAuth requester logos now resolve through the shared MCP icon registry while preserving the existing `SupabaseLogo` treatment for paired authorisation screens. Cursor uses transparent SVG light/dark variants, Perplexity has cropped transparent SVG light/dark variants, and OpenAI/ChatGPT uses the newer monoblossom SVG in black/white variants. Claude remains static until a suitable variant is available. Unknown requester icons still render from the provided URL and fall back to the requester initial if the image fails. | Before | After | | --- | --- | | <img width="828" height="636" alt="Authorize OpenAI Supabase-E2A05664-589F-458F-8452-9CEE008D558A" src="https://github.com/user-attachments/assets/140021b1-ff05-4092-98ef-2eae94ff2ddb" /> | <img width="828" height="636" alt="Authorize OpenAI Supabase-EC7E00BD-439A-45D1-8E55-240B227C6897" src="https://github.com/user-attachments/assets/93e603f2-5cbf-4219-b692-d36ac98e8d2a" /> | | <img width="828" height="636" alt="66 Authorize OpenAI Supabase-CB31FF76-86DB-43A6-A426-46B99B8B1B91" src="https://github.com/user-attachments/assets/b261416e-39b8-40b3-87fd-461653aa0334" /> | <img width="828" height="636" alt="Authorize OpenAI Supabase-EAFCF2F2-5CEA-4FE6-8AC0-819F764B414E" src="https://github.com/user-attachments/assets/35ad7525-0fa9-4438-b117-4e70b78eb719" /> | ## To test 1. Navigate to `http://localhost:8082/authorize?auth_id=test-auth-id` 2. Open DevTools → Network 3. Find `/platform/oauth/authorizations/test-auth-id` 4. Right-click → Override content 5. Replace the response body with: ```js { "name": "Perplexity", "website": "https://perplexity.ai", "icon": null, "domain": "perplexity.ai", "scopes": [], "expires_at": "2026-12-31T23:59:59.000Z", "approved_at": null, "registration_type": "dynamic" } ``` 6. Then change "name" to Cursor, Claude, ChatGPT, or OpenAI and refresh to inspect each logo <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * OAuth app requester logos now dynamically adapt to light and dark themes, with improved logo selection for known requesters. * Cursor now uses a distinct dark icon variant. * Added Perplexity client icon support. * **Bug Fixes** * Improved logo rendering robustness: if a logo can’t be loaded, the UI falls back to the requester’s initial. * **Tests** * Expanded coverage for theme-aware logo rendering and icon variant handling, including unknown-icon and fallback scenarios. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
fd0f2dd459 |
Scope last visited organization local storage to profile (#47071)
## Context If a user switches account without an explicit log out via the dashboard, landing back on `/org` will redirect users to the last visited organization as stored in local storage, in which it can result in the following state if the last visited organization does not exist in the current account <img width="2538" height="1060" alt="image" src="https://github.com/user-attachments/assets/270e482a-3515-48ef-898b-87e76fce80d6" /> ## Changes involved Am opting to scope the last visited organization to the user profile instead - this would be a bit more cleaner than trying to actively clear the last visited org slug from local storage with implicit account changes as there's no deterministic way to track that (afaik) from FE side of things ## To test Can reproduce the problem as such - Ensure that you have 2 accounts to log in with, and one account has an org that the other is not a part of - For the organization that has the "extra" org, ensure that you click into it so that the last visited org slug is saved in local storage - Mimic changing accounts by visiting `/auth/v1/authorize?provider=github` (using the domain for the env that you're testing on - e.g localhost:8000 for local, or green for staging preview) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Unified “last visited organization” handling across the Studio UI with a shared hook, improving consistency for home/dashboard return, cancel/back navigation, and account routing. * **Bug Fixes** * Updated redirects to only route to an organization when a valid last-visited value is available; otherwise users go to the general organizations page. * Kept MFA enrollment and factor delete/leave flows aligned to the unified last-visited organization value. * **Tests** * Updated onboarding and layout tests to match the new last-visited organization storage key format and hook/query success behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
96d43099bb |
chore: refactor Button API so that it can be used a standard button (#46880)
## Problem Our `<Button>` component breaks the default `button` contract by redefining the `type` prop to set its variant (`primary`, `default`, etc) instead of the button type (`submit`, `button`, etc). This is confusing and forces to write more code when using it with shadcn components that expect/inject the standard button props. ## Solution - rename the `type` prop to `variant` - rename the `htmlType` prop to `type` - propagate the changes where necessary - format code ## How to test As this is just prop renaming, if it builds it's ok --------- Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com> |
||
|
|
43c2229f1e |
fix(studio): align /authorize invalid and edge states with interstitial UI (#46960)
## What kind of change does this PR introduce?
Bug fix / UI polish
## What is the current behavior?
Visiting `/authorize` without an `auth_id` renders a bare `Card` outside
the shared Connect interstitial — no centered layout, no Supabase logo,
inconsistent with every other `/authorize` state (loading, error, form,
approved).
Two edge cases also produce poor UX: a blank flash while
`router.isReady` is false, and a silent empty page when the
authorization query succeeds but returns no requester.
## What is the new behavior?
- **Missing `auth_id`**: `ApiAuthorizationInvalidScreen` now uses
`InterstitialLayout` with `SupabaseLogo`, a user-facing title ("Missing
authorization link"), warning admonition, and "Back to dashboard" —
matching the error screen and CLI missing-params pattern.
- **Router not ready**: `authorize.tsx` shows
`ApiAuthorizationLoadingScreen` instead of `null`.
- **Empty requester**: `ApiAuthorization.Valid.tsx` renders
`ApiAuthorizationErrorScreen` instead of returning `null`.
Tests updated in `ApiAuthorization.test.tsx`; added `authorize.test.tsx`
for router-not-ready loading.
| Before | After |
| --- | --- |
| <img width="524" height="455" alt="Authorize API Access
Supabase-DCB404EC-7D65-4DD1-A6E0-B720DC765DA7"
src="https://github.com/user-attachments/assets/8d2b68fc-e008-4145-aa74-3154a883083c"
/> | <img width="524" height="455" alt="Authorize API Access
Supabase-6B642066-D0BE-4EDC-A186-A0290B4B5634"
src="https://github.com/user-attachments/assets/b04bee93-6b23-411f-8e36-9a0fff8a975d"
/> |
## To test
Please do a visual check on `http://localhost:8082/authorize` (no
`auth_id` or other parameters).
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved the UI and copy shown when the authorization link is missing.
* Updated behavior to show an explicit error screen when authorization
requester data is unavailable.
* **New Features**
* Added a loading state for the authorization page while router
parameters are initializing.
* **Tests**
* Updated component expectations for the missing authorization and
“unable to load” scenarios.
* Added a page test to verify the loading message when the router is not
ready.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
|
||
|
|
c713135384 |
fix(studio): wrappers install state + one-click install (#46697)
- fix install badge state in wrappers detail page - add "Install" button in top action bar - "Install wrapper" if required extensions _aren't_ installed - "Add new wrapper" if required extensions _are_ installed - make wrappers "one-click install" by - showing the required extensions in the CreateWrappersSheet - and automatically installing them on wrapper submission Only available behind `isMarketplaceEnabled` flag at the moment. https://github.com/user-attachments/assets/38f5549d-938e-4e2f-a723-53b9a028e9dc |
||
|
|
40c947ebfb |
fix: Handle non existant columns when sorting tables (#46741)
When a user has sorted by some column in the Table Editor and the column is deleted, the sort data is wrong so it causes issues. In the general view in the Table Editor, the error is handled by removing the sort key when a specific error is detected but it can still happen in ForeignRowSelector. To test: 1. Have 2 tables with references between them. 2. In the `sessionStorage`, under the `supabase_grid-<ref>` key, update the sort key to a non-existant column for a table. 3. Try to open the `ForeignRowSelector` for that table by clicking on a cell in the referencing column. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Sorting now validates referenced columns and ignores invalid sort entries. * Local sort restoration and UI sort application now derive sorts from the original table context for more consistent behavior across editors and popovers. * Prefetch logic uses the resolved table context when falling back to saved sorts. * **Tests** * Added cases for malformed and out-of-scope sort parameters to prevent regressions. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
35df570342 |
feat(studio): move /authorize to connect interstitial (#46359)
> [!CAUTION] > The `do-not-merge` label has been applied because this contains mocks for easier review and testing. I'll remove those mocks before merging. ## What kind of change does this PR introduce? Feature. Part of the shared Connect UI (interstitial) rollout. Previous slices: #46058, #45909, #45862. ## What is the current behavior? The `/authorize` MCP/OAuth consent screen uses the old `Card`/`Alert` layout. ## What is the new behavior? - Wraps all `/authorize` states in `InterstitialLayout` (the shared full-screen centered card used across Connect flows) - Shows a quiet footnote below the Cancel button ("Authorizing will redirect you to \<url\>") for non-localhost redirect URIs, so users can verify the destination before approving. No extra friction for localhost flows (local MCP servers) | Before | After | | --- | --- | | <img width="692" height="997" alt="Authorize API access Supabase-F6C3747A-5077-43D8-A509-3E16B1DDC168" src="https://github.com/user-attachments/assets/e86dde34-94cb-48ef-b026-66aac9122df6" /> | <img width="692" height="997" alt="Authorize API Access Supabase-FE6FD8B3-1159-4EA5-94D7-EA5CEA7A25F3" src="https://github.com/user-attachments/assets/c1a94a44-51d9-40d8-8046-f3104a27b929" /> | | <img width="692" height="997" alt="Authorize API access Supabase-86742351-3521-4B62-AF87-403CB7E7F4F5" src="https://github.com/user-attachments/assets/41cff7af-b9e4-4a20-a979-7148b4220265" /> | <img width="692" height="997" alt="Authorize Cursor Supabase-B665B4A4-600F-462B-8C97-84B171EC3103" src="https://github.com/user-attachments/assets/804286f2-ce51-45ab-bb3f-315f8ac62445" /> | | <img width="692" height="997" alt="Authorize API access Supabase-C73DC3D0-8646-4E6E-A259-3E84AE46DAF2" src="https://github.com/user-attachments/assets/8f285edb-438f-4262-9faa-f1133c679ed4" /> | <img width="692" height="997" alt="Authorize Cursor Supabase-FEA86625-27D5-4DB5-B4D4-1A2CB804E56E" src="https://github.com/user-attachments/assets/b54f2ceb-e1cf-4c7e-be3f-8e1b0942e9a4" /> | | <img width="692" height="997" alt="Authorize API access Supabase-48E0C7CB-DDDD-4305-B821-F3BEB52C4A4E" src="https://github.com/user-attachments/assets/7d123c57-e05d-408c-8df9-d747a3afd714" /> | <img width="692" height="997" alt="Authorize Cursor Supabase-CE8F9905-FAE0-4C06-B77A-9F269B2100FE" src="https://github.com/user-attachments/assets/9f403b83-5de3-43c8-a592-c3022e041243" /> | | <img width="692" height="997" alt="Authorize API access Supabase-E37D2CD5-476F-4F49-A5FB-631B265025DC" src="https://github.com/user-attachments/assets/3d235315-d7c0-4279-b23f-e8b595888511" /> | <img width="692" height="997" alt="Authorize Cursor Supabase-DF078AEB-BB78-4647-9FA2-5D5403CCA5D6" src="https://github.com/user-attachments/assets/53d51718-8707-4b97-9cbe-8e523f4ce0e0" /> | | <img width="692" height="997" alt="Authorize API access Supabase-D6F6817F-D8DD-4D55-85BB-A15100814AAB" src="https://github.com/user-attachments/assets/c80c5579-772a-4dfe-a247-b0b9772b9690" /> | <img width="692" height="997" alt="Authorize Cursor Supabase-E457B580-9786-43AD-9CF9-FE4F5BB8E785" src="https://github.com/user-attachments/assets/30c47b05-edf5-4380-a2f1-aedb99482540" /> | | <img width="692" height="997" alt="Authorize API access Supabase-4F3D6AA4-E2E3-4526-B391-49B6E0861911" src="https://github.com/user-attachments/assets/ffbe5b65-6eef-49d7-95f1-c29072c320b8" /> | <img width="692" height="997" alt="Authorize Cursor Supabase-CA9FFCC9-4CA2-4718-AD49-B02D86C6EF6A" src="https://github.com/user-attachments/assets/8fd7ff39-19f5-4414-af13-3821290735b2" /> | | <img width="692" height="997" alt="Authorize API access Supabase-E507B7A5-9AD0-4F17-8743-63A7B47D171A" src="https://github.com/user-attachments/assets/1639b5cc-69c4-4a43-b049-6f989e2cdbb1" /> | <img width="692" height="997" alt="Authorize Cursor Supabase-9844BB27-2429-4BA6-BD36-1AB54099F44F" src="https://github.com/user-attachments/assets/a94b88e2-9c2f-4941-840a-5182342bb335" /> | | <img width="692" height="997" alt="Authorize API access Supabase-27684173-9DBB-4F6E-9F7F-87EFD4E10A5F" src="https://github.com/user-attachments/assets/91794c96-8a81-4d83-9c97-01d134639676" /> | <img width="692" height="997" alt="Authorize Cursor Supabase-04E31F7B-D098-4814-A394-01CE3D3E5A51" src="https://github.com/user-attachments/assets/ba0284a3-363c-4aa5-9e4a-c378aed9c42c" /> | | <img width="692" height="997" alt="Authorize API access Supabase-207CBC69-4957-499C-92E8-163F2B34C8AD" src="https://github.com/user-attachments/assets/1bafedd2-bba8-473c-ba57-637289f1c940" /> | <img width="692" height="997" alt="Authorize API Access Supabase-C1627071-4AE2-4012-8F7C-4E6D883618A3" src="https://github.com/user-attachments/assets/a6fc6125-3c1e-4b8c-821a-c3c9f32f3cc0" /> | ## To test A mock toolbar is included for easy local testing. Navigate to `/authorize?mock=loading` and then switch between the following variants: | State | What to check | | --- | --- | | `loading` | Shimmer skeleton inside the card | | `ready` | Regular waiting state | | `approving` | Authorize button shows spinner, both buttons disabled | | `approved` | Success admonition: "Authorization approved" | | `expired` | Warning admonition: "Authorization request expired", no action buttons | | `organizations-loading` | Org selector shimmer, no action buttons | | `organizations-error` | "Unable to load organizations" admonition, no action buttons | | `empty` | "No organizations found" admonition, no action buttons | | `not-member` | "Organization unavailable" admonition, no action buttons | | `error` | "Unable to load authorization" error screen | Then please test the `organization_slug` prefill: `/authorize?mock=ready&organization_slug=<your-org-name-here>`. That org selector should be pre-selected and locked. To test against a real OAuth app, use a registered app on `supabase.green` — the mock states cover all edge cases but a live round-trip confirms the approve/decline API calls. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **New Features** * Added mock preview functionality for testing API authorization and Connect flows * Introduced collapsible, grouped permissions view for OAuth authorization requests * **Refactor** * Redesigned API authorization screens with improved layout and messaging * Restructured permissions display for better organization and clarity * **Bug Fixes** * Fixed inline link underline decoration color * **Tests** * Updated authorization flow test assertions to match new UI behavior <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46359?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Ali Waseem <waseema393@gmail.com> |
||
|
|
a776b54863 |
fix(studio): show role permission descriptions in edit access drawer (#46627)
Mirrors the recent invite drawer change (#46515) on the edit access drawer. Each role option now describes its permissions via the shared \`ROLE_DESCRIPTIONS\` map instead of showing just the role name. Closes FE-3524. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Role selection in Team Settings now shows full, role-specific permission descriptions and appends any disabled-reason details for clarity. * **Tests** * Added integration tests covering the role panel UI: role listing, selected role label, documentation link, role-specific descriptions, and an admin-safety notice; includes test environment compatibility stubs for animations and routing. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
b28f91741f | fix(self-hosted): reveal and copy secret api key in project settings (#46592) | ||
|
|
0c8b71de64 | feat(self-hosted): update project home for self-hosted and cli (#46544) | ||
|
|
ca9b02b5ac | feat(self-hosted): add minimal project settings (#46554) | ||
|
|
3e7d8d0f68 |
chore: Update styling and more descriptive information for roles when inviting members (#46515)
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? - Better role selector thats actually more helpful with descriptions - More tests with MSW - Refactored to a side panel due to more information being presented in the modal ## How to test - Try inviting members to an org - Make sure members can still be revoked! <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Team member invitation interface redesigned from modal dialog to side panel. * Role selection now displays as an interactive radio list with descriptions for each role. * Improved form layout with horizontal organization for better usability. * **Tests** * Added integration and unit tests for team member invitation functionality. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
1d203f6c93 |
feat: Support CLI for Vector buckets (#46381)
## Context > [!IMPORTANT] > Will open up for review once CLI PR is merged and deployed so that it's easier to test Related PR: https://github.com/supabase/cli/pull/5230 Adding support for vector buckets for local CLI - will need to be tested locally via `pnpm run dev:studio-local` ## To test There's a bit of testing instructions in the linear ticket [here](https://linear.app/supabase/issue/FE-3474/show-vector-buckets-in-local-admin-studio) as it involves using a branch of CLI - otherwise do reach out to Fabrizio if any help might be needed, but generally: ### Local CLI You might need to manually set `isCli` to `true` in `StorageMenuV2` if the "Vectors" nav item isn't showing up on the storage UI given we're testing via `pnpm run dev:studio-local` - [x] Can create bucket - [x] Can delete bucket - [x] Can create indexes - [x] Can insert data into indexes (via FDW) - [x] Can delete indexes Known issues (that aren't directly solvable from FE end) Reach out to Fabrizio for context as we were both investigating this - PG database needs to be on 17.6 (otherwise there's no S3 vectors FDW) - Storage version needs to be on 1.59.0 ### Self-hosted (This might be tricky to actually test, but just ensure that the code satisfies this) - [x] Cannot see vector buckets ### Hosted - [x] Everything works status quo <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Vector bucket management UI and platform APIs (create/list/delete buckets & indexes) * Local S3 credentials endpoint and client-side hook for self‑hosted/CLI use * **Bug Fixes** * Improved S3 vector setup notifications and clearer error guidance for manual installation * **Refactor** * Deployment-mode gating: platform vs CLI/self‑hosted now controls feature visibility and page behavior * **Tests** * Added suites covering deployment-mode gates and vector bucket error/usage scenarios * **Chores** * Build env updated to expose local S3 credential vars <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46381?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Ali Waseem <waseema393@gmail.com> |
||
|
|
6236ee9ef9 |
POC: bring back MSW to remove the pattern of vi.mock (#46439)
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Right now our tests for API mocking is using vi.mock and mocking that query or fetch handler. This is not the right approach IMO, 2 years ago @jordienr added MSW with some very powerful helpers. The idea is to move component test that rely on API using MSW within ViteTest. Principles are simple: - Mock API responses - Mount your component that uses API responses - Tests and assert on UI - Added Skill for Clanker This pattern is 100 times better than what we have <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Expanded and strengthened test suites for secrets, org lookup, support flows, OAuth auth, and onboarding; mocks now use contract-backed responses for more realistic coverage. * **Documentation** * Added a comprehensive guide describing a standardized pattern for component tests that mock network requests. * **Chores** * Improved test helpers, typing for API mocks, and test runner configuration for more reliable and maintainable tests. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46439?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Alaister Young <alaister@users.noreply.github.com> Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com> |
||
|
|
c1276c8e9a | feat(self-hosted): add new API keys to self-hosted Studio and MCP server (#46173) | ||
|
|
51ecfbb86d |
studio(chore): reuse org details fields in AWS marketplace flow (#46087)
## What kind of change does this PR introduce? Refactor. Resolves FE-3216. ## What is the current behavior? The AWS Marketplace create-organisation dialog owns its own copy of the organisation name, type, and company-size form fields. It’s duplicative and has drifted from the normal `/new` organisation form, making the AWS flow harder to keep aligned. This is stacked on #46058. ## What is the new behavior? - Extracts the shared organisation details schema, defaults, option constants, and fields from the normal `NewOrgForm` - Reuses those shared fields in both the full organisation creation form and the AWS Marketplace create-and-link dialog - Keeps the AWS Marketplace flow anchored in the onboarding interstitial rather than routing through `/new` - Keeps the AWS-specific buyer ID, AWS-managed organisation endpoint, create-and-link success state, and modal dismissal behaviour | Before | After | | --- | --- | | <img width="1024" height="759" alt="Link AWS Marketplace Supabase-3742FEDF-53BD-4E80-926D-498B2EA94773" src="https://github.com/user-attachments/assets/617ee422-1cf0-4858-801b-a4ee5ee402c9" /> | <img width="1024" height="759" alt="Link AWS Marketplace Supabase-0FEE2292-CB9F-43AA-B131-B6A549890970" src="https://github.com/user-attachments/assets/ff017468-f8ac-469a-bb17-eea07842306f" /> | ## Additional context The shared field extraction is intentionally limited to organisation details. Billing, plan selection, spend cap, Stripe, captcha, and the `/new/[slug]` redirect behaviour stay owned by `NewOrgForm`; AWS Marketplace keeps its separate create-and-link container because AWS owns the billing contract. ## Validation - `pnpm --filter studio exec vitest --run tests/pages/aws-marketplace-onboarding.test.tsx` - `pnpm --filter studio lint:ratchet --rule no-restricted-exports` - `git diff --check` Full Studio typecheck was also run, but it currently fails on existing unrelated repo-wide React/implicit-any errors outside this diff. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved AWS Marketplace organization creation dialog to prevent accidental closure while the creation process is in progress. * **Improvements** * Standardized organization details form handling across different organization creation flows for improved consistency and user experience. * **Tests** * Added comprehensive test coverage for the AWS Marketplace organization creation workflow, including form submission, validation, and state transitions. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46087?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
a8720dee1f |
feat(studio): move AWS Marketplace to connect interstitial (#46058)
## What kind of change does this PR introduce? Feature. Resolves DEPR-556. ## What is the current behavior? AWS Marketplace onboarding uses a separate scaffold and AWS-specific organization selection UI, so it does not match the newer shared connect interstitial pattern used by Redeem Credits. ## What is the new behavior? - Moves `/aws-marketplace-onboarding` onto the shared connect interstitial shell with AWS and Supabase branding - Reuses the shared organization selector behaviour from Redeem Credits, including last-visited organization promotion, selected organization promotion, the create-organization card, and compact overflow disclosure - Keeps the existing AWS data path for buyer eligibility, onboarding info, organization linking, AWS-managed organization creation, and success/error/ineligible states - Removes the now-unused legacy AWS Marketplace layout/scaffold components - Removes the temporary reviewer mocks from the branch before merge ## Additional context This PR preserves the current AWS-managed organization creation modal so the AWS flow keeps working while adopting the shared connect sheet. FE-3216 should move that creation path into the general organization form later, likely replacing the AWS-specific modal with a preconfigured `/new` flow that can still return to AWS Marketplace onboarding and link automatically. --------- Co-authored-by: Joshen Lim <joshenlimek@gmail.com> |
||
|
|
ba77d15d41 |
chore(billing): remove billing address modal and tax id banner (#46210)
This PR removes the billing address modal and tax id banner code completely since we no longer need it. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Removed Features** * Billing address update modal is no longer accessible. * Tax ID banner has been removed from the app UI. * Placeholder banner block disabled. * **Tests** * Automated tests for the billing address modal were removed. * **Chores** * Associated local-storage key for the tax ID banner was removed. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46210?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
df77fc9011 |
fix(cli): resolve infinite loader on device code screen (#46137)
## Summary Follow-up fix for [#46120](https://github.com/supabase/supabase/pull/46120). PR #46120 correctly guarded against duplicate `POST /platform/cli/login` calls using a `useRef`, but left `navigate` in the `useEffect` deps array. Because the parent passes an inline lambda, `navigate` gets a new reference on every render. This causes React to: 1. Run the effect cleanup mid-flight (setting `isActive = false`) 2. Re-run the effect, which hits the session-id ref guard and returns early When step 1 happens while the POST is in-flight, the response arrives with `isActive === false`, silently drops the `navigate(...)` call, and leaves status stuck at `{ _tag: 'loading' }` — the infinite spinner reported in Slack. ## Fix Store `navigate` in a ref (updated each render) and call `navigateRef.current(...)` inside `createSession`. Remove `navigate` from the deps array so parent re-renders never trigger a cleanup while the POST is in-flight. ```ts const navigateRef = useRef(navigate) navigateRef.current = navigate // always up to date, never a dep ``` All 7 existing CLI login unit tests pass, including the "POSTs exactly once even when parent re-renders" regression test. ## Test plan - [ ] Run `pnpm test:studio tests/pages/cli-login.test.tsx` — all 7 tests pass - [ ] Browser: `supabase login` flow completes and shows the verification code screen without hanging on the loader - [ ] DevTools Network: exactly one `POST /platform/cli/login` fires per login attempt 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved CLI login navigation reliability when parent components update during session creation. * **Style** * Adjusted loading indicator styling on the CLI login screen. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46137?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com> |
||
|
|
da3b0cb3ec |
fix(cli): login creating duplicate tokens on re-renders (#46120)
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Bug fix ## What is the current behavior? The CLI login page was firing `POST /platform/cli/login` multiple times per page load due to an unstable `navigate` reference in the parent component re-triggering the effect. This caused several duplicate personal access tokens to be created for each browser sign-in attempt (regression CLI-1491). Additionally, error messages from non-Error rejection shapes (like those from openapi-fetch) were being replaced with a generic "Unknown error" message instead of surfacing the actual platform error. ## What is the new behavior? 1. **Prevents duplicate API calls**: Added a `useRef` guard (`startedForSessionIdRef`) to ensure `createCliLoginSession` is only called once per `sessionId`, even if the parent component re-renders with a new `navigate` reference. 2. **Improved error handling**: Created a `getErrorMessage()` utility that properly extracts error messages from both Error instances and plain objects (e.g., `{ message: string, statusCode: number }`), allowing platform error messages to surface instead of generic fallbacks. 3. **Added comprehensive test coverage**: - E2E test verifying the POST fires exactly once per page load with realistic network latency - E2E test confirming platform error messages are displayed correctly - Unit test for non-Error rejection shapes - Unit test verifying the effect doesn't re-trigger on parent re-renders ## Additional context The fix addresses the root cause by: - Using a ref to track which `sessionId` has already been processed, preventing re-execution when deps change - Extracting error message handling into a reusable utility that handles both Error instances and plain objects - Adding tests that specifically check for the regression (multiple POST calls and error message display) The E2E test includes a 400ms delay in the mock response to simulate real-world conditions where the original bug only surfaced after React committed multiple re-renders. Closes: CLI-1491 https://claude.ai/code/session_01GAujw33MTRBRYSnS8cxcEa <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved CLI login error handling to display platform-specific error messages instead of generic fallback text. * Fixed duplicate login session creation during component rerenders. * **Tests** * Added test coverage for error message display in CLI login. * Added regression tests for single session creation and platform error scenarios. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46120?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
4e86c39ea1 |
chore: remove <ContextMenu> _Shadcn_ suffix (#45971)
## Problem The `_Shadcn_` suffix isn't needed anymore on `<ContextMenu_Shadcn_>` and related components ## Solution Remove it. No other changes <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Replaced legacy context-menu component variants with the unified UI context-menu components across the app for consistent rendering and imports; behavior and menu content remain unchanged. * **Tests** * Updated a test mock to track the unified context-menu component mount count. * **Chores** * Simplified UI package re-exports to expose the canonical context-menu symbols. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45971) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
205ab69061 |
feat(studio): move CLI login to connect interstitial (#45814)
## What kind of change does this PR introduce? Feature / UI refactor ## What is the current behaviour? The CLI browser login route still uses the older API authorisation layout and redirects missing or failed sign-in session states to generic 404/500 pages. ## What is the new behaviour? Moves `/cli/login` onto the shared connect interstitial layout as the next small stacked slice after the organisation invite work. This keeps the real CLI login contract intact while updating the surface: - creates the CLI login session from `session_id`, `public_key`, and optional `token_name` - redirects to the generated `device_code` - renders missing-parameter and session-creation failures in-card instead of redirecting away - keeps the 8-character verification code selectable and copyable as a single string - uses a full-width primary `Copy code` action This also adds the small shared interstitial helpers needed by this surface and adjusts `CopyButton` so the copied check icon inherits the primary button colour instead of turning green. This also removes the CLI version admonition: > Browser login flow requires Supabase CLI version 1.219.0 and above. I checked with our stats and the CLI team. The vast majority of users are on a newer version. | Before | After | | --- | --- | | <img width="1024" height="759" alt="Authorize API access Supabase-D1E3CF26-BD59-4BB2-B457-B552EE47E3DA" src="https://github.com/user-attachments/assets/c89b8b13-fa98-41b7-8093-e59d15b2aa9e" /> | <img width="1024" height="759" alt="Authorize CLI Supabase-C9977F21-88B8-441B-8A2C-09A9515935B0" src="https://github.com/user-attachments/assets/ca13b65a-3875-425c-b73b-8f2101c1e406" /> | | <img width="1024" height="759" alt="Supabase-F42FBEAF-F74D-4920-8A51-7C25004F66D5" src="https://github.com/user-attachments/assets/51adb1e6-a2fb-41fb-b36f-0ae466fe60e2" /> | <img width="1024" height="759" alt="Authorize CLI Supabase-8159A1B1-2594-4183-AC35-FEF1EFD4EA37" src="https://github.com/user-attachments/assets/6f143218-795d-41c9-a8e1-52e529a6b988" /> | <img width="1024" height="759" alt="Supabase-2506E468-9F42-44B9-A5B7-BC4D3777F552" src="https://github.com/user-attachments/assets/a304fca5-cf26-4ae7-abe9-77cdbc21fba5" /> | <img width="1024" height="759" alt="Authorize CLI Supabase-A0EE1239-A345-427C-9CF7-997037A8FC0E" src="https://github.com/user-attachments/assets/33118777-35f3-49d6-bc1e-30e7124b3677" /> | | <img width="1024" height="759" alt="Authorize API access Supabase-A7B84CA6-D230-4C3E-9227-DE21CE35375C" src="https://github.com/user-attachments/assets/78eb6296-035a-4201-b254-b97eda44443c" /> | <img width="1024" height="759" alt="Authorize CLI Supabase-F55E26B2-609B-449C-9C64-08AA90AE3D1E" src="https://github.com/user-attachments/assets/ff7b3b4e-729c-4681-844d-2d5d94bfc084" /> | ## Testing instructions Use the Vercel preview URL for this PR once it is available. The examples below use `<preview-origin>` as a placeholder, for example `https://studio-git-dnywh-feat-cli-login-interstitial-supabase.vercel.app`. You need to be signed in to Studio to see these states because `/cli/login` is still behind `withAuth`. Ready state: - Open `<preview-origin>/cli/login?device_code=ABCD1234` - Check the page title is `Authorize CLI | Supabase` - Check the card title is `Authorize Supabase CLI` - Check the code fills the width, uses the normal sans font, and can be selected - Drag-select the code and copy it; the clipboard should contain `ABCD1234`, not one character per line - Click `Copy code`; the button should show the usual copied success state without a green check icon on the primary button Missing parameters state: - Open `<preview-origin>/cli/login` - Check the card says `Missing sign-in parameters` and names the missing `session_id` and `public_key` parameters - Open `<preview-origin>/cli/login?session_id=session-test` - Check it still stays in-card and names the missing `public_key` parameter instead of redirecting to `/404` Creation error state: - Open `<preview-origin>/cli/login?session_id=not-real&public_key=not-real&token_name=local-dev` - Check it stays in-card with `Unable to create CLI sign-in` instead of redirecting to `/500` - The exact error detail can vary by environment; the important bit is that the failure is shown inside the interstitial card Loading state: - This is transient because there are no production mocks in this slice - To inspect it manually, throttle the browser network before opening a session-creation URL such as `<preview-origin>/cli/login?session_id=not-real&public_key=not-real` Real CLI flow: - Run the browser login flow from Supabase CLI as usual - When the CLI opens a Studio URL, keep the path and query string but replace the origin with the PR preview origin - The page should create the login session and then route to `/cli/login?device_code=<8 character code>` - Enter that 8-character code back in the CLI prompt <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Redesigned CLI login flow with clearer state-driven screens and improved verification UI. * Added a small paired-logo component for centered logo pairs with a connector icon. * **Improvements** * Copy button behavior and styling refined for consistent visual feedback across variants. * **Tests** * New unit tests covering copy-button behavior and multiple CLI login UI flows. [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45814) <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
9660b0075c |
refine organisation invite state helpers (#45813)
## What kind of change does this PR introduce? Code cleanup. Follow-up to #45774. ## What is the current behavior? The organisation invite interstitial derives invite states, titles, and descriptions from nested conditional logic in the component. That makes the component harder to scan and pushes too much state coverage into render tests. ## What is the new behavior? See #45774 for screenshots of the general UI before-and-after (which this one builds upon). That PR also contains testing instructions. Extracts the invite status and content decisions into small pure helpers, then covers those helpers with focused unit tests. The component keeps the user-facing render and interaction coverage, including the invalid lookup regression where a 404 should render the invalid invite state instead of raw backend copy. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Improved organization invite flow with enhanced error state handling for expired, invalid, and wrong-account scenarios. * Better consistency in error messages and user guidance throughout the invite process. [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45813) <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
791fc74412 |
feat(studio): shared connect layout for organisation invites (#45774)
## What kind of change does this PR introduce? Feature. Part of DEPR-279. ## What is the current behavior? The organization invite page has its own bespoke centered card and page-level Supabase logo. ## What is the new behavior? Introduces a minimal shared interstitial layout and migrates `/join` onto it as the first small connect-surface slice. The invite API and accept-invite mutation paths are unchanged. | Before | After | | --- | --- | | <img width="1024" height="794" alt="Supabase-F2325C57-D5DE-445D-8083-12EF8A1EE0CA" src="https://github.com/user-attachments/assets/b23dcc7a-c649-4b59-9393-9232d74f0c6b" /> | <img width="1024" height="794" alt="Join Organization Supabase-66CDA329-0531-4B12-AC32-A7E21931F876" src="https://github.com/user-attachments/assets/454917ce-1a96-4e50-b003-6c16a541b39a" /> | | <img width="1060" height="822" alt="CleanShot 2026-03-13 at 11 04 43@2x-2616AECB-8203-4439-A1CD-45AB18FC4CA8 1-584A0600-CCE0-4F16-9111-9BEB94BE85EC" src="https://github.com/user-attachments/assets/871c7dcb-120e-40cd-afc8-2cec95e4b7ae" /> | <img width="1024" height="794" alt="Join Organization Supabase-26AD978E-4CF9-4600-9885-082084349E94" src="https://github.com/user-attachments/assets/ee9bfaff-dde4-4366-abae-77dc8a95c4ef" /> | | <img width="1024" height="794" alt="Supabase-4993D74C-D62B-43B7-9681-826BE1591AC4" src="https://github.com/user-attachments/assets/1c411ae0-90e7-481d-a4cc-3eac26267291" /> | <img width="1024" height="794" alt="Join Organization Supabase-C84D4E4C-24F5-463D-B1D6-D11D3256596F" src="https://github.com/user-attachments/assets/688387a4-3c49-41db-b89c-7c5531e91aed" /> | | <img width="1024" height="794" alt="Supabase-D9BD2601-98A4-489D-A51D-CEB73F51FA6F" src="https://github.com/user-attachments/assets/6d1da65f-d655-4047-9f6a-db65f8c0a729" /> | <img width="1024" height="794" alt="Join Organization Supabase-50065F40-179A-4BD6-8F1D-6106FFD8A15C" src="https://github.com/user-attachments/assets/e61809f9-dcec-4e51-ba94-91b04010ec50" /> | ## Testing notes Staging invite emails are generated with the fixed staging dashboard origin, for example: ```text https://supabase.green/dashboard/join?token=...&slug=... ``` To test this PR preview with a real invite token, keep the path and query string from the email but replace the origin with the Vercel preview origin, for example: ```text https://studio-staging-git-dnywh-featconnect-interstitial-join-supabase.vercel.app/dashboard/join?token=...&slug=... ``` ### Manual state checks - **Signed out:** open the swapped invite URL in an incognito window or a browser signed out of Studio. Expected: `View invitation`, sign-in/create-account actions, and no loading skeleton hang. - **Wrong account:** sign in to the PR preview as an account that is not the invite recipient, then open the swapped invite URL. Expected: `Wrong account`, warning callout, and `Sign out`. - **Happy path:** sign in as the invited email address, then open the swapped invite URL. Expected: `Join {Organization}`, signed-in account row, `Accept invite`, and `Decline`. Accepting should join the organization. - **Invalid token:** alter one character in the token in the swapped invite URL. Expected: invalid invite state. - **No longer valid:** accept the invite once, then open the same swapped invite URL again. Expected: no-longer-valid/already-used state, depending on the backend response. ### Test-covered states Expired invites, generic backend error, loading, and create-account-disabled states are harder to force manually in staging. They are covered by `tests/components/OrganizationInvite.test.tsx`. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Redesigned the organization invitation experience with an interstitial layout, clearer early-return flows for signed-out, loading, expired/invalid, wrong-account, and accepted-invite states; primary CTA now reads “Accept invite”. * Streamlined error and sign-out flows with clearer, focused messaging. * **New Features** * Added a reusable interstitial layout and compact account row for invitation screens. * **Tests** * Added comprehensive tests covering invite states, accept/decline actions, and error handling. [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45774) <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
d676c832f3 |
fix(studio): pre-empt React 19 regressions in tests + Support form (#45784)
Four React-19-sensitive patterns that pass on React 18 today but break
under React 19 (verified on the in-flight TanStack Start branch).
Landing on master now so the eventual React 19 upgrade is a no-op for
tests, instead of a separate cleanup pass under upgrade pressure.
Each fix is a strict superset / less-fragile equivalent of the existing
pattern, so master (React 18) stays green.
**Changed:**
- `hooks/misc/useStateTransition.ts` — fire on entry into `newTest` from
any state other than `newTest`, instead of requiring exactly `prevTest →
newTest`. React 18+ auto-batches dispatches across awaits (e.g.
`dispatch SUBMIT` in the handler, `dispatch ERROR` in `onError`),
collapsing `editing → submitting → error` into a single render where the
intermediate `submitting` tick is never observed. Strict superset of the
old check for our reducers — `success`/`error` are only reachable from
`submitting`.
- `Support/CategoryAndSeverityInfo.tsx` — guard `onValueChange` against
Radix Select's spurious `''` emission. When the controlled value
transitions from `undefined` to a defined value whose `SelectItem` isn't
mounted yet (dropdown closed → items haven't registered), Radix's hidden
`BubbleSelect` fires `onValueChange('')` and clobbers the field. No
`SelectItem` can have `value=""` (Radix throws), so any `''` is
guaranteed spurious — drop it before calling `field.onChange`.
([radix-ui/primitives#3381](https://github.com/radix-ui/primitives/issues/3381))
- `EditSecretModal.test.tsx` — `getByLabelText` → `findByLabelText`.
Under React 19's scheduling, the decrypted-value query resolves on a
separate render tick, so form fields appear one tick after the skeleton.
- `LogsPreviewer.test.tsx` — `addEventListener('click', spy)` instead of
`loadOlder.onclick = vi.fn()`. React 19 reassigns `.onclick` on managed
elements as part of its event wiring, clobbering the direct-property
spy.
## To test
### Unit tests
- `pnpm --filter studio test` — all unit tests pass on master (React 18)
### Support form URL prefill (Radix Select guard)
- `/support/new?category=Problem` → category dropdown reads "APIs and
client libraries" on first paint
- `/support/new?category=dashboard_bug` → "Dashboard bug"
(case-insensitive match)
- `/support/new?category=invalid_garbage` → falls back to "Select an
issue" placeholder, no crash
- `/support/new?subject=My%20issue&message=Details%20here` → subject and
message inputs are prefilled
- `/support/new?projectRef=<your-ref>&category=Problem` → both project
selector and category set, library selector appears
- With a prefilled URL, click the category dropdown and pick a different
option — the new value sticks (this is the path that surfaced the Radix
bug, want to confirm we didn't break user selection)
- DevTools console on first load should be clean — no React hydration
mismatch warning
### Support form submit (`useStateTransition` success + error branches)
- Submit a valid support form → green toast "Support request sent"
appears **once**, view swaps to the success screen, one `POST
/platform/feedback/send` in the network panel
- Block `POST /platform/feedback/send` in DevTools → submit → red error
toast appears **once** (not twice — if you see two toasts the relaxed
transition is firing more than it should), form stays editable with all
inputs preserved
- Unblock and submit again → success path runs cleanly
### Sidebar support form (same reducer + `useStateTransition`, separate
component)
- Open the support widget in the side nav (`SupportSidebarForm`)
- Repeat the success and error paths — should behave identically
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Fixed category selector to prevent selected values from being
unexpectedly cleared during form interactions.
* **Tests**
* Improved test reliability for modal field rendering and event handling
assertions.
* **Chores**
* Clarified internal comments for form initialization logic.
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45784)
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
|
||
|
|
d8bb0ade65 |
feat(studio): add timezone picker to user dropdown (#45517)
## Problem The dashboard renders all timestamps in the browser's local timezone. When debugging app issues, users often want to see logs and timestamps in a different timezone (e.g. their app's deployment region) without changing their OS clock. ## Fix - New Timezone submenu in the user-avatar dropdown, sitting next to the existing Theme picker. Search-as-you-type combobox over the full IANA catalog plus an Auto detect option. - Selection persists in localStorage (`supabase-ui-timezone`) and survives `clearLocalStorage()`. No backend schema change. - New `lib/datetime.tsx` exposes pure timezone-aware formatters (`formatDateTime`, `formatDate`, `formatTime`, `formatFromNow`, `toTimezone`) plus a `TimezoneProvider` and matching React hooks (`useTimezone`, `useFormatDateTime`, ...). The pure functions take `tz` explicitly so they're easy to unit test (17 vitest cases covering DST transitions, multi-tz formatting, unix-micro/Date inputs, invalid-tz fallback). - The selected timezone propagates to every existing `<TimestampInfo>` in Studio via a new `TimestampInfoProvider` context exported from `ui-patterns`. No per-callsite changes needed for those ~20+ surfaces. - The `UnifiedLogs` date column migrates off `date-fns` to the new `useFormatDateTime` hook (the rest of the date-fns callers stay as-is, since they're either internal range math or non-display). - `ALL_TIMEZONES` (~600 entries) moves out of `PITR.constants.ts` into a shared `lib/constants/timezones.ts`. PITR keeps a re-export shim so its callers don't move. New `TIMEZONES_BY_IANA` dedupes the catalog by primary IANA name (the original list contains both PDT and PST rows for `America/Los_Angeles`, etc.) and `findTimezoneByIana` provides reverse lookup. - Telemetry: `timezone_picker_clicked` PostHog event with `previousTimezone`, `nextTimezone`, `isAutoDetected` properties. Notes for reviewers: - Bare `dayjs(x).format(...)` calls (~157 files) intentionally still render in browser-local time. Surfaces opt in by switching to the new wrappers, so this PR is the abstraction plus logs adoption; broader migration is a follow-up. - Two `// prettier-ignore` lines (`apps/studio/pages/_app.tsx`, `apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.fields.tsx`) work around a pre-existing local-tooling issue where `prettier-plugin-sql-cst` strips angle-bracket type arguments under certain conditions. Project's pinned prettier (3.8.1) does not strip; the issue surfaces with a globally-installed prettier. Worth tracking separately. - Hydration: `guessLocalTimezone()` and `useLocalStorageQuery` are client-only. Studio is mostly CSR via the Pages Router, but any SSR'd `<TimestampInfo>` may briefly render in the server's tz before client hydration. Existing behavior already had this mismatch with `.local()`; this PR does not regress it. - Backend timestamps round-tripped through query params and mutations stay UTC. The picker is display-only. ## How to test - Run `pnpm dev:studio`, sign in. - Open the user avatar dropdown (top right). Hover Timezone. - Search for "tokyo", pick `(UTC+09:00) Osaka, Sapporo, Tokyo`. - Open any project, navigate to Logs (e.g. `Project > Logs > Edge Functions`). Hover a log row's timestamp; the popover should show UTC, the chosen tz (`Asia/Tokyo`), and the relative time. Visible cell text should be in JST. - Visit any page that uses `<TimestampInfo>` (Database > Backups, Project Pause state, Edge Function details). Same tooltip should reflect Asia/Tokyo. - Refresh the page; timezone is still Asia/Tokyo. - Reopen the picker, choose Auto detect; timestamps revert to browser local. - Run `pnpm --filter studio test lib/datetime.test.ts`. 17 tests should pass. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Timezone selector added to the user menu with auto-detect and manual override * App-wide timezone provider and hooks plus a shared timezone catalog for consistent timezone-aware display * Timestamp components accept an optional timezone prop and respect user preference (persisted) * **Bug Fixes / Improvements** * Logs and timestamp displays now use the new timezone formatting hooks * **Tests** * Added comprehensive datetime and timezone catalog tests * **Telemetry** * Telemetry event added for timezone picker interactions <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
153f2619bc |
feat(studio): show expand affordance for large SQL result cells (#45589)
## Summary
- Adds a hover-revealed expand button to SQL result cells whose value is
unlikely to fit on one line (objects, arrays, strings >60 chars, or
strings with newlines). Clicking opens the existing `CellDetailPanel`
for that cell.
- Switches the expand state from a boolean tied to the selected cell to
a direct `{ column, value }` reference, so the context menu and the new
button both target the right-clicked / clicked cell.
- Extracts the per-cell renderer into its own `ResultCell` component to
keep `Results.tsx` digestible and the new affordance isolated.
- Covers the new logic with exhaustive `isLargeValue` unit tests and a
`ResultCell` component test (visibility, click, right-click).
Linear: [FE-3130](https://linear.app/supabase/issue/FE-3130)
## Test plan
- [x] Run a SQL query that returns mixed cell types (short strings, long
strings, JSON objects, arrays, nulls) and confirm the expand button
appears only on cells where content is likely truncated.
- [x] Hover a large cell and click the expand button — `CellDetailPanel`
opens with the correct column + value.
- [x] Right-click a large cell and choose "View cell content" — same
panel opens with the right cell.
- [x] Right-click a small cell and "Copy cell content" — clipboard
contains the raw value.
- [x] Resize a column wider than its content and confirm the button
still positions correctly.
- [x] `pnpm vitest` for `Results.utils.test.ts`, `Results.test.tsx`,
`ResultCell.test.tsx` — all green.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Enhanced SQL result cells with automatic detection and expansion
functionality for large values (exceeding 60 characters or containing
line breaks)
* Added expand button to view full cell content directly in results
* Integrated right-click context menu for cell content options
* Improved display of null values in query results
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
|
||
|
|
ee5d4a9314 |
chore: remove format param from audit log query (#45466)
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Cleanup after shipping https://github.com/supabase/supabase/pull/45389, the backend is now defaulting to the new v2 `format`, and made `format` param optional. So this: - removes references to `v2` naming, as this is the only format - removes the `format` query param from the audit logs API calls ## What is the current behavior? Same audit log functionality shown in https://github.com/supabase/supabase/pull/45389 ## What is the new behavior? Functionally the same behavior for audit logs. - [x] Manual test in staging ## Additional context ⚠️ Will leave the `do-not-merge` tag on until: - [ ] backend `format` optional PR lands in production. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Consolidated audit log type definitions and updated internal API request formatting for audit endpoints across Account and Organization audit log components. No changes to user-facing functionality or audit log display. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
e540f9089f |
fix(studio): restore Safari table editor cell copy and context menu (#45353)
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Bug fix. ## What is the current behavior? - Safari Table Editor cells fail to copy from a focused cell with `⌘C`. - Safari right-click can show the browser menu instead of the custom cell menu. - Copy can leave RDG's copied-cell fill behind. ## What is the new behavior? - Reuses the existing shared `copyToClipboard(value, onSuccess)` pattern, with the Safari clipboard fix inside that util. - Handles selected-cell `⌘C` in the RDG keydown path, preventing browser/RDG defaults and showing the success toast only after copy. - Replaces the row-level synthetic context-menu shim with RDG's `onCellContextMenu`, so we prevent Safari's browser menu at the source and select/focus the target cell. - Keeps the selected-cell outline while the controlled menu is open. ## Additional context - `RowRenderer` was only supporting the old context-menu shim; removing it is part of moving to RDG's cell event path. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **New Features** * Context menu now provides feedback with toast notifications when copying cells or rows. * Selected cells retain their visual styling when context menu is open. * **Bug Fixes** * Improved keyboard shortcut handling for copy functionality. * Enhanced clipboard error handling with user-friendly error messages. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Ali Waseem <waseema393@gmail.com> |
||
|
|
d666b950ff |
feat: update audit log schema & UI (#45389)
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? - Update to the audit log schema (changes were already applied in staging) - Updates the org & project audit log page to reflect the changes to the schema - The schema should be agnostic to whether logs were emitted to logflare with the old & new schema format - the backend adjusts old logs to the new format. ## What is the current behavior? Currently, the frontend is parsing the legacy schema as the backend returns this by default. It also doesn't show some of these new fields yet. ## What is the new behavior? ### Org Audit Logs - Table View <img width="1810" height="1310" alt="CleanShot 2026-04-29 at 18 27 22" src="https://github.com/user-attachments/assets/47fec068-1ffa-4e52-bc46-3bffdef55adb" /> ### Org Audit Logs - Single log View <img width="1842" height="1494" alt="CleanShot 2026-04-29 at 18 27 37" src="https://github.com/user-attachments/assets/3cff3bdf-4a6a-4981-acaa-7f95bb3ae9cf" /> Note that the `Target` field is no longer there. We just show the `metadata` JSON. <img width="1842" height="1494" alt="CleanShot 2026-04-29 at 18 27 40" src="https://github.com/user-attachments/assets/d2e681f0-41a6-4bc7-a3d7-ec7e8101616c" /> ### Account (Profile) Audit Logs - Table View <img width="1810" height="1310" alt="CleanShot 2026-04-29 at 18 25 20" src="https://github.com/user-attachments/assets/c72e19df-9b82-4611-8889-7af463769550" /> ### Account (Profile) Audit Logs - Single log View <img width="1810" height="1310" alt="CleanShot 2026-04-29 at 18 25 32" src="https://github.com/user-attachments/assets/46f8d3b6-4f2f-4944-b891-431a93e5f3c3" /> ## Additional context ⚠️ currently leaving the `do not merge` tag on, until: - [x] I have verified it works in staging - [x] We've deployed the new schema to production <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Audit logs now use the v2 format with microsecond-accurate timestamps, improved ordering, and a revamped details panel showing clearer actor/action/request/project/org fields and fallback labels. * Page/header layout updated so audit logs render at top level with adjusted spacing. * **Refactor** * Shared sorting and filtering utilities added for consistent user/project filtering and non-mutating log sorting. * **Tests** * Added tests for timestamp conversion, sorting, filtering, and date-range formatting. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
7f5865872a |
Enforce noUnusedLocals and noUnusedParameters in tsconfig.json + fix all related issues (#45264)
## Context Enforce `noUnusedLocals` and `noUnusedParameters` in tsconfig.json + fix all related issues |
||
|
|
8454ec241d |
feat: add batch email org invites (#44832)
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Feature ## What is the current behavior? When sending organization invites to multiple emails at once, the invitations API is called once for each email passed, passing a single email address in the `email` field. ## What is the new behavior? A single request is used when sending multiple organization invites at once, by using the new `emails` field. ## Additional context This builds further on https://github.com/supabase/supabase/pull/42637 ⚠️ Note: I'd like to merge this after getting the API changes in first: https://github.com/supabase/platform/pull/31561 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Bulk invite: paste comma-separated emails (parsed, trimmed, deduplicated, lowercased) and send as a single batched request; inputs are categorized into new, already-invited, and existing members. * SSO and project scope options included in invite payloads. * **Bug Fixes / API** * Invitation endpoint now accepts multiple emails; resend uses multi-email format. Invalid addresses are blocked, existing members are skipped with error toasts, and overall success is reported with the dialog closing after invite. * **Tests** * Added unit and UI tests covering parsing, categorization, payload building, validation limits, and invite flows. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Danny White <3104761+dnywh@users.noreply.github.com> |
||
|
|
1ab7251060 |
chore(studio): clarify partnered orgs and projects (#44328)
## What kind of change does this PR introduce? UI improvements. - Resolves DEPR-401 - Resolves DEPR-424 - Resolves DEPR-425 ## What is the current behaviour? Studio currently blurs two different concepts together: - `billing_partner` / `billing_via_partner`, which represent real billing ownership for marketplace-managed organisations such as AWS and Vercel - Stripe connection state, which is not actually partner billing in the same sense, but was previously being mocked through the same UI paths That made the Stripe work harder to reason about and left some local behaviour dependent on temporary overrides rather than the API shape we want to ship. ## What is the new behaviour? This PR separates those concerns while keeping the existing AWS and Vercel marketplace experience intact. - AWS and Vercel continue to use `billing_partner` / `billing_via_partner` for billing ownership, lockouts, and manage CTAs - Stripe display state now comes from `integration_source`, which lets Studio show Stripe-specific badges and alerts without treating Stripe as a billing partner - organisation-level partner UI is unified across AWS, Vercel, and Stripe, including the org banner, navbar icon treatment, and organisation cards - project-level Stripe UI now appears only when the project itself is marked as Stripe-connected, including the project switcher, project list surfaces, and a project-level banner - Stripe-connected organisations are no longer incorrectly blocked behind the AWS/Vercel-style billing management alerts for invoices, billing address, payment methods, or plan changes - banner dismissal is scoped to the relevant org/project and partner/integration state ## Review order Most of the diff size here is regression tests and generated types. The behavioural changes are concentrated in a smaller set of files. Recommended review order: 1. `integration_source` vs `billing_partner` data-model split and org/project query mapping 2. org-level UI: partner icon, org banner, org dropdown/card treatment 3. billing gating updates for Stripe vs AWS/Vercel 4. project-level Stripe UI: dropdown, list surfaces, banner 5. tests and generated types | Stripe Org(s) | | --- | | <img width="1024" height="759" alt="Organizations Supabase" src="https://github.com/user-attachments/assets/d0ef338c-3b41-4c6d-b3bd-f21a2c182840" /> | | Vercel Org(s) | | --- | | <img width="1024" height="759" alt="Organizations Supabase" src="https://github.com/user-attachments/assets/1dc57770-3f24-45ac-840f-34680555cde8" /> | | AWS Org(s) | | --- | | <img width="1024" height="759" alt="Organizations Supabase" src="https://github.com/user-attachments/assets/7847dad0-ee30-4a65-ab0b-b3b16af0d34f" /> | | Stripe Org, Non-Stripe Project | | --- | | <img width="1152" height="885" alt="Mallet Toolshed Supabase-1673E019-792C-462C-B6F8-C5DDB810B331" src="https://github.com/user-attachments/assets/556fbea3-b5ae-4f2f-96b9-6f66c6654e4a" /> | | Stripe Org, Stripe Project | | --- | | <img width="1152" height="885" alt="Hammer Toolshed Supabase-7E86C17C-561F-4221-BD16-EAFF7D41AAE0" src="https://github.com/user-attachments/assets/94f8daf6-0320-413e-8d56-59f9acaaea15" /> | | Vercel Org | | --- | | <img width="1024" height="759" alt="Projects Toolshed Supabase-A7891653-9366-4B99-89DD-789D70CD52E3" src="https://github.com/user-attachments/assets/c87ee6e8-4451-4866-a905-23a38b2593e3" /> | | AWS Org | | --- | | <img width="1024" height="759" alt="Projects Toolshed Supabase-58A43ECE-569E-4541-9463-346A90B02CFF" src="https://github.com/user-attachments/assets/9350a180-4d58-42a1-ad1a-95893c2e8b12" /> | This also removes the old Stripe mock override path in Studio so the frontend matches the intended API model more closely. ## ~~Dependencies~~ (merged!) This work depends on the private platform change that exposes `integration_source` on the relevant organisation and project payloads: - https://github.com/supabase/platform/pull/31874 _Update: now merged._ ## Local testing ### Stripe If you have the private `platform` repo checked out locally, make sure your local API returns `integration_source: 'stripe_projects'` consistently for the Stripe-linked org/project you are testing. Important responses: - `/platform/organizations` - `/platform/organizations/:slug/projects` - `/platform/projects/:ref` Verify: - org banner and org icon show the Stripe connected state - unopened and opened project switcher both show Stripe only for Stripe-linked projects - project cards / table rows show the Stripe chip only for Stripe-linked projects - the project-level Stripe banner appears across project surfaces - billing address, tax ID, invoices, payment methods, and plan changes remain editable in Studio for Stripe orgs ### Vercel Use a Vercel Marketplace org with real `billing_partner` / `billing_via_partner` values. Important org-level endpoints for local mocking in `platform`: - `/platform/organizations` - `/platform/organizations/:slug` - `/platform/organizations/:slug/billing/subscription` Project-level Vercel indicators still come from `/platform/integrations/:slug`, not `integration_source`. ### AWS Use an AWS Marketplace org with real `billing_partner` / `billing_via_partner` values. Important org-level endpoints for local mocking in `platform`: - `/platform/organizations` - `/platform/organizations/:slug` - `/platform/organizations/:slug/billing/subscription` AWS does not currently have a Stripe-like project-level indicator in these org/project payloads. ## Notes - `billing_partner` is no longer the right abstraction for the Stripe-connected case in this PR. It remains the source of truth for marketplace billing ownership, while Stripe currently uses `integration_source` as a connection/display signal. - I re-ran `pnpm api:codegen` while tightening this PR and kept only the generated type changes this branch actually depends on, to avoid unrelated API drift in the review. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Stripe Projects integration added for billing and project flows * Partner icons/badges shown across org and project lists, dropdowns, and rows * Dismissible, partner-specific marketplace/integration banners with contextual CTA behavior * Improved partner-billing detection to drive billing UI and invoice/plan availability * **Tests** * Extensive new test coverage for billing UI, partner-managed fallbacks, banners, icons, and related flows <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com> |
||
|
|
e8df67d5d5 |
chore: migrate shortcuts to new hooks API (#44955)
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Cleanup shortcuts with new hooks <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Centralized keyboard shortcut system for consistent shortcut behavior across the app and moved preference toggles to a unified registry. * **New Features** * Added explicit shortcuts for Command Menu, AI Assistant, Inline Editor, and result copy/download actions. * Hotkey preferences UI now renders dynamically from the centralized shortcut list. * **Tests** * Test helpers updated to include the command menu provider for accurate shortcut behavior in tests. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
1b1d05ff96 |
chore: upgrade vite to v8 and vitest to v4 (#44833)
Upgrade vite and vitest to their latest major versions across the
monorepo, along with related packages.
**Changed:**
- `vite` catalog: `^7.3.2` → `^8.0.8` (Rolldown replaces esbuild/Rollup)
- `vitest` catalog: `^3.2.0` → `^4.1.4`
- `@vitejs/plugin-react`: `^4.3.4` → `^6.0.1`
- `@vitest/coverage-v8`: `^3.2.0` → `^4.1.4`
- `@vitest/ui`: `^3.2.0` → `^4.1.4`
- `vite-tsconfig-paths`: `^4.3.2` / `^5.1.4` → `^6.1.1`
**Pinned to vite 7:**
- `apps/lite-studio` — `@react-router/dev` hasn't declared vite 8
support yet
- `blocks/vue` — Nuxt plugins (`vite-plugin-inspect`, `vite-dev-rpc`,
`vite-hot-client`, `vite-plugin-vue-tracer`) haven't declared vite 8
support yet
**Test fixes for vitest 4 breaking changes:**
- **`apps/studio/lib/api/snippets.utils.test.ts`** — Replaced
`vi.mock('fs/promises')` automock with an explicit factory. Vitest 4's
automocking doesn't create mock functions for getter-based exports on
Node built-ins, so `mockedFS.access.mockResolvedValue` etc. were
`undefined`.
- **`apps/studio/lib/api/self-hosted/functions/index.test.ts`** —
Changed `mockReturnValue` to `mockImplementation(function() { ... })`
for a constructor mock. Vitest 4 no longer allows `mockReturnValue` when
the mock is called with `new`.
- **`apps/studio/tests/pages/api/mcp/index.test.ts`** — Changed arrow
function to regular `function` in `mockImplementation` for
`StreamableHTTPServerTransport`. Arrow functions can't be constructors,
and vitest 4 now enforces this.
- **`packages/ui-patterns/vitest.setup.ts`** — Changed `ResizeObserver`
mock from arrow function to regular `function` for the same constructor
enforcement reason. This was crashing Radix popover rendering in jsdom.
## To test
- `pnpm test:studio` — all 226 test files should pass
- `pnpm --filter ui-patterns vitest run` — all 183 tests should pass
- `pnpm --filter www test -- --run` — all 19 tests should pass
- `pnpm --filter ui vitest run` — all tests should pass
- `pnpm --filter dev-tools vitest run` — all tests should pass
- `pnpm --filter ai-commands vitest run` — all tests should pass
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Standardized and updated development tooling versions and version
sources for consistent installs across the repo (Vite, Vitest,
vite-tsconfig-paths and related plugins/catalog entries).
* **Tests**
* Improved test mocks and typings (updated mock
factories/implementations and tightened spy/type assertions) to increase
test reliability and compatibility with updated tooling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
|
||
|
|
21584fe512 |
feat(studio): add backup cli instructions (#44621)
## Problem When a project is paused, in a failed state, or about to be deleted, users have no obvious way to take a logical backup of their data before proceeding. This is particularly risky at deletion time — once deleted, data is gone. ## Solution Introduce a new `LogicalBackupCliInstructions` component that surfaces ready-to-run `supabase db dump` commands pre-filled with the project's direct connection details. ### Where it appears | State | How | |---|---| | Project paused (restorable) | Inline in `ProjectPausedState` with a note to resume first | | Pause failed | Dialog via "Download backup" button when no backup is available | | Restore failed | Dialog via "Download backup" button when no backup is available | | Delete project modal | Inline in `DeleteProjectModal` for all plans | Not shown in `PauseDisabledState` (project paused 90+ days, compute stopped — `pg_dump` would fail anyway). ### What the component does - Fetches the project's direct connection settings via `useProjectSettingsV2Query` - Builds a connection URI with a `[YOUR-PASSWORD]` placeholder (password is never stored or displayed) - Shows three shell commands to dump roles, schema, and data separately — mirroring the [logical backup docs](https://supabase.com/docs/guides/platform/backups) - Optionally shows a **Reset database password** button (gated on `UPDATE projects` permission); shown in the paused state, hidden elsewhere via `showResetPassword={false}` - Includes inline guidance to percent-encode special characters in the password ### Shell safety The generated `--db-url` values are wrapped in single quotes to prevent shell metacharacter expansion when users paste and run the commands. `npx supabase login` is intentionally omitted — the `--db-url` flag authenticates directly against Postgres and does not require a Supabase account. ### Backup button behaviour in failed states The "Download backup" button in `PauseFailedState` and `RestoreFailedState` now always stays enabled: - **Backup available** — downloads immediately (unchanged) - **No backup / physical backups** — opens a dialog with CLI instructions instead of silently failing ## How to test **Delete project flow** 1. Open any project → Settings → General → Delete project 2. Verify the CLI backup section appears with the project's host, port, user, and db name pre-filled 3. Verify no Reset database password button is shown **Paused project** 1. Open a paused project (`ProjectPausedState`) — verify CLI instructions appear with the "Your project must be resumed before running these commands." note 2. Open a project paused for 90+ days (`PauseDisabledState`) — verify CLI instructions do not appear **Failed states** 1. Simulate a pause-failed or restore-failed state 2. If a downloadable backup exists — "Download backup" downloads it directly 3. Block the backup API or use a project with physical backups — "Download backup" should open the CLI instructions dialog **Error state** 1. Block the project settings API call (DevTools → Network → block request) 2. Verify an error message appears with a link to Database settings 3. Verify a loading skeleton shows while the request is in flight --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
cfce3c7efc |
refactor: save tax ID via customer update endpoint (#44728)
## Summary
- Consolidate tax ID saving into the `PUT
/organizations/{slug}/customer` endpoint instead of using a
separate `/tax-ids` endpoint
## Test plan
### Updating billing information
From the billing dashboard`/org/_/billing`:
- [ ] Manually test updating billing address + tax ID from org billing
settings - single API call should save both
- [ ] Clear the Tax ID in the org, save and assert that it has been
deleted
- [ ] Modify all the fields in the address form, including TaxID. Click
"Cancel" and assert that everything has returned to the previous values.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Billing address and tax ID updates are now sent in a single update
operation.
* Error messaging for billing updates consolidated into a single failure
notification.
* Tax ID handling clarified: you can clear tax ID explicitly or leave it
unchanged; omitting address fields no longer overwrites existing
address.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
||
|
|
205cbe7d26 | chore(studio}: enforce import order, remove bare import specifiers (#44585) | ||
|
|
fbb0770b47 |
fix(studio): AI assistant results make page unresponsive (#44578)
## Summary Fixes https://linear.app/supabase/issue/FE-2941 - Replaced per-cell `ContextMenu_Shadcn_` in SQL result tables with a single shared instance - Each Radix ContextMenu registers a `keydown` listener on `document` via `useEffect`. With 1000+ row result sets, this created thousands of document-level listeners. Chrome trace showed listeners growing from 21k to 347k, with every keystroke taking ~250ms (70k+ function calls per long task) - Fixed DataGrid not rendering in Firefox by using flex layout instead of `height: 100%` for sizing - Fixed double scrollbar in QueryBlock results by making the container a flex column and removing `overflow-auto` - Moved format utils into `Results.utils.ts` ## Test plan The `Results` component and `QueryBlock` are used in several places. Each should be verified: - [x] **AI Assistant** — Have the assistant run a query returning 1000+ rows. Verify the page stays responsive while typing and there is only a single scrollbar on the results table - [x] **AI Assistant (Firefox)** — Same as above but in Firefox. Verify the results table actually renders - [x] **SQL Editor results panel** — Run a query in the SQL Editor. Verify results render correctly with a single scrollbar in the utility panel - [x] **SQL Editor explain tab** — Run an EXPLAIN query. Verify explain results render - [x] **Editor Panel** (used in Table Editor SQL preview) — Verify results display correctly - [x] **Context menu** — Right-click a cell in any of the above and verify "Copy cell content" and "View cell content" still work ## Traces <img width="891" height="599" alt="image" src="https://github.com/user-attachments/assets/6e1b710b-ca9e-4748-9369-d03457d80206" /> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Fixed context menu behavior so it opens at the cursor and is instantiated once. * Improved clipboard copy formatting for cell values; NULLs copy as empty and cells render as "NULL". * **Style** * Adjusted table layout and scrolling behavior to improve results container sizing. * **Tests** * Added tests for results rendering, context-menu behavior, and cell/clipboard formatting utilities. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |