mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
chore(studio): rename SQL Editor sidebar items (#46241)
## What kind of change does this PR introduce? Chore. Rename / UX copy update in Studio's SQL Editor. ## What is the current behavior? The SQL Editor sidebar has a **Community** section containing two pages: - **Templates**: reusable SQL snippets for common tasks - **Quickstarts**: end-to-end examples and starter projects The section label "Community" is misleading because these are first-party presets maintained by the Supabase team, not user-contributed content. "Quickstarts" also doesn't clearly convey "end-to-end example". ## What is the new behavior? - **Community** → **Reference** (sidebar section header) - **Quickstarts** → **Examples** (route: `/sql/quickstarts` → `/sql/examples`) - Templates keeps its name and route (`/sql/templates`), description updated to "Reusable SQL snippets for common tasks" Taxonomy: - **Templates** = reusable SQL patterns you adapt - **Examples** = end-to-end walkthroughs you run as-is A permanent redirect is added so `/sql/quickstarts` gracefully forwards to `/sql/examples`. The existing `/sql/templates` route is unchanged. | Before | After | | --- | --- | | <img width="1024" height="759" alt="Quickstarts SQL Editor Pickles Pantry Supabase-644881A5-6396-43AA-9AC4-61FFFFF18831" src="https://github.com/user-attachments/assets/ff876c78-c499-4bac-b1ae-91e31817511d" /> | <img width="1024" height="759" alt="Examples SQL Editor Pickles Pantry Supabase-573775FA-E38F-4F8D-92E3-114237410C36" src="https://github.com/user-attachments/assets/bdb8910f-94e9-4c21-bb3a-f6513008d8bc" /> | ## Additional context - `CommunitySnippetsSection.tsx`: header label + route keys updated; the underlying `community` localStorage key is intentionally unchanged to avoid resetting stored collapsed/expanded state for existing users. - ESLint rule baselines and a docs troubleshooting link updated to reflect the new filenames/routes. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Updated troubleshooting guide to reference the correct SQL examples location. * **New Features** * Renamed "Quickstarts" to "Examples" throughout the SQL editor for improved clarity. * Updated SQL template and examples section descriptions and labels to better reflect their purpose. * Reorganized SQL editor navigation to streamline access to templates and examples. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46241?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: Joshen Lim <joshenlimek@gmail.com>
This commit is contained in:
15 files changed
+43
-217
No files matched your search
@@ -127,7 +127,7 @@ DROP FUNCTION <function name>() CASCADE;
|
||||
4. Recreate the triggers
|
||||
|
||||
**Example function and trigger using security definer**
|
||||
The [SQL Editor](/dashboard/project/_/sql/) contains a template for [User Management](/dashboard/project/_/sql/quickstarts). Within it, there is a working example of how to setup triggers with security definer that may be worth referencing:
|
||||
The [SQL Editor](/dashboard/project/_/sql/) contains a template for [User Management](/dashboard/project/_/sql/examples). Within it, there is a working example of how to setup triggers with security definer that may be worth referencing:
|
||||
|
||||
```sql
|
||||
create table profiles (
|
||||
|
||||
+3
-3
@@ -132,7 +132,7 @@
|
||||
"pages/project/[ref]/auth/policies.tsx": 2,
|
||||
"pages/project/[ref]/editor/[id].tsx": 1,
|
||||
"pages/project/[ref]/settings/jwt/legacy.tsx": 1,
|
||||
"pages/project/[ref]/sql/quickstarts.tsx": 1,
|
||||
"pages/project/[ref]/sql/examples.tsx": 1,
|
||||
"pages/project/[ref]/sql/templates.tsx": 1,
|
||||
"pages/sign-in-mfa.tsx": 1,
|
||||
"state/role-impersonation-state.tsx": 1,
|
||||
@@ -363,7 +363,7 @@
|
||||
"components/interfaces/SQLEditor/RenameQueryModal.tsx": 2,
|
||||
"components/interfaces/SQLEditor/SQLEditor.tsx": 4,
|
||||
"components/interfaces/SQLEditor/SQLEditor.utils.ts": 1,
|
||||
"components/interfaces/SQLEditor/SQLTemplates/SQLQuickstarts.tsx": 1,
|
||||
"components/interfaces/SQLEditor/SQLTemplates/SQLExamples.tsx": 1,
|
||||
"components/interfaces/SQLEditor/SQLTemplates/SQLTemplates.tsx": 1,
|
||||
"components/interfaces/SQLEditor/UtilityPanel/CellDetailPanel.tsx": 1,
|
||||
"components/interfaces/SQLEditor/UtilityPanel/ChartConfig.tsx": 2,
|
||||
@@ -755,7 +755,7 @@
|
||||
"components/interfaces/SQLEditor/InlineWidget.tsx": 1,
|
||||
"components/interfaces/SQLEditor/MonacoEditor.tsx": 1,
|
||||
"components/interfaces/SQLEditor/RenameQueryModal.tsx": 1,
|
||||
"components/interfaces/SQLEditor/SQLTemplates/SQLQuickstarts.tsx": 1,
|
||||
"components/interfaces/SQLEditor/SQLTemplates/SQLExamples.tsx": 1,
|
||||
"components/interfaces/SQLEditor/SQLTemplates/SQLTemplates.tsx": 1,
|
||||
"components/interfaces/SQLEditor/UtilityPanel/ReadOnlyBadge.tsx": 1,
|
||||
"components/interfaces/SQLEditor/UtilityPanel/Results.tsx": 1,
|
||||
|
||||
@@ -20,7 +20,7 @@ export interface DownloadSnippetModalProps extends ModalProps {
|
||||
id: string
|
||||
}
|
||||
|
||||
const DownloadSnippetModal = ({ id, ...props }: DownloadSnippetModalProps) => {
|
||||
export const DownloadSnippetModal = ({ id, ...props }: DownloadSnippetModalProps) => {
|
||||
const snapV2 = useSqlEditorV2StateSnapshot()
|
||||
|
||||
const snippet = snapV2.snippets[id]?.snippet
|
||||
@@ -129,5 +129,3 @@ const DownloadSnippetModal = ({ id, ...props }: DownloadSnippetModalProps) => {
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default DownloadSnippetModal
|
||||
@@ -38,7 +38,7 @@ const formSchema = z.object({
|
||||
description: z.string().optional(),
|
||||
})
|
||||
|
||||
const RenameQueryModal = ({
|
||||
export const RenameQueryModal = ({
|
||||
snippet = {} as any,
|
||||
visible,
|
||||
onCancel,
|
||||
@@ -237,5 +237,3 @@ const RenameQueryModal = ({
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default RenameQueryModal
|
||||
+4
-7
@@ -15,7 +15,7 @@ import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
|
||||
import { useProfile } from '@/lib/profile'
|
||||
import { useSqlEditorV2StateSnapshot } from '@/state/sql-editor-v2'
|
||||
|
||||
const SQLQuickstarts = () => {
|
||||
const SQLExamples = () => {
|
||||
const router = useRouter()
|
||||
const { ref } = useParams()
|
||||
const { profile } = useProfile()
|
||||
@@ -65,11 +65,8 @@ const SQLQuickstarts = () => {
|
||||
<div className="block h-full space-y-8 overflow-y-auto p-6 px-10 bg-dash-sidebar dark:bg-surface-100">
|
||||
<div className="mb-8">
|
||||
<div className="mb-6">
|
||||
<h2 className="mb-1">Quickstarts</h2>
|
||||
<p className="text-foreground-light text-sm">
|
||||
Click on any script to fill the query box, modify the script, then click
|
||||
<span className="text-code">Run</span>.
|
||||
</p>
|
||||
<h2 className="mb-1">Examples</h2>
|
||||
<p className="text-foreground-light text-sm">End-to-end examples and starter projects</p>
|
||||
</div>
|
||||
<div className="grid gap-4 sm:grid-cols-1 lg:grid-cols-2 xl:grid-cols-3">
|
||||
{quickStart.map((x, i) => (
|
||||
@@ -96,4 +93,4 @@ const SQLQuickstarts = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export default SQLQuickstarts
|
||||
export default SQLExamples
|
||||
@@ -65,12 +65,8 @@ const SQLTemplates = () => {
|
||||
<div className="block h-full space-y-8 overflow-y-auto p-6 px-10 bg-dash-sidebar dark:bg-surface-100">
|
||||
<div>
|
||||
<div className="mb-6">
|
||||
<h2 className="mb-1">Scripts</h2>
|
||||
<p className="text-foreground-light text-sm">Quick scripts to run on your database.</p>
|
||||
<p className="text-foreground-light text-sm">
|
||||
Click on any script to fill the query box, modify the script, then click
|
||||
<span className="text-code">Run</span>.
|
||||
</p>
|
||||
<h2 className="mb-1">Templates</h2>
|
||||
<p className="text-foreground-light text-sm">Reusable SQL snippets for common tasks</p>
|
||||
</div>
|
||||
<div className="grid gap-4 sm:grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 ">
|
||||
{sql.map((x, i) => (
|
||||
|
||||
+4
-4
@@ -11,9 +11,9 @@ import { InnerSideMenuDataItem } from 'ui-patterns/InnerSideMenu'
|
||||
import { DEFAULT_SECTION_STATE, type SectionState } from './SQLEditorNav.constants'
|
||||
import { useLocalStorage } from '@/hooks/misc/useLocalStorage'
|
||||
|
||||
const OPTIONS = ['templates', 'quickstarts'] as const
|
||||
const OPTIONS = ['templates', 'examples'] as const
|
||||
|
||||
export function CommunitySnippetsSection() {
|
||||
export function ReferenceSnippetsSection() {
|
||||
const { ref } = useParams()
|
||||
const router = useRouter()
|
||||
|
||||
@@ -38,14 +38,14 @@ export function CommunitySnippetsSection() {
|
||||
})
|
||||
}}
|
||||
>
|
||||
<InnerSideMenuCollapsibleTrigger title="Community" />
|
||||
<InnerSideMenuCollapsibleTrigger title="Reference" />
|
||||
<InnerSideMenuCollapsibleContent className="group-data-open:pt-2">
|
||||
{OPTIONS.map((pageId) => {
|
||||
const active = isPageActive(pageId)
|
||||
return (
|
||||
<InnerSideMenuDataItem
|
||||
key={pageId}
|
||||
title={pageId === 'templates' ? 'Templates' : 'Quickstarts'}
|
||||
title={pageId === 'templates' ? 'Templates' : 'Examples'}
|
||||
isActive={active}
|
||||
isOpened={false}
|
||||
href={`/project/${ref}/sql/${pageId}`}
|
||||
+1
-3
@@ -1,6 +1,6 @@
|
||||
import { Skeleton } from 'ui'
|
||||
|
||||
const SQLEditorLoadingSnippets = () => {
|
||||
export const SQLEditorLoadingSnippets = () => {
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-row h-6 px-3 items-center gap-3">
|
||||
@@ -26,5 +26,3 @@ const SQLEditorLoadingSnippets = () => {
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default SQLEditorLoadingSnippets
|
||||
@@ -14,27 +14,27 @@ import {
|
||||
} from 'ui-patterns'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
|
||||
import { CommunitySnippetsSection } from './CommunitySnippetsSection'
|
||||
import { DeleteSnippetsModal } from './DeleteSnippetsModal'
|
||||
import { ReferenceSnippetsSection } from './ReferenceSnippetsSection'
|
||||
import { ShareSnippetModal } from './ShareSnippetModal'
|
||||
import SQLEditorLoadingSnippets from './SQLEditorLoadingSnippets'
|
||||
import { SQLEditorLoadingSnippets } from './SQLEditorLoadingSnippets'
|
||||
import { DEFAULT_SECTION_STATE, type SectionState } from './SQLEditorNav.constants'
|
||||
import { formatFolderResponseForTreeView, getLastItemIds, ROOT_NODE } from './SQLEditorNav.utils'
|
||||
import { SQLEditorTreeViewItem } from './SQLEditorTreeViewItem'
|
||||
import { UnshareSnippetModal } from './UnshareSnippetModal'
|
||||
import DownloadSnippetModal from '@/components/interfaces/SQLEditor/DownloadSnippetModal'
|
||||
import { DownloadSnippetModal } from '@/components/interfaces/SQLEditor/DownloadSnippetModal'
|
||||
import { MoveQueryModal } from '@/components/interfaces/SQLEditor/MoveQueryModal'
|
||||
import RenameQueryModal from '@/components/interfaces/SQLEditor/RenameQueryModal'
|
||||
import { RenameQueryModal } from '@/components/interfaces/SQLEditor/RenameQueryModal'
|
||||
import { generateSnippetTitle } from '@/components/interfaces/SQLEditor/SQLEditor.constants'
|
||||
import { createSqlSnippetSkeletonV2 } from '@/components/interfaces/SQLEditor/SQLEditor.utils'
|
||||
import { EmptyPrivateQueriesPanel } from '@/components/layouts/SQLEditorLayout/PrivateSqlSnippetEmpty'
|
||||
import EditorMenuListSkeleton from '@/components/layouts/TableEditorLayout/EditorMenuListSkeleton'
|
||||
import { EditorMenuListSkeleton } from '@/components/layouts/TableEditorLayout/EditorMenuListSkeleton'
|
||||
import { useSqlEditorTabsCleanup } from '@/components/layouts/Tabs/Tabs.utils'
|
||||
import { useContentCountQuery } from '@/data/content/content-count-query'
|
||||
import { useContentDeleteMutation } from '@/data/content/content-delete-mutation'
|
||||
import { useSQLSnippetFoldersDeleteMutation } from '@/data/content/sql-folders-delete-mutation'
|
||||
import { Snippet, SnippetFolder, useSQLSnippetFoldersQuery } from '@/data/content/sql-folders-query'
|
||||
import { useSqlSnippetsQuery } from '@/data/content/sql-snippets-query'
|
||||
import { useSqlSnippetsQuery, type SqlSnippet } from '@/data/content/sql-snippets-query'
|
||||
import { useLocalStorage } from '@/hooks/misc/useLocalStorage'
|
||||
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
|
||||
import { useProfile } from '@/lib/profile'
|
||||
@@ -209,7 +209,7 @@ export const SQLEditorNav = ({ sort = 'inserted_at' }: SQLEditorNavProps) => {
|
||||
let snippets = favoriteSqlSnippetsData?.pages.flatMap((page) => page.contents ?? []) ?? []
|
||||
|
||||
if (snippet && snippet.favorite && !snippets.find((x) => x.id === snippet.id)) {
|
||||
snippets.push(snippet as any)
|
||||
snippets.push(snippet as SqlSnippet)
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -260,7 +260,7 @@ export const SQLEditorNav = ({ sort = 'inserted_at' }: SQLEditorNavProps) => {
|
||||
let snippets = sharedSqlSnippetsData?.pages.flatMap((page) => page.contents ?? []) ?? []
|
||||
|
||||
if (snippet && snippet.visibility === 'project' && !snippets.find((x) => x.id === snippet.id)) {
|
||||
snippets.push(snippet as any)
|
||||
snippets.push(snippet as SqlSnippet)
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -750,7 +750,7 @@ export const SQLEditorNav = ({ sort = 'inserted_at' }: SQLEditorNavProps) => {
|
||||
|
||||
<InnerSideMenuSeparator />
|
||||
|
||||
<CommunitySnippetsSection />
|
||||
<ReferenceSnippetsSection />
|
||||
|
||||
<InnerSideMenuSeparator />
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ import { ShareSnippetModal } from './ShareSnippetModal'
|
||||
import { formatFolderResponseForTreeView, getLastItemIds } from './SQLEditorNav.utils'
|
||||
import { SQLEditorTreeViewItem } from './SQLEditorTreeViewItem'
|
||||
import { UnshareSnippetModal } from './UnshareSnippetModal'
|
||||
import DownloadSnippetModal from '@/components/interfaces/SQLEditor/DownloadSnippetModal'
|
||||
import RenameQueryModal from '@/components/interfaces/SQLEditor/RenameQueryModal'
|
||||
import { DownloadSnippetModal } from '@/components/interfaces/SQLEditor/DownloadSnippetModal'
|
||||
import { RenameQueryModal } from '@/components/interfaces/SQLEditor/RenameQueryModal'
|
||||
import { useContentCountQuery } from '@/data/content/content-count-query'
|
||||
import { useContentInfiniteQuery } from '@/data/content/content-infinite-query'
|
||||
import { Snippet, SNIPPET_PAGE_LIMIT } from '@/data/content/sql-folders-query'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { memo } from 'react'
|
||||
import { Skeleton } from 'ui'
|
||||
|
||||
const EditorMenuListSkeleton = memo(function EditorMenuListSkeleton() {
|
||||
export const EditorMenuListSkeleton = memo(function EditorMenuListSkeleton() {
|
||||
const items = [
|
||||
{ width: 'w-40', opacity: 'opacity-100' },
|
||||
{ width: 'w-32', opacity: 'opacity-100' },
|
||||
@@ -21,5 +21,3 @@ const EditorMenuListSkeleton = memo(function EditorMenuListSkeleton() {
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
export default EditorMenuListSkeleton
|
||||
@@ -20,7 +20,7 @@ import { parseSupaTable } from '@/components/grid/SupabaseGrid.utils'
|
||||
import { SupaTable } from '@/components/grid/types'
|
||||
import { ProtectedSchemaWarning } from '@/components/interfaces/Database/ProtectedSchemaWarning'
|
||||
import { ErrorMatcher } from '@/components/interfaces/ErrorHandling/ErrorMatcher'
|
||||
import EditorMenuListSkeleton from '@/components/layouts/TableEditorLayout/EditorMenuListSkeleton'
|
||||
import { EditorMenuListSkeleton } from '@/components/layouts/TableEditorLayout/EditorMenuListSkeleton'
|
||||
import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
|
||||
import { InfiniteListDefault, LoaderForIconMenuItems } from '@/components/ui/InfiniteList'
|
||||
import SchemaSelector from '@/components/ui/SchemaSelector'
|
||||
|
||||
@@ -1,37 +1,11 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useParams } from 'common'
|
||||
import { partition } from 'lodash'
|
||||
import { Table2 } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { toast } from 'sonner'
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
Card,
|
||||
CardContent,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
cn,
|
||||
SQL_ICON,
|
||||
Tabs_Shadcn_,
|
||||
TabsContent_Shadcn_,
|
||||
TabsList_Shadcn_,
|
||||
TabsTrigger_Shadcn_,
|
||||
} from 'ui'
|
||||
import { Badge, Button, Card, CardContent, CardHeader, CardTitle } from 'ui'
|
||||
|
||||
import { useEditorType } from '../editors/EditorsLayout.hooks'
|
||||
import { ActionCard } from './ActionCard'
|
||||
import { RecentItems } from './RecentItems'
|
||||
import { SQL_TEMPLATES } from '@/components/interfaces/SQLEditor/SQLEditor.queries'
|
||||
import { createSqlSnippetSkeletonV2 } from '@/components/interfaces/SQLEditor/SQLEditor.utils'
|
||||
import { useSendEventMutation } from '@/data/telemetry/send-event-mutation'
|
||||
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
|
||||
import { useQuerySchemaState } from '@/hooks/misc/useSchemaQueryState'
|
||||
import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
|
||||
import { useIsProtectedSchema } from '@/hooks/useProtectedSchemas'
|
||||
import { useProfile } from '@/lib/profile'
|
||||
import {
|
||||
useImpersonatedAAL,
|
||||
useImpersonatedExternalAuth,
|
||||
@@ -39,43 +13,20 @@ import {
|
||||
useIsImpersonatingAnon,
|
||||
useRoleImpersonationStateSnapshot,
|
||||
} from '@/state/role-impersonation-state'
|
||||
import { useSqlEditorV2StateSnapshot } from '@/state/sql-editor-v2'
|
||||
import { useTableEditorStateSnapshot } from '@/state/table-editor'
|
||||
import { createTabId, useTabsStateSnapshot } from '@/state/tabs'
|
||||
import { type ResponseError } from '@/types'
|
||||
|
||||
export function NewTab() {
|
||||
const router = useRouter()
|
||||
const { ref } = useParams()
|
||||
const editor = useEditorType()
|
||||
const { profile } = useProfile()
|
||||
const { data: org } = useSelectedOrganizationQuery()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const { selectedSchema } = useQuerySchemaState()
|
||||
const { isSchemaLocked } = useIsProtectedSchema({ schema: selectedSchema })
|
||||
|
||||
const snap = useTableEditorStateSnapshot()
|
||||
const snapV2 = useSqlEditorV2StateSnapshot()
|
||||
const tabs = useTabsStateSnapshot()
|
||||
const [templates] = partition(SQL_TEMPLATES, { type: 'template' })
|
||||
const [quickstarts] = partition(SQL_TEMPLATES, { type: 'quickstart' })
|
||||
|
||||
const roleState = useRoleImpersonationStateSnapshot()
|
||||
const impersonatingAnon = useIsImpersonatingAnon()
|
||||
const impersonatedUser = useImpersonatedUser()
|
||||
const impersonatedExternalUser = useImpersonatedExternalAuth()
|
||||
const impersonatedAAL = useImpersonatedAAL()
|
||||
|
||||
const { mutate: sendEvent } = useSendEventMutation()
|
||||
const { can: canCreateSQLSnippet } = useAsyncCheckPermissions(
|
||||
PermissionAction.CREATE,
|
||||
'user_content',
|
||||
{
|
||||
resource: { type: 'sql', owner_id: profile?.id },
|
||||
subject: { id: profile?.id },
|
||||
}
|
||||
)
|
||||
|
||||
const tableEditorActions = isSchemaLocked
|
||||
? []
|
||||
: [
|
||||
@@ -89,52 +40,7 @@ export function NewTab() {
|
||||
},
|
||||
]
|
||||
|
||||
const sqlEditorActions = [
|
||||
{
|
||||
icon: <SQL_ICON className={cn('fill-foreground', 'w-4 h-4')} strokeWidth={1.5} />,
|
||||
title: 'New SQL Snippet',
|
||||
description: 'Execute SQL queries',
|
||||
bgColor: 'bg-green-500',
|
||||
isBeta: false,
|
||||
onClick: () => router.push(`/project/${ref}/sql/new`),
|
||||
},
|
||||
]
|
||||
|
||||
const actions = editor === 'sql' ? sqlEditorActions : tableEditorActions
|
||||
|
||||
const handleNewQuery = async (sql: string, name: string) => {
|
||||
if (!ref) return console.error('Project ref is required')
|
||||
if (!project) return console.error('Project is required')
|
||||
if (!profile) return console.error('Profile is required')
|
||||
|
||||
if (!canCreateSQLSnippet) {
|
||||
return toast('Your queries will not be saved as you do not have sufficient permissions')
|
||||
}
|
||||
|
||||
try {
|
||||
const snippet = createSqlSnippetSkeletonV2({
|
||||
name,
|
||||
sql,
|
||||
owner_id: profile?.id,
|
||||
project_id: project?.id,
|
||||
})
|
||||
snapV2.addSnippet({ projectRef: ref, snippet })
|
||||
snapV2.addNeedsSaving(snippet.id)
|
||||
|
||||
const tabId = createTabId('sql', { id: snippet.id })
|
||||
|
||||
tabs.addTab({
|
||||
id: tabId,
|
||||
type: 'sql',
|
||||
label: name,
|
||||
metadata: { sqlId: snippet.id },
|
||||
})
|
||||
|
||||
router.push(`/project/${ref}/sql/${snippet.id}`)
|
||||
} catch (error) {
|
||||
toast.error(`Failed to create new query: ${(error as ResponseError).message}`)
|
||||
}
|
||||
}
|
||||
const actions = editor === 'table' ? tableEditorActions : []
|
||||
|
||||
return (
|
||||
<div className="bg-surface-100 h-full overflow-y-auto py-12">
|
||||
@@ -178,71 +84,6 @@ export function NewTab() {
|
||||
|
||||
<RecentItems />
|
||||
</div>
|
||||
|
||||
{editor === 'sql' && (
|
||||
<div className="flex flex-col gap-4 mx-auto py-10">
|
||||
<Tabs_Shadcn_ defaultValue="templates">
|
||||
<TabsList_Shadcn_ className="mx-auto justify-center gap-5">
|
||||
<TabsTrigger_Shadcn_ value="templates">Templates</TabsTrigger_Shadcn_>
|
||||
<TabsTrigger_Shadcn_ value="quickstarts">Quickstarts</TabsTrigger_Shadcn_>
|
||||
</TabsList_Shadcn_>
|
||||
<TabsContent_Shadcn_ value="templates" className="max-w-5xl mx-auto py-5">
|
||||
<div className="grid grid-cols-3 gap-4 px-8">
|
||||
{templates.slice(0, 9).map((item, i) => (
|
||||
<ActionCard
|
||||
onClick={() => {
|
||||
handleNewQuery(item.sql, item.title)
|
||||
sendEvent({
|
||||
action: 'sql_editor_template_clicked',
|
||||
properties: { templateName: item.title },
|
||||
groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
|
||||
})
|
||||
}}
|
||||
bgColor="bg-alternative border"
|
||||
key={`action-card-${i}`}
|
||||
{...item}
|
||||
icon={
|
||||
<SQL_ICON className={cn('fill-foreground', 'w-4 h-4')} strokeWidth={1.5} />
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex justify-center mt-5">
|
||||
<Button asChild type="default">
|
||||
<Link href={`/project/${ref}/sql/templates`}>View more templates</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</TabsContent_Shadcn_>
|
||||
<TabsContent_Shadcn_ value="quickstarts" className="max-w-5xl mx-auto py-5">
|
||||
<div className="grid grid-cols-3 gap-4 px-8">
|
||||
{quickstarts.map((item, i) => (
|
||||
<ActionCard
|
||||
onClick={() => {
|
||||
handleNewQuery(item.sql, item.title)
|
||||
sendEvent({
|
||||
action: 'sql_editor_quickstart_clicked',
|
||||
properties: { quickstartName: item.title },
|
||||
groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
|
||||
})
|
||||
}}
|
||||
bgColor="bg-alternative border"
|
||||
key={`action-card-${i}`}
|
||||
{...item}
|
||||
icon={
|
||||
<SQL_ICON className={cn('fill-foreground', 'w-4 h-4')} strokeWidth={1.5} />
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex justify-center mt-5">
|
||||
<Button asChild type="default">
|
||||
<Link href={`/project/${ref}/sql/quickstarts`}>View more templates</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</TabsContent_Shadcn_>
|
||||
</Tabs_Shadcn_>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -323,8 +323,8 @@ const nextConfig = {
|
||||
permanent: true,
|
||||
},
|
||||
{
|
||||
source: '/project/:ref/sql/templates',
|
||||
destination: '/project/:ref/sql',
|
||||
source: '/project/:ref/sql/quickstarts',
|
||||
destination: '/project/:ref/sql/examples',
|
||||
permanent: true,
|
||||
},
|
||||
{
|
||||
|
||||
+9
-9
@@ -2,7 +2,7 @@ import { useParams } from 'next/navigation'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import SQLQuickstarts from '@/components/interfaces/SQLEditor/SQLTemplates/SQLQuickstarts'
|
||||
import SQLExamples from '@/components/interfaces/SQLEditor/SQLTemplates/SQLExamples'
|
||||
import DefaultLayout from '@/components/layouts/DefaultLayout'
|
||||
import { EditorBaseLayout } from '@/components/layouts/editors/EditorBaseLayout'
|
||||
import SQLEditorLayout from '@/components/layouts/SQLEditorLayout/SQLEditorLayout'
|
||||
@@ -10,7 +10,7 @@ import { SQLEditorMenu } from '@/components/layouts/SQLEditorLayout/SQLEditorMen
|
||||
import { createTabId, useTabsStateSnapshot } from '@/state/tabs'
|
||||
import type { NextPageWithLayout } from '@/types'
|
||||
|
||||
const SqlQuickstarts: NextPageWithLayout = () => {
|
||||
const SqlExamples: NextPageWithLayout = () => {
|
||||
const router = useRouter()
|
||||
const ref = useParams<{ ref: string }>()?.ref
|
||||
const tabs = useTabsStateSnapshot()
|
||||
@@ -18,22 +18,22 @@ const SqlQuickstarts: NextPageWithLayout = () => {
|
||||
useEffect(() => {
|
||||
if (!router.isReady) return
|
||||
|
||||
const tabId = createTabId('sql', { id: 'quickstarts' })
|
||||
const tabId = createTabId('sql', { id: 'examples' })
|
||||
tabs.addTab({
|
||||
id: tabId,
|
||||
type: 'sql',
|
||||
label: 'Quickstarts',
|
||||
label: 'Examples',
|
||||
metadata: {
|
||||
sqlId: 'quickstarts',
|
||||
name: 'quickstarts',
|
||||
sqlId: 'examples',
|
||||
name: 'examples',
|
||||
},
|
||||
})
|
||||
}, [router.isReady, ref])
|
||||
|
||||
return <SQLQuickstarts />
|
||||
return <SQLExamples />
|
||||
}
|
||||
|
||||
SqlQuickstarts.getLayout = (page) => (
|
||||
SqlExamples.getLayout = (page) => (
|
||||
<DefaultLayout>
|
||||
<EditorBaseLayout productMenu={<SQLEditorMenu />} product="SQL Editor">
|
||||
<SQLEditorLayout>{page}</SQLEditorLayout>
|
||||
@@ -41,4 +41,4 @@ SqlQuickstarts.getLayout = (page) => (
|
||||
</DefaultLayout>
|
||||
)
|
||||
|
||||
export default SqlQuickstarts
|
||||
export default SqlExamples
|
||||
Reference in new issue
Block a user