mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
feat(studio): add Explorer query tabs (#49038)
<img width="1693" height="1037" alt="image" src="https://github.com/user-attachments/assets/51fdf618-f06e-45ca-bf30-e1307dfbb372" /> ## Stack Depends on #49041. Followed by #49028. ## Summary - add a dedicated ad-hoc query tab type and route under Explorer - connect query tabs to the shared `QueryEditor` through a `QueryTab` lifecycle adapter - add local query draft/result state and restore query tabs from their routes - confirm before closing populated local-only drafts and clean up their state on close ## To test 1. Open Explorer, select **Run SQL**, enter `select 1`, and run the query. 2. Rename the query, reload the page, then close the tab and confirm the discard prompt appears. ## Why Explorer needs a lightweight place to run SQL without creating a snippet. This layer adds the query-tab lifecycle on top of the shared editor foundation. ## Impact Queries in this layer run against the selected project's primary database. Drafts are local to the browser and are discarded when their tabs are closed. ## Validation - fresh non-incremental Studio TypeScript check - 22 focused tests across query draft state, tab state, and notebook tab registration <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added support for creating, opening, editing, and running SQL queries in Explorer. * Added project-scoped persistence for query drafts and results. * Added dedicated query routes, query icons, and query tabs. * Added unsaved-changes warnings when closing query tabs. * Added a pinned Explorer Home tab and “New query” option. * Improved notebook tab registration and editor tab organization. * **Bug Fixes** * Improved tab navigation, closing behavior, and layout. * **Tests** * Added coverage for query persistence, cleanup, restoration, and tab navigation. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
This commit is contained in:
1 parent
076a205ac4
commit
75d16f360f
23 files changed
+772
-320
No files matched your search
@@ -229,6 +229,7 @@ import { Route as ProjectRefFunctionsFunctionSlugLogsRouteImport } from './route
|
||||
import { Route as ProjectRefFunctionsFunctionSlugInvocationsRouteImport } from './routes/project/$ref/functions/$functionSlug/invocations'
|
||||
import { Route as ProjectRefFunctionsFunctionSlugDetailsRouteImport } from './routes/project/$ref/functions/$functionSlug/details'
|
||||
import { Route as ProjectRefFunctionsFunctionSlugCodeRouteImport } from './routes/project/$ref/functions/$functionSlug/code'
|
||||
import { Route as ProjectRefExplorerQueryIdRouteImport } from './routes/project/$ref/explorer/query/$id'
|
||||
import { Route as ProjectRefExplorerNotebookIdRouteImport } from './routes/project/$ref/explorer/notebook/$id'
|
||||
import { Route as ProjectRefDatabaseTriggersEventRouteImport } from './routes/project/$ref/database/triggers/event'
|
||||
import { Route as ProjectRefDatabaseTriggersDataRouteImport } from './routes/project/$ref/database/triggers/data'
|
||||
@@ -1516,6 +1517,12 @@ const ProjectRefFunctionsFunctionSlugCodeRoute =
|
||||
path: '/code',
|
||||
getParentRoute: () => ProjectRefFunctionsFunctionSlugRoute,
|
||||
} as any)
|
||||
const ProjectRefExplorerQueryIdRoute =
|
||||
ProjectRefExplorerQueryIdRouteImport.update({
|
||||
id: '/query/$id',
|
||||
path: '/query/$id',
|
||||
getParentRoute: () => ProjectRefExplorerRoute,
|
||||
} as any)
|
||||
const ProjectRefExplorerNotebookIdRoute =
|
||||
ProjectRefExplorerNotebookIdRouteImport.update({
|
||||
id: '/notebook/$id',
|
||||
@@ -2283,6 +2290,7 @@ export interface FileRoutesByFullPath {
|
||||
'/project/$ref/database/triggers/data': typeof ProjectRefDatabaseTriggersDataRoute
|
||||
'/project/$ref/database/triggers/event': typeof ProjectRefDatabaseTriggersEventRoute
|
||||
'/project/$ref/explorer/notebook/$id': typeof ProjectRefExplorerNotebookIdRoute
|
||||
'/project/$ref/explorer/query/$id': typeof ProjectRefExplorerQueryIdRoute
|
||||
'/project/$ref/functions/$functionSlug/code': typeof ProjectRefFunctionsFunctionSlugCodeRoute
|
||||
'/project/$ref/functions/$functionSlug/details': typeof ProjectRefFunctionsFunctionSlugDetailsRoute
|
||||
'/project/$ref/functions/$functionSlug/invocations': typeof ProjectRefFunctionsFunctionSlugInvocationsRoute
|
||||
@@ -2580,6 +2588,7 @@ export interface FileRoutesByTo {
|
||||
'/project/$ref/database/triggers/data': typeof ProjectRefDatabaseTriggersDataRoute
|
||||
'/project/$ref/database/triggers/event': typeof ProjectRefDatabaseTriggersEventRoute
|
||||
'/project/$ref/explorer/notebook/$id': typeof ProjectRefExplorerNotebookIdRoute
|
||||
'/project/$ref/explorer/query/$id': typeof ProjectRefExplorerQueryIdRoute
|
||||
'/project/$ref/functions/$functionSlug/code': typeof ProjectRefFunctionsFunctionSlugCodeRoute
|
||||
'/project/$ref/functions/$functionSlug/details': typeof ProjectRefFunctionsFunctionSlugDetailsRoute
|
||||
'/project/$ref/functions/$functionSlug/invocations': typeof ProjectRefFunctionsFunctionSlugInvocationsRoute
|
||||
@@ -2893,6 +2902,7 @@ export interface FileRoutesById {
|
||||
'/project/$ref/database/triggers/data': typeof ProjectRefDatabaseTriggersDataRoute
|
||||
'/project/$ref/database/triggers/event': typeof ProjectRefDatabaseTriggersEventRoute
|
||||
'/project/$ref/explorer/notebook/$id': typeof ProjectRefExplorerNotebookIdRoute
|
||||
'/project/$ref/explorer/query/$id': typeof ProjectRefExplorerQueryIdRoute
|
||||
'/project/$ref/functions/$functionSlug/code': typeof ProjectRefFunctionsFunctionSlugCodeRoute
|
||||
'/project/$ref/functions/$functionSlug/details': typeof ProjectRefFunctionsFunctionSlugDetailsRoute
|
||||
'/project/$ref/functions/$functionSlug/invocations': typeof ProjectRefFunctionsFunctionSlugInvocationsRoute
|
||||
@@ -3205,6 +3215,7 @@ export interface FileRouteTypes {
|
||||
| '/project/$ref/database/triggers/data'
|
||||
| '/project/$ref/database/triggers/event'
|
||||
| '/project/$ref/explorer/notebook/$id'
|
||||
| '/project/$ref/explorer/query/$id'
|
||||
| '/project/$ref/functions/$functionSlug/code'
|
||||
| '/project/$ref/functions/$functionSlug/details'
|
||||
| '/project/$ref/functions/$functionSlug/invocations'
|
||||
@@ -3502,6 +3513,7 @@ export interface FileRouteTypes {
|
||||
| '/project/$ref/database/triggers/data'
|
||||
| '/project/$ref/database/triggers/event'
|
||||
| '/project/$ref/explorer/notebook/$id'
|
||||
| '/project/$ref/explorer/query/$id'
|
||||
| '/project/$ref/functions/$functionSlug/code'
|
||||
| '/project/$ref/functions/$functionSlug/details'
|
||||
| '/project/$ref/functions/$functionSlug/invocations'
|
||||
@@ -3814,6 +3826,7 @@ export interface FileRouteTypes {
|
||||
| '/project/$ref/database/triggers/data'
|
||||
| '/project/$ref/database/triggers/event'
|
||||
| '/project/$ref/explorer/notebook/$id'
|
||||
| '/project/$ref/explorer/query/$id'
|
||||
| '/project/$ref/functions/$functionSlug/code'
|
||||
| '/project/$ref/functions/$functionSlug/details'
|
||||
| '/project/$ref/functions/$functionSlug/invocations'
|
||||
@@ -5561,6 +5574,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof ProjectRefFunctionsFunctionSlugCodeRouteImport
|
||||
parentRoute: typeof ProjectRefFunctionsFunctionSlugRoute
|
||||
}
|
||||
'/project/$ref/explorer/query/$id': {
|
||||
id: '/project/$ref/explorer/query/$id'
|
||||
path: '/query/$id'
|
||||
fullPath: '/project/$ref/explorer/query/$id'
|
||||
preLoaderRoute: typeof ProjectRefExplorerQueryIdRouteImport
|
||||
parentRoute: typeof ProjectRefExplorerRoute
|
||||
}
|
||||
'/project/$ref/explorer/notebook/$id': {
|
||||
id: '/project/$ref/explorer/notebook/$id'
|
||||
path: '/notebook/$id'
|
||||
@@ -6517,11 +6537,13 @@ const ProjectRefEditorRouteWithChildren =
|
||||
interface ProjectRefExplorerRouteChildren {
|
||||
ProjectRefExplorerIndexRoute: typeof ProjectRefExplorerIndexRoute
|
||||
ProjectRefExplorerNotebookIdRoute: typeof ProjectRefExplorerNotebookIdRoute
|
||||
ProjectRefExplorerQueryIdRoute: typeof ProjectRefExplorerQueryIdRoute
|
||||
}
|
||||
|
||||
const ProjectRefExplorerRouteChildren: ProjectRefExplorerRouteChildren = {
|
||||
ProjectRefExplorerIndexRoute: ProjectRefExplorerIndexRoute,
|
||||
ProjectRefExplorerNotebookIdRoute: ProjectRefExplorerNotebookIdRoute,
|
||||
ProjectRefExplorerQueryIdRoute: ProjectRefExplorerQueryIdRoute,
|
||||
}
|
||||
|
||||
const ProjectRefExplorerRouteWithChildren =
|
||||
|
||||
Reference in new issue
Block a user