mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
Clean up tabs interface feature flags (#36441)
* Clean up tabs interface feature flags * Update SQL e2e test
This commit is contained in:
1 parent
4945ba1861
commit
327cab053a
29 files changed
+213
-653
No files matched your search
@@ -8,20 +8,6 @@ export const FEATURE_PREVIEWS = [
|
||||
isNew: true,
|
||||
isPlatformOnly: false,
|
||||
},
|
||||
{
|
||||
key: LOCAL_STORAGE_KEYS.UI_TABLE_EDITOR_TABS,
|
||||
name: 'Table Editor Tabs',
|
||||
discussionsUrl: 'https://github.com/orgs/supabase/discussions/35636',
|
||||
isNew: true,
|
||||
isPlatformOnly: false,
|
||||
},
|
||||
{
|
||||
key: LOCAL_STORAGE_KEYS.UI_SQL_EDITOR_TABS,
|
||||
name: 'SQL Editor Tabs',
|
||||
discussionsUrl: 'https://github.com/orgs/supabase/discussions/35636',
|
||||
isNew: true,
|
||||
isPlatformOnly: true,
|
||||
},
|
||||
{
|
||||
key: LOCAL_STORAGE_KEYS.UI_PREVIEW_API_SIDE_PANEL,
|
||||
name: 'Project API documentation',
|
||||
|
||||
@@ -2,8 +2,6 @@ import { noop } from 'lodash'
|
||||
import { PropsWithChildren, createContext, useContext, useEffect, useState } from 'react'
|
||||
|
||||
import { FeatureFlagContext, LOCAL_STORAGE_KEYS } from 'common'
|
||||
import { useFlag } from 'hooks/ui/useFlag'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import { EMPTY_OBJ } from 'lib/void'
|
||||
import { FEATURE_PREVIEWS } from './FeaturePreview.constants'
|
||||
|
||||
@@ -21,15 +19,10 @@ export const useFeaturePreviewContext = () => useContext(FeaturePreviewContext)
|
||||
|
||||
export const FeaturePreviewContextProvider = ({ children }: PropsWithChildren<{}>) => {
|
||||
const { hasLoaded } = useContext(FeatureFlagContext)
|
||||
const enableTabsInterface = useFlag('tabsInterface')
|
||||
|
||||
// [Joshen] Similar logic to feature flagging previews, we can use flags to default opt in previews
|
||||
const isDefaultOptIn = (feature: (typeof FEATURE_PREVIEWS)[number]) => {
|
||||
switch (feature.key) {
|
||||
case LOCAL_STORAGE_KEYS.UI_SQL_EDITOR_TABS:
|
||||
return enableTabsInterface
|
||||
case LOCAL_STORAGE_KEYS.UI_TABLE_EDITOR_TABS:
|
||||
return enableTabsInterface
|
||||
default:
|
||||
return false
|
||||
}
|
||||
@@ -86,14 +79,3 @@ export const useIsInlineEditorEnabled = () => {
|
||||
const { flags } = useFeaturePreviewContext()
|
||||
return flags[LOCAL_STORAGE_KEYS.UI_PREVIEW_INLINE_EDITOR]
|
||||
}
|
||||
|
||||
export const useIsTableEditorTabsEnabled = () => {
|
||||
const { flags } = useFeaturePreviewContext()
|
||||
return flags[LOCAL_STORAGE_KEYS.UI_TABLE_EDITOR_TABS]
|
||||
}
|
||||
|
||||
export const useIsSQLEditorTabsEnabled = () => {
|
||||
const { flags } = useFeaturePreviewContext()
|
||||
if (!IS_PLATFORM) return false
|
||||
return flags[LOCAL_STORAGE_KEYS.UI_SQL_EDITOR_TABS]
|
||||
}
|
||||
@@ -14,15 +14,11 @@ import { CLSPreview } from './CLSPreview'
|
||||
import { FEATURE_PREVIEWS } from './FeaturePreview.constants'
|
||||
import { useFeaturePreviewContext } from './FeaturePreviewContext'
|
||||
import { InlineEditorPreview } from './InlineEditorPreview'
|
||||
import { SqlEditorTabsPreview } from './SqlEditorTabs'
|
||||
import { TableEditorTabsPreview } from './TableEditorTabs'
|
||||
|
||||
const FEATURE_PREVIEW_KEY_TO_CONTENT: {
|
||||
[key: string]: ReactNode
|
||||
} = {
|
||||
[LOCAL_STORAGE_KEYS.UI_PREVIEW_INLINE_EDITOR]: <InlineEditorPreview />,
|
||||
[LOCAL_STORAGE_KEYS.UI_TABLE_EDITOR_TABS]: <TableEditorTabsPreview />,
|
||||
[LOCAL_STORAGE_KEYS.UI_SQL_EDITOR_TABS]: <SqlEditorTabsPreview />,
|
||||
[LOCAL_STORAGE_KEYS.UI_PREVIEW_API_SIDE_PANEL]: <APISidePanelPreview />,
|
||||
[LOCAL_STORAGE_KEYS.UI_PREVIEW_CLS]: <CLSPreview />,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import Image from 'next/image'
|
||||
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
import { Admonition } from 'ui-patterns'
|
||||
|
||||
export const InlineEditorPreview = () => {
|
||||
return (
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
import Image from 'next/image'
|
||||
|
||||
export const SqlEditorTabsPreview = () => {
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<Image
|
||||
src={`${BASE_PATH}/img/previews/tabs-sql.png`}
|
||||
width={1860}
|
||||
height={970}
|
||||
alt="api-docs-side-panel-preview"
|
||||
className="rounded border"
|
||||
/>
|
||||
<p className="text-foreground-light text-sm">
|
||||
The SQL Editor now features tabs for improved navigation and organization. Conveniently go
|
||||
between the queries that you're focused on, and collapse the sidebar for a bigger real
|
||||
estate while writing your queries.
|
||||
</p>
|
||||
<div className="space-y-2 !mt-4">
|
||||
<p className="text-sm">Enabling this preview will:</p>
|
||||
<ul className="list-disc pl-6 text-sm text-foreground-light space-y-1">
|
||||
<li>Enable opening of queries in the SQL Editor as tabs</li>
|
||||
<li>Support closing of the navigation sidebar for a larger code editor space</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
import { ExternalLink, X } from 'lucide-react'
|
||||
import Image from 'next/image'
|
||||
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
import { useEditorType } from 'components/layouts/editors/EditorsLayout.hooks'
|
||||
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
|
||||
import { InlineLinkClassName } from 'components/ui/InlineLink'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
import {
|
||||
Alert_Shadcn_,
|
||||
AlertDescription_Shadcn_,
|
||||
AlertTitle_Shadcn_,
|
||||
Badge,
|
||||
Button,
|
||||
cn,
|
||||
HoverCard,
|
||||
HoverCardContent_Shadcn_,
|
||||
HoverCardTrigger_Shadcn_,
|
||||
} from 'ui'
|
||||
import { useIsSQLEditorTabsEnabled, useIsTableEditorTabsEnabled } from './FeaturePreviewContext'
|
||||
|
||||
export const TableEditorTabsPreview = () => {
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<Image
|
||||
src={`${BASE_PATH}/img/previews/tabs-editor.png`}
|
||||
width={1860}
|
||||
height={970}
|
||||
alt="api-docs-side-panel-preview"
|
||||
className="rounded border"
|
||||
/>
|
||||
<p className="text-foreground-light text-sm">
|
||||
The Table Editor now features tabs for improved navigation and organization. Have multiple
|
||||
tables opened across schemas and conveniently go across them without having to switch
|
||||
schemas. Collapse the sidebar for a bigger real estate while browsing your data.
|
||||
</p>
|
||||
<div className="space-y-2 !mt-4">
|
||||
<p className="text-sm">Enabling this preview will:</p>
|
||||
<ul className="list-disc pl-6 text-sm text-foreground-light space-y-1">
|
||||
<li>Enable opening of tables in the Table Editor as tabs</li>
|
||||
<li>Support closing of the navigation sidebar for a larger data grid space</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const TabsUpdateCallout = () => {
|
||||
const editor = useEditorType()
|
||||
const appSnap = useAppStateSnapshot()
|
||||
|
||||
const isTableEditorTabsEnabled = useIsTableEditorTabsEnabled()
|
||||
const isSQLEditorTabsEnabled = useIsSQLEditorTabsEnabled()
|
||||
const isTabsEnabled = isTableEditorTabsEnabled || isSQLEditorTabsEnabled
|
||||
|
||||
const [tableEditorTabsPreviewState] = useLocalStorageQuery(
|
||||
LOCAL_STORAGE_KEYS.UI_TABLE_EDITOR_TABS,
|
||||
''
|
||||
)
|
||||
const [sqlEditorTabsPreviewState] = useLocalStorageQuery(
|
||||
LOCAL_STORAGE_KEYS.UI_SQL_EDITOR_TABS,
|
||||
''
|
||||
)
|
||||
|
||||
const [tabsInterfaceAcknowledge, setTabsInterfaceAcknowledge] = useLocalStorageQuery(
|
||||
LOCAL_STORAGE_KEYS.TABS_INTERFACE_ACKNOWLEDGED,
|
||||
false
|
||||
)
|
||||
const isDefaultOptedInTabs =
|
||||
isTabsEnabled && tableEditorTabsPreviewState === '' && sqlEditorTabsPreviewState === ''
|
||||
|
||||
if (!isDefaultOptedInTabs || tabsInterfaceAcknowledge) return null
|
||||
|
||||
return (
|
||||
<Alert_Shadcn_ className="mb-4 relative">
|
||||
<AlertTitle_Shadcn_>
|
||||
<Badge variant="brand" className="mr-2">
|
||||
NEW
|
||||
</Badge>
|
||||
Tabs Interface for Editors
|
||||
</AlertTitle_Shadcn_>
|
||||
<AlertDescription_Shadcn_>
|
||||
The Table and SQL Editors now feature tabs for improved navigation and organization! Check
|
||||
out our{' '}
|
||||
<span
|
||||
className={cn(InlineLinkClassName, 'cursor-pointer')}
|
||||
onClick={() => {
|
||||
appSnap.setSelectedFeaturePreview(
|
||||
editor === 'table'
|
||||
? LOCAL_STORAGE_KEYS.UI_TABLE_EDITOR_TABS
|
||||
: LOCAL_STORAGE_KEYS.UI_SQL_EDITOR_TABS
|
||||
)
|
||||
appSnap.setShowFeaturePreviewModal(true)
|
||||
}}
|
||||
>
|
||||
feature previews
|
||||
</span>{' '}
|
||||
for more information.
|
||||
</AlertDescription_Shadcn_>
|
||||
<AlertDescription_Shadcn_ className="mt-4 flex items-center gap-x-2">
|
||||
<Button asChild type="default" icon={<ExternalLink />}>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
href="https://github.com/orgs/supabase/discussions/35636"
|
||||
>
|
||||
View announcement
|
||||
</a>
|
||||
</Button>
|
||||
</AlertDescription_Shadcn_>
|
||||
<ButtonTooltip
|
||||
type="text"
|
||||
icon={<X />}
|
||||
className="absolute top-2 right-2 px-1"
|
||||
onClick={() => setTabsInterfaceAcknowledge(true)}
|
||||
tooltip={{ content: { side: 'bottom', text: 'Dismiss' } }}
|
||||
/>
|
||||
</Alert_Shadcn_>
|
||||
)
|
||||
}
|
||||
|
||||
export const TabsUpdateTooltip = () => {
|
||||
const editor = useEditorType()
|
||||
const appSnap = useAppStateSnapshot()
|
||||
|
||||
const isTableEditorTabsEnabled = useIsTableEditorTabsEnabled()
|
||||
const isSQLEditorTabsEnabled = useIsSQLEditorTabsEnabled()
|
||||
const isTabsEnabled = isTableEditorTabsEnabled || isSQLEditorTabsEnabled
|
||||
|
||||
const [tableEditorTabsPreviewState] = useLocalStorageQuery(
|
||||
LOCAL_STORAGE_KEYS.UI_TABLE_EDITOR_TABS,
|
||||
''
|
||||
)
|
||||
const [sqlEditorTabsPreviewState] = useLocalStorageQuery(
|
||||
LOCAL_STORAGE_KEYS.UI_SQL_EDITOR_TABS,
|
||||
''
|
||||
)
|
||||
const [tabsInterfaceAcknowledge, setTabsInterfaceAcknowledge] = useLocalStorageQuery(
|
||||
LOCAL_STORAGE_KEYS.TABS_INTERFACE_ACKNOWLEDGED,
|
||||
false
|
||||
)
|
||||
|
||||
const isDefaultOptedInTabs =
|
||||
isTabsEnabled && tableEditorTabsPreviewState === '' && sqlEditorTabsPreviewState === ''
|
||||
|
||||
if (!isDefaultOptedInTabs || tabsInterfaceAcknowledge) return null
|
||||
|
||||
return (
|
||||
<HoverCard openDelay={150}>
|
||||
<HoverCardTrigger_Shadcn_ asChild>
|
||||
<div
|
||||
className={cn(
|
||||
'flex items-center justify-center px-2 h-10 shrink-0',
|
||||
'border-b border-b-default gap-x-2'
|
||||
)}
|
||||
>
|
||||
<Badge variant="brand" className="rounded">
|
||||
<span>NEW</span>
|
||||
</Badge>
|
||||
</div>
|
||||
</HoverCardTrigger_Shadcn_>
|
||||
<HoverCardContent_Shadcn_ className="p-3 w-72">
|
||||
<div className="flex flex-col gap-y-1">
|
||||
<p className="text-sm">Tabs Interface for Editors</p>
|
||||
<p className="text-xs text-foreground-light">
|
||||
The Table and SQL Editors now feature tabs for improved navigation and organization!
|
||||
Check out our{' '}
|
||||
<span
|
||||
className={cn(InlineLinkClassName, 'cursor-pointer')}
|
||||
onClick={() => {
|
||||
appSnap.setSelectedFeaturePreview(
|
||||
editor === 'table'
|
||||
? LOCAL_STORAGE_KEYS.UI_TABLE_EDITOR_TABS
|
||||
: LOCAL_STORAGE_KEYS.UI_SQL_EDITOR_TABS
|
||||
)
|
||||
appSnap.setShowFeaturePreviewModal(true)
|
||||
}}
|
||||
>
|
||||
feature previews
|
||||
</span>{' '}
|
||||
for more information.
|
||||
</p>
|
||||
</div>
|
||||
<Button type="default" className="mt-2" onClick={() => setTabsInterfaceAcknowledge(true)}>
|
||||
Dismiss
|
||||
</Button>
|
||||
</HoverCardContent_Shadcn_>
|
||||
</HoverCard>
|
||||
)
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { toast } from 'sonner'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useSqlTitleGenerateMutation } from 'data/ai/sql-title-mutation'
|
||||
import { useProjectSettingsV2Query } from 'data/config/project-settings-v2-query'
|
||||
import { getContentById } from 'data/content/content-id-query'
|
||||
import {
|
||||
UpsertContentPayload,
|
||||
@@ -11,12 +12,10 @@ import {
|
||||
import { Snippet } from 'data/content/sql-folders-query'
|
||||
import type { SqlSnippet } from 'data/content/sql-snippets-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useProjectSettingsV2Query } from 'data/config/project-settings-v2-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSqlEditorV2StateSnapshot } from 'state/sql-editor-v2'
|
||||
import { createTabId, useTabsStateSnapshot } from 'state/tabs'
|
||||
import { AiIconAnimation, Button, Form, Input, Modal } from 'ui'
|
||||
import { useIsSQLEditorTabsEnabled } from '../App/FeaturePreview/FeaturePreviewContext'
|
||||
import { subscriptionHasHipaaAddon } from '../Billing/Subscription/Subscription.utils'
|
||||
|
||||
export interface RenameQueryModalProps {
|
||||
@@ -42,7 +41,6 @@ const RenameQueryModal = ({
|
||||
{ enabled: visible }
|
||||
)
|
||||
const isSQLSnippet = snippet.type === 'sql'
|
||||
const isSQLEditorTabsEnabled = useIsSQLEditorTabsEnabled()
|
||||
const { data: projectSettings } = useProjectSettingsV2Query({ projectRef: ref })
|
||||
|
||||
// Customers on HIPAA plans should not have access to Supabase AI
|
||||
@@ -112,10 +110,8 @@ const RenameQueryModal = ({
|
||||
|
||||
snapV2.renameSnippet({ id, name: nameInput, description: descriptionInput })
|
||||
|
||||
if (isSQLEditorTabsEnabled && ref) {
|
||||
const tabId = createTabId('sql', { id })
|
||||
tabsSnap.updateTab(tabId, { label: nameInput })
|
||||
}
|
||||
const tabId = createTabId('sql', { id })
|
||||
tabsSnap.updateTab(tabId, { label: nameInput })
|
||||
|
||||
toast.success('Successfully renamed snippet!')
|
||||
if (onComplete) onComplete()
|
||||
|
||||
@@ -51,7 +51,6 @@ import {
|
||||
TooltipTrigger,
|
||||
cn,
|
||||
} from 'ui'
|
||||
import { useIsSQLEditorTabsEnabled } from '../App/FeaturePreview/FeaturePreviewContext'
|
||||
import { useSqlEditorDiff, useSqlEditorPrompt } from './hooks'
|
||||
import { RunQueryWarningModal } from './RunQueryWarningModal'
|
||||
import {
|
||||
@@ -95,7 +94,6 @@ export const SQLEditor = () => {
|
||||
const { isOptedInToAI, isHipaaProjectDisallowed } = useOrgOptedIntoAiAndHippaProject()
|
||||
const [selectedSchemas] = useSchemasForAi(project?.ref!)
|
||||
const includeSchemaMetadata = (isOptedInToAI && !isHipaaProjectDisallowed) || !IS_PLATFORM
|
||||
const isSQLEditorTabsEnabled = useIsSQLEditorTabsEnabled()
|
||||
|
||||
const {
|
||||
sourceSqlDiff,
|
||||
@@ -212,10 +210,8 @@ export const SQLEditor = () => {
|
||||
try {
|
||||
const { title: name } = await generateSqlTitle({ sql })
|
||||
snapV2.renameSnippet({ id, name })
|
||||
if (isSQLEditorTabsEnabled && ref) {
|
||||
const tabId = createTabId('sql', { id })
|
||||
tabs.updateTab(tabId, { label: name })
|
||||
}
|
||||
const tabId = createTabId('sql', { id })
|
||||
tabs.updateTab(tabId, { label: name })
|
||||
} catch (error) {
|
||||
// [Joshen] No error handler required as this happens in the background and not necessary to ping the user
|
||||
}
|
||||
|
||||
@@ -42,10 +42,7 @@ import {
|
||||
Sidebar as SidebarPrimitive,
|
||||
useSidebar,
|
||||
} from 'ui'
|
||||
import {
|
||||
useIsAPIDocsSidePanelEnabled,
|
||||
useIsSQLEditorTabsEnabled,
|
||||
} from './App/FeaturePreview/FeaturePreviewContext'
|
||||
import { useIsAPIDocsSidePanelEnabled } from './App/FeaturePreview/FeaturePreviewContext'
|
||||
|
||||
export const ICON_SIZE = 32
|
||||
export const ICON_STROKE_WIDTH = 1.5
|
||||
@@ -228,7 +225,6 @@ const ProjectLinks = () => {
|
||||
|
||||
const showWarehouse = useFlag('warehouse')
|
||||
const showUnifiedLogs = useFlag('unifiedLogs')
|
||||
const isSqlEditorTabsEnabled = useIsSQLEditorTabsEnabled()
|
||||
|
||||
const activeRoute = router.pathname.split('/')[3]
|
||||
|
||||
@@ -244,9 +240,7 @@ const ProjectLinks = () => {
|
||||
'realtime:all',
|
||||
])
|
||||
|
||||
const toolRoutes = generateToolRoutes(ref, project, {
|
||||
sqlEditorTabs: isSqlEditorTabsEnabled,
|
||||
})
|
||||
const toolRoutes = generateToolRoutes(ref, project)
|
||||
const productRoutes = generateProductRoutes(ref, project, {
|
||||
auth: authEnabled,
|
||||
edgeFunctions: edgeFunctionsEnabled,
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import ProductEmptyState from 'components/to-be-cleaned/ProductEmptyState'
|
||||
import { useEntityTypesQuery } from 'data/entity-types/entity-types-infinite-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useLocalStorage } from 'hooks/misc/useLocalStorage'
|
||||
import { useQuerySchemaState } from 'hooks/misc/useSchemaQueryState'
|
||||
import { PROTECTED_SCHEMAS } from 'lib/constants/schemas'
|
||||
import { useTableEditorStateSnapshot } from 'state/table-editor'
|
||||
|
||||
export interface EmptyStateProps {}
|
||||
|
||||
const EmptyState = ({}: EmptyStateProps) => {
|
||||
const snap = useTableEditorStateSnapshot()
|
||||
const { selectedSchema } = useQuerySchemaState()
|
||||
const isProtectedSchema = PROTECTED_SCHEMAS.includes(selectedSchema)
|
||||
const canCreateTables =
|
||||
useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_WRITE, 'tables') && !isProtectedSchema
|
||||
|
||||
const [sort] = useLocalStorage<'alphabetical' | 'grouped-alphabetical'>(
|
||||
'table-editor-sort',
|
||||
'alphabetical'
|
||||
)
|
||||
|
||||
const { project } = useProjectContext()
|
||||
const { data } = useEntityTypesQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
schemas: [selectedSchema],
|
||||
sort,
|
||||
})
|
||||
|
||||
const totalCount = data?.pages?.[0].data.count ?? 0
|
||||
|
||||
return (
|
||||
<div className="w-full h-full flex items-center justify-center">
|
||||
{totalCount === 0 ? (
|
||||
<ProductEmptyState
|
||||
title="Table Editor"
|
||||
ctaButtonLabel={canCreateTables ? 'Create a new table' : undefined}
|
||||
onClickCta={canCreateTables ? snap.onAddTable : undefined}
|
||||
>
|
||||
<p className="text-sm text-foreground-light">
|
||||
There are no tables available in this schema.
|
||||
</p>
|
||||
</ProductEmptyState>
|
||||
) : (
|
||||
<div className="flex flex-col items-center space-y-4">
|
||||
<ProductEmptyState
|
||||
title="Table Editor"
|
||||
ctaButtonLabel={canCreateTables ? 'Create a new table' : undefined}
|
||||
onClickCta={canCreateTables ? snap.onAddTable : undefined}
|
||||
>
|
||||
<p className="text-sm text-foreground-light">
|
||||
Select a table from the navigation panel on the left to view its data
|
||||
{canCreateTables && ', or create a new one.'}
|
||||
</p>
|
||||
</ProductEmptyState>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default EmptyState
|
||||
+2
-4
@@ -5,7 +5,6 @@ import { useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useIsTableEditorTabsEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useDatabasePublicationCreateMutation } from 'data/database-publications/database-publications-create-mutation'
|
||||
import { useDatabasePublicationsQuery } from 'data/database-publications/database-publications-query'
|
||||
@@ -21,6 +20,7 @@ import { tableRowKeys } from 'data/table-rows/keys'
|
||||
import { useTableRowCreateMutation } from 'data/table-rows/table-row-create-mutation'
|
||||
import { useTableRowUpdateMutation } from 'data/table-rows/table-row-update-mutation'
|
||||
import { tableKeys } from 'data/tables/keys'
|
||||
import { RetrieveTableResult } from 'data/tables/table-retrieve-query'
|
||||
import { getTables } from 'data/tables/tables-query'
|
||||
import { useUrlState } from 'hooks/ui/useUrlState'
|
||||
import { useGetImpersonatedRoleState } from 'state/role-impersonation-state'
|
||||
@@ -50,7 +50,6 @@ import {
|
||||
import SpreadsheetImport from './SpreadsheetImport/SpreadsheetImport'
|
||||
import TableEditor from './TableEditor/TableEditor'
|
||||
import type { ImportContent } from './TableEditor/TableEditor.types'
|
||||
import { RetrieveTableResult } from 'data/tables/table-retrieve-query'
|
||||
|
||||
export interface SidePanelEditorProps {
|
||||
editable?: boolean
|
||||
@@ -71,7 +70,6 @@ const SidePanelEditor = ({
|
||||
const { ref } = useParams()
|
||||
const snap = useTableEditorStateSnapshot()
|
||||
const tabsSnap = useTabsStateSnapshot()
|
||||
const isTableEditorTabsEnabled = useIsTableEditorTabsEnabled()
|
||||
const [_, setParams] = useUrlState({ arrayKeys: ['filter', 'sort'] })
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
@@ -493,7 +491,7 @@ const SidePanelEditor = ({
|
||||
`Table ${table.name} has been updated but there were some errors. Please check these errors separately.`
|
||||
)
|
||||
} else {
|
||||
if (isTableEditorTabsEnabled && ref && payload.name) {
|
||||
if (ref && payload.name) {
|
||||
// [Joshen] Only table entities can be updated via the dashboard
|
||||
const tabId = createTabId(ENTITY_TYPE.TABLE, { id: selectedTable.id })
|
||||
tabsSnap.updateTab(tabId, { label: payload.name })
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { isUndefined } from 'lodash'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
@@ -18,13 +18,11 @@ import { useQuerySchemaState } from 'hooks/misc/useSchemaQueryState'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { useUrlState } from 'hooks/ui/useUrlState'
|
||||
import { PROTECTED_SCHEMAS } from 'lib/constants/schemas'
|
||||
import Link from 'next/link'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
import { TableEditorTableStateContextProvider } from 'state/table-editor-table'
|
||||
import { createTabId, useTabsStateSnapshot } from 'state/tabs'
|
||||
import { Button } from 'ui'
|
||||
import { Admonition, GenericSkeletonLoader } from 'ui-patterns'
|
||||
import { useIsTableEditorTabsEnabled } from '../App/FeaturePreview/FeaturePreviewContext'
|
||||
import DeleteConfirmationDialogs from './DeleteConfirmationDialogs'
|
||||
import SidePanelEditor from './SidePanelEditor/SidePanelEditor'
|
||||
import TableDefinition from './TableDefinition'
|
||||
@@ -44,7 +42,6 @@ export const TableGridEditor = ({
|
||||
const { ref: projectRef, id } = useParams()
|
||||
|
||||
const tabs = useTabsStateSnapshot()
|
||||
const isTableEditorTabsEnabled = useIsTableEditorTabsEnabled()
|
||||
const { selectedSchema } = useQuerySchemaState()
|
||||
|
||||
useLoadTableEditorStateFromLocalStorageIntoUrl({
|
||||
@@ -65,9 +62,9 @@ export const TableGridEditor = ({
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
|
||||
const onClearDashboardHistory = () => {
|
||||
const onClearDashboardHistory = useCallback(() => {
|
||||
if (projectRef) appSnap.setDashboardHistory(projectRef, 'editor', undefined)
|
||||
}
|
||||
}, [appSnap, projectRef])
|
||||
|
||||
const onTableCreated = useCallback(
|
||||
(table: { id: number }) => {
|
||||
@@ -78,19 +75,12 @@ export const TableGridEditor = ({
|
||||
|
||||
const onTableDeleted = useCallback(async () => {
|
||||
// For simplicity for now, we just open the first table within the same schema
|
||||
if (isTableEditorTabsEnabled && selectedTable) {
|
||||
if (selectedTable) {
|
||||
// Close tab
|
||||
const tabId = createTabId(selectedTable.entity_type, { id: selectedTable.id })
|
||||
tabs.handleTabClose({ id: tabId, router, editor: 'table', onClearDashboardHistory })
|
||||
} else {
|
||||
const tables = await getTables(selectedSchema)
|
||||
if (tables.length > 0) {
|
||||
router.push(`/project/${projectRef}/editor/${tables[0].id}`)
|
||||
} else {
|
||||
router.push(`/project/${projectRef}/editor`)
|
||||
}
|
||||
}
|
||||
}, [getTables, isTableEditorTabsEnabled, projectRef, router, selectedSchema])
|
||||
}, [onClearDashboardHistory, router, selectedTable, tabs])
|
||||
|
||||
// NOTE: DO NOT PUT HOOKS AFTER THIS LINE
|
||||
if (isLoadingSelectedTable || !projectRef) {
|
||||
@@ -105,7 +95,7 @@ export const TableGridEditor = ({
|
||||
)
|
||||
}
|
||||
|
||||
if (isUndefined(selectedTable)) {
|
||||
if (!selectedTable) {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<div className="w-[400px]">
|
||||
@@ -114,45 +104,41 @@ export const TableGridEditor = ({
|
||||
title={`Unable to find your table with ID ${id}`}
|
||||
description="This table doesn't exist in your database"
|
||||
>
|
||||
{isTableEditorTabsEnabled && (
|
||||
<>
|
||||
{!!tabId ? (
|
||||
<Button
|
||||
type="default"
|
||||
className="mt-2"
|
||||
onClick={() => {
|
||||
tabs.handleTabClose({
|
||||
id: tabId,
|
||||
router,
|
||||
editor: 'table',
|
||||
onClearDashboardHistory,
|
||||
})
|
||||
}}
|
||||
>
|
||||
Close tab
|
||||
</Button>
|
||||
) : openTabs.length > 0 ? (
|
||||
<Button
|
||||
asChild
|
||||
type="default"
|
||||
className="mt-2"
|
||||
onClick={() => appSnap.setDashboardHistory(projectRef, 'editor', undefined)}
|
||||
>
|
||||
<Link href={`/project/${projectRef}/editor/${openTabs[0].split('-')[1]}`}>
|
||||
Close tab
|
||||
</Link>
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
asChild
|
||||
type="default"
|
||||
className="mt-2"
|
||||
onClick={() => appSnap.setDashboardHistory(projectRef, 'editor', undefined)}
|
||||
>
|
||||
<Link href={`/project/${projectRef}/editor`}>Head back</Link>
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
{!!tabId ? (
|
||||
<Button
|
||||
type="default"
|
||||
className="mt-2"
|
||||
onClick={() => {
|
||||
tabs.handleTabClose({
|
||||
id: tabId,
|
||||
router,
|
||||
editor: 'table',
|
||||
onClearDashboardHistory,
|
||||
})
|
||||
}}
|
||||
>
|
||||
Close tab
|
||||
</Button>
|
||||
) : openTabs.length > 0 ? (
|
||||
<Button
|
||||
asChild
|
||||
type="default"
|
||||
className="mt-2"
|
||||
onClick={() => appSnap.setDashboardHistory(projectRef, 'editor', undefined)}
|
||||
>
|
||||
<Link href={`/project/${projectRef}/editor/${openTabs[0].split('-')[1]}`}>
|
||||
Close tab
|
||||
</Link>
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
asChild
|
||||
type="default"
|
||||
className="mt-2"
|
||||
onClick={() => appSnap.setDashboardHistory(projectRef, 'editor', undefined)}
|
||||
>
|
||||
<Link href={`/project/${projectRef}/editor`}>Head back</Link>
|
||||
</Button>
|
||||
)}
|
||||
</Admonition>
|
||||
</div>
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
export { default as EmptyState } from './EmptyState'
|
||||
export { default as SidePanelEditor } from './SidePanelEditor/SidePanelEditor'
|
||||
@@ -19,12 +19,7 @@ import {
|
||||
} from 'icons'
|
||||
import { IS_PLATFORM, PROJECT_STATUS } from 'lib/constants'
|
||||
|
||||
export const generateToolRoutes = (
|
||||
ref?: string,
|
||||
project?: Project,
|
||||
features?: { sqlEditorTabs: boolean }
|
||||
): Route[] => {
|
||||
const { sqlEditorTabs } = features ?? {}
|
||||
export const generateToolRoutes = (ref?: string, project?: Project, features?: {}): Route[] => {
|
||||
const isProjectBuilding = project?.status === PROJECT_STATUS.COMING_UP
|
||||
const buildingUrl = `/project/${ref}`
|
||||
|
||||
@@ -42,8 +37,7 @@ export const generateToolRoutes = (
|
||||
icon: <SqlEditor size={ICON_SIZE} strokeWidth={ICON_STROKE_WIDTH} />,
|
||||
link: !IS_PLATFORM
|
||||
? `/project/${ref}/sql/1`
|
||||
: ref &&
|
||||
(isProjectBuilding ? buildingUrl : `/project/${ref}/sql${!!sqlEditorTabs ? '' : '/new'}`),
|
||||
: ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/sql`),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -4,10 +4,6 @@ import { useRouter } from 'next/router'
|
||||
import { forwardRef, Fragment, PropsWithChildren, ReactNode, useEffect, useState } from 'react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import {
|
||||
useIsSQLEditorTabsEnabled,
|
||||
useIsTableEditorTabsEnabled,
|
||||
} from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import ProjectAPIDocs from 'components/interfaces/ProjectAPIDocs/ProjectAPIDocs'
|
||||
import { AIAssistant } from 'components/ui/AIAssistantPanel/AIAssistant'
|
||||
import AISettingsModal from 'components/ui/AISettingsModal'
|
||||
@@ -101,14 +97,8 @@ const ProjectLayout = forwardRef<HTMLDivElement, PropsWithChildren<ProjectLayout
|
||||
} = useAppStateSnapshot()
|
||||
const aiSnap = useAiAssistantStateSnapshot()
|
||||
|
||||
const isTableEditorTabsEnabled = useIsTableEditorTabsEnabled()
|
||||
const isSQLEditorTabsEnabled = useIsSQLEditorTabsEnabled()
|
||||
|
||||
// For tabs preview flag logic - only conditionally collapse sidebar for table editor and sql editor if feature flags are on
|
||||
const editor = useEditorType()
|
||||
const tableEditorTabsEnabled = editor === 'table' && isTableEditorTabsEnabled
|
||||
const sqlEditorTabsEnabled = editor === 'sql' && isSQLEditorTabsEnabled
|
||||
const forceShowProductMenu = !tableEditorTabsEnabled && !sqlEditorTabsEnabled
|
||||
const forceShowProductMenu = editor === undefined
|
||||
const sideBarIsOpen = forceShowProductMenu || showSidebar
|
||||
|
||||
const projectName = selectedProject?.name
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { Eye, EyeOffIcon, Heart, Unlock } from 'lucide-react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import { useIsSQLEditorTabsEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import DownloadSnippetModal from 'components/interfaces/SQLEditor/DownloadSnippetModal'
|
||||
import { MoveQueryModal } from 'components/interfaces/SQLEditor/MoveQueryModal'
|
||||
import RenameQueryModal from 'components/interfaces/SQLEditor/RenameQueryModal'
|
||||
@@ -19,10 +23,6 @@ import { useLocalStorage } from 'hooks/misc/useLocalStorage'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { useProfile } from 'lib/profile'
|
||||
import uuidv4 from 'lib/uuid'
|
||||
import { Eye, EyeOffIcon, Heart, Unlock } from 'lucide-react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
import {
|
||||
SnippetWithContent,
|
||||
useSnippetFolders,
|
||||
@@ -59,7 +59,6 @@ export const SQLEditorNav = ({ sort = 'inserted_at' }: SQLEditorNavProps) => {
|
||||
const snapV2 = useSqlEditorV2StateSnapshot()
|
||||
|
||||
const tabs = useTabsStateSnapshot()
|
||||
const isSQLEditorTabsEnabled = useIsSQLEditorTabsEnabled()
|
||||
|
||||
const [sectionVisibility, setSectionVisibility] = useLocalStorage<SectionState>(
|
||||
LOCAL_STORAGE_KEYS.SQL_EDITOR_SECTION_STATE(projectRef ?? ''),
|
||||
@@ -293,12 +292,10 @@ export const SQLEditorNav = ({ sort = 'inserted_at' }: SQLEditorNavProps) => {
|
||||
|
||||
const { mutate: deleteContent, isLoading: isDeleting } = useContentDeleteMutation({
|
||||
onSuccess: (data) => {
|
||||
if (isSQLEditorTabsEnabled) {
|
||||
// Update Tabs state - currently unknown how to differentiate between sql and non-sql content
|
||||
// so we're just deleting all tabs for with matching IDs
|
||||
const tabIds = data.map((id) => createTabId('sql', { id }))
|
||||
tabs.removeTabs(tabIds)
|
||||
}
|
||||
// Update Tabs state - currently unknown how to differentiate between sql and non-sql content
|
||||
// so we're just deleting all tabs for with matching IDs
|
||||
const tabIds = data.map((id) => createTabId('sql', { id }))
|
||||
tabs.removeTabs(tabIds)
|
||||
},
|
||||
onError: (error, data) => {
|
||||
if (error.message.includes('Contents not found')) {
|
||||
@@ -541,10 +538,10 @@ export const SQLEditorNav = ({ sort = 'inserted_at' }: SQLEditorNavProps) => {
|
||||
|
||||
const sqlEditorTabsCleanup = useSqlEditorTabsCleanup()
|
||||
useEffect(() => {
|
||||
if (isSuccess && isSQLEditorTabsEnabled) {
|
||||
if (isSuccess) {
|
||||
sqlEditorTabsCleanup({ snippets: allSnippetsInView as any })
|
||||
}
|
||||
}, [allSnippetsInView, isSQLEditorTabsEnabled, isSuccess, sqlEditorTabsCleanup])
|
||||
}, [allSnippetsInView, isSuccess, sqlEditorTabsCleanup])
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -572,15 +569,13 @@ export const SQLEditorNav = ({ sort = 'inserted_at' }: SQLEditorNavProps) => {
|
||||
data={projectSnippetsTreeState}
|
||||
aria-label="project-level-snippets"
|
||||
nodeRenderer={({ element, ...props }) => {
|
||||
const isOpened =
|
||||
isSQLEditorTabsEnabled &&
|
||||
Object.values(tabs.tabsMap).some(
|
||||
(tab) => tab.metadata?.sqlId === element.metadata?.id
|
||||
)
|
||||
const isOpened = Object.values(tabs.tabsMap).some(
|
||||
(tab) => tab.metadata?.sqlId === element.metadata?.id
|
||||
)
|
||||
const tabId = createTabId('sql', {
|
||||
id: element?.metadata?.id as unknown as Snippet['id'],
|
||||
})
|
||||
const isPreview = isSQLEditorTabsEnabled && tabs.previewTabId === tabId
|
||||
const isPreview = tabs.previewTabId === tabId
|
||||
const isActive = !isPreview && element.metadata?.id === id
|
||||
const isSelected = selectedSnippets.some((x) => x.id === element.metadata?.id)
|
||||
|
||||
@@ -656,15 +651,13 @@ export const SQLEditorNav = ({ sort = 'inserted_at' }: SQLEditorNavProps) => {
|
||||
data={favoritesTreeState}
|
||||
aria-label="favorite-snippets"
|
||||
nodeRenderer={({ element, ...props }) => {
|
||||
const isOpened =
|
||||
isSQLEditorTabsEnabled &&
|
||||
Object.values(tabs.tabsMap).some(
|
||||
(tab) => tab.metadata?.sqlId === element.metadata?.id
|
||||
)
|
||||
const isOpened = Object.values(tabs.tabsMap).some(
|
||||
(tab) => tab.metadata?.sqlId === element.metadata?.id
|
||||
)
|
||||
const tabId = createTabId('sql', {
|
||||
id: element?.metadata?.id as unknown as Snippet['id'],
|
||||
})
|
||||
const isPreview = isSQLEditorTabsEnabled && tabs.previewTabId === tabId
|
||||
const isPreview = tabs.previewTabId === tabId
|
||||
const isActive = !isPreview && element.metadata?.id === id
|
||||
const isSelected = selectedSnippets.some((x) => x.id === element.metadata?.id)
|
||||
|
||||
@@ -746,15 +739,13 @@ export const SQLEditorNav = ({ sort = 'inserted_at' }: SQLEditorNavProps) => {
|
||||
}}
|
||||
expandedIds={expandedFolderIds}
|
||||
nodeRenderer={({ element, ...props }) => {
|
||||
const isOpened =
|
||||
isSQLEditorTabsEnabled &&
|
||||
Object.values(tabs.tabsMap).some(
|
||||
(tab) => tab.metadata?.sqlId === element.metadata?.id
|
||||
)
|
||||
const isOpened = Object.values(tabs.tabsMap).some(
|
||||
(tab) => tab.metadata?.sqlId === element.metadata?.id
|
||||
)
|
||||
const tabId = createTabId('sql', {
|
||||
id: element?.metadata?.id as unknown as Snippet['id'],
|
||||
})
|
||||
const isPreview = isSQLEditorTabsEnabled && tabs.previewTabId === tabId
|
||||
const isPreview = tabs.previewTabId === tabId
|
||||
const isActive = !isPreview && element.metadata?.id === id
|
||||
const isSelected = selectedSnippets.some((x) => x.id === element.metadata?.id)
|
||||
|
||||
|
||||
+2
-5
@@ -1,7 +1,6 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { IS_PLATFORM } from 'common'
|
||||
import { useParams } from 'common/hooks/useParams'
|
||||
import { useIsSQLEditorTabsEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import { useSQLSnippetFolderContentsQuery } from 'data/content/sql-folder-contents-query'
|
||||
import { Snippet } from 'data/content/sql-folders-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
@@ -83,7 +82,6 @@ export const SQLEditorTreeViewItem = ({
|
||||
const { profile } = useProfile()
|
||||
const { className, onClick } = getNodeProps()
|
||||
const snapV2 = useSqlEditorV2StateSnapshot()
|
||||
const isSQLEditorTabsEnabled = useIsSQLEditorTabsEnabled()
|
||||
|
||||
const isOwner = profile?.id === element?.metadata.owner_id
|
||||
const isSharedSnippet = element.metadata.visibility === 'project'
|
||||
@@ -262,13 +260,12 @@ export const SQLEditorTreeViewItem = ({
|
||||
<ContextMenuItem_Shadcn_
|
||||
asChild
|
||||
className="gap-x-2"
|
||||
onSelect={() => {}}
|
||||
onFocusCapture={(e) => e.stopPropagation()}
|
||||
>
|
||||
<Link
|
||||
href={`/project/${projectRef}/sql/${element.id}`}
|
||||
target={isSQLEditorTabsEnabled ? '_self' : '_blank'}
|
||||
target="_self"
|
||||
rel="noreferrer"
|
||||
href={`/project/${projectRef}/sql/${element.id}`}
|
||||
>
|
||||
<ExternalLink size={14} />
|
||||
Open in new tab
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
MAX_EXPORT_ROW_COUNT_MESSAGE,
|
||||
} from 'components/grid/components/header/Header'
|
||||
import { parseSupaTable } from 'components/grid/SupabaseGrid.utils'
|
||||
import { useIsTableEditorTabsEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import {
|
||||
formatTableRowsToSQL,
|
||||
getEntityLintDetails,
|
||||
@@ -70,11 +69,9 @@ const EntityListItem: ItemRenderer<Entity, EntityListItemProps> = ({
|
||||
const snap = useTableEditorStateSnapshot()
|
||||
const { selectedSchema } = useQuerySchemaState()
|
||||
|
||||
// For tabs preview flag logic
|
||||
const isTableEditorTabsEnabled = useIsTableEditorTabsEnabled()
|
||||
const tabId = createTabId(entity.type, { id: entity.id })
|
||||
const tabs = useTabsStateSnapshot()
|
||||
const isPreview = isTableEditorTabsEnabled ? tabs.previewTabId === tabId : false
|
||||
const isPreview = tabs.previewTabId === tabId
|
||||
|
||||
const isOpened = Object.values(tabs.tabsMap).some((tab) => tab.metadata?.tableId === entity.id)
|
||||
const isActive = Number(id) === entity.id
|
||||
|
||||
@@ -5,7 +5,6 @@ import { useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useBreakpoint } from 'common/hooks/useBreakpoint'
|
||||
import { useIsTableEditorTabsEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import { ProtectedSchemaModal } from 'components/interfaces/Database/ProtectedSchemaWarning'
|
||||
import EditorMenuListSkeleton from 'components/layouts/TableEditorLayout/EditorMenuListSkeleton'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
@@ -45,11 +44,10 @@ import EntityListItem from './EntityListItem'
|
||||
import { TableMenuEmptyState } from './TableMenuEmptyState'
|
||||
|
||||
const TableEditorMenu = () => {
|
||||
const { ref, id: _id } = useParams()
|
||||
const { id: _id } = useParams()
|
||||
const id = _id ? Number(_id) : undefined
|
||||
const snap = useTableEditorStateSnapshot()
|
||||
const { selectedSchema, setSelectedSchema } = useQuerySchemaState()
|
||||
const isTableEditorTabsEnabled = useIsTableEditorTabsEnabled()
|
||||
const isMobile = useBreakpoint()
|
||||
|
||||
const [showModal, setShowModal] = useState(false)
|
||||
@@ -118,10 +116,10 @@ const TableEditorMenu = () => {
|
||||
const tableEditorTabsCleanUp = useTableEditorTabsCleanUp()
|
||||
useEffect(() => {
|
||||
// Clean up tabs + recent items for any tables that might have been removed outside of the dashboard session
|
||||
if (isTableEditorTabsEnabled && entityTypes && !searchText) {
|
||||
if (entityTypes && !searchText) {
|
||||
tableEditorTabsCleanUp({ schemas: [selectedSchema], entities: entityTypes })
|
||||
}
|
||||
}, [entityTypes, isTableEditorTabsEnabled, searchText, selectedSchema, tableEditorTabsCleanUp])
|
||||
}, [entityTypes, searchText, selectedSchema, tableEditorTabsCleanUp])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -6,7 +6,6 @@ import { useRouter } from 'next/router'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { TabsUpdateCallout } from 'components/interfaces/App/FeaturePreview/TableEditorTabs'
|
||||
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'
|
||||
@@ -114,7 +113,6 @@ export function NewTab() {
|
||||
return (
|
||||
<div className="bg-surface-100 h-full overflow-y-auto py-12">
|
||||
<div className="mx-auto max-w-2xl flex flex-col gap-10 px-10">
|
||||
<TabsUpdateCallout />
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{actions.map((item, i) => (
|
||||
<ActionCard key={`action-card-${i}`} {...item} />
|
||||
|
||||
@@ -12,7 +12,6 @@ import { Plus, X } from 'lucide-react'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { TabsUpdateTooltip } from 'components/interfaces/App/FeaturePreview/TableEditorTabs'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
import { editorEntityTypes, useTabsStateSnapshot, type Tab } from 'state/tabs'
|
||||
import {
|
||||
@@ -173,43 +172,41 @@ export const EditorTabs = () => {
|
||||
|
||||
{/* Non-draggable new tab */}
|
||||
{hasNewTab && (
|
||||
<>
|
||||
<TabsTrigger_Shadcn_
|
||||
value="new"
|
||||
className={cn(
|
||||
'flex items-center gap-2 px-3 text-xs',
|
||||
'bg-dash-sidebar/50 dark:bg-surface-100/50',
|
||||
'data-[state=active]:bg-dash-sidebar dark:data-[state=active]:bg-surface-100',
|
||||
'relative group h-full border-t-2 !border-b-0',
|
||||
'hover:bg-surface-300 dark:hover:bg-surface-100'
|
||||
)}
|
||||
<TabsTrigger_Shadcn_
|
||||
value="new"
|
||||
className={cn(
|
||||
'flex items-center gap-2 px-3 text-xs',
|
||||
'bg-dash-sidebar/50 dark:bg-surface-100/50',
|
||||
'data-[state=active]:bg-dash-sidebar dark:data-[state=active]:bg-surface-100',
|
||||
'relative group h-full border-t-2 !border-b-0',
|
||||
'hover:bg-surface-300 dark:hover:bg-surface-100'
|
||||
)}
|
||||
>
|
||||
<Plus size={16} strokeWidth={1.5} className={'text-foreground-lighter'} />
|
||||
<div className="flex items-center gap-0">
|
||||
<span>New</span>
|
||||
</div>
|
||||
<span
|
||||
role="button"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
}}
|
||||
className="ml-1 opacity-0 group-hover:opacity-100 hover:bg-200 rounded-sm cursor-pointer"
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
}}
|
||||
onPointerDown={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
handleClose('new')
|
||||
}}
|
||||
>
|
||||
<Plus size={16} strokeWidth={1.5} className={'text-foreground-lighter'} />
|
||||
<div className="flex items-center gap-0">
|
||||
<span>New</span>
|
||||
</div>
|
||||
<span
|
||||
role="button"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
}}
|
||||
className="ml-1 opacity-0 group-hover:opacity-100 hover:bg-200 rounded-sm cursor-pointer"
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
}}
|
||||
onPointerDown={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
handleClose('new')
|
||||
}}
|
||||
>
|
||||
<X size={12} className="text-foreground-light" />
|
||||
</span>{' '}
|
||||
<div className="absolute w-full -bottom-[1px] left-0 right-0 h-px bg-dash-sidebar dark:bg-surface-100 opacity-0 group-data-[state=active]:opacity-100" />
|
||||
</TabsTrigger_Shadcn_>
|
||||
</>
|
||||
<X size={12} className="text-foreground-light" />
|
||||
</span>{' '}
|
||||
<div className="absolute w-full -bottom-[1px] left-0 right-0 h-px bg-dash-sidebar dark:bg-surface-100 opacity-0 group-data-[state=active]:opacity-100" />
|
||||
</TabsTrigger_Shadcn_>
|
||||
)}
|
||||
|
||||
<AnimatePresence initial={false}>
|
||||
@@ -235,8 +232,6 @@ export const EditorTabs = () => {
|
||||
</AnimatePresence>
|
||||
<div className="grow h-full border-b pr-6" />
|
||||
</TabsList_Shadcn_>
|
||||
|
||||
<TabsUpdateTooltip />
|
||||
</Tabs_Shadcn_>
|
||||
|
||||
<DragOverlay dropAnimation={null}>
|
||||
|
||||
@@ -2,10 +2,6 @@ import { usePathname } from 'next/navigation'
|
||||
import { ComponentProps, ReactNode } from 'react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import {
|
||||
useIsSQLEditorTabsEnabled,
|
||||
useIsTableEditorTabsEnabled,
|
||||
} from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import { useTabsStateSnapshot } from 'state/tabs'
|
||||
import { cn } from 'ui'
|
||||
import { ProjectLayoutWithAuth } from '../ProjectLayout/ProjectLayout'
|
||||
@@ -26,12 +22,6 @@ export const EditorBaseLayout = ({ children, title, product, ...props }: Explore
|
||||
const editor = useEditorType()
|
||||
const tabs = useTabsStateSnapshot()
|
||||
|
||||
const isTableEditorTabsEnabled = useIsTableEditorTabsEnabled()
|
||||
const isSQLEditorTabsEnabled = useIsSQLEditorTabsEnabled()
|
||||
|
||||
const tableEditorTabsEnabled = editor === 'table' && isTableEditorTabsEnabled
|
||||
const sqlEditorTabsEnabled = editor === 'sql' && isSQLEditorTabsEnabled
|
||||
|
||||
const hasNoOpenTabs =
|
||||
editor === 'table' ? tabs.openTabs.filter((x) => !x.startsWith('sql')).length === 0 : false
|
||||
const hideTabs =
|
||||
@@ -40,16 +30,14 @@ export const EditorBaseLayout = ({ children, title, product, ...props }: Explore
|
||||
return (
|
||||
<ProjectLayoutWithAuth resizableSidebar title={title} product={product} {...props}>
|
||||
<div className="flex flex-col h-full">
|
||||
{tableEditorTabsEnabled || sqlEditorTabsEnabled ? (
|
||||
<div
|
||||
className={cn(
|
||||
'h-10 flex items-center',
|
||||
!hideTabs ? 'bg-surface-200 dark:bg-alternative' : 'bg-surface-100'
|
||||
)}
|
||||
>
|
||||
{hideTabs ? <CollapseButton hideTabs={hideTabs} /> : <EditorTabs />}
|
||||
</div>
|
||||
) : null}
|
||||
<div
|
||||
className={cn(
|
||||
'h-10 flex items-center',
|
||||
!hideTabs ? 'bg-surface-200 dark:bg-alternative' : 'bg-surface-100'
|
||||
)}
|
||||
>
|
||||
{hideTabs ? <CollapseButton hideTabs={hideTabs} /> : <EditorTabs />}
|
||||
</div>
|
||||
<div className="h-full">{children}</div>
|
||||
</div>
|
||||
</ProjectLayoutWithAuth>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useIsTableEditorTabsEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import { TableGridEditor } from 'components/interfaces/TableGridEditor/TableGridEditor'
|
||||
import DefaultLayout from 'components/layouts/DefaultLayout'
|
||||
import { EditorBaseLayout } from 'components/layouts/editors/EditorBaseLayout'
|
||||
@@ -30,11 +29,9 @@ const TableEditorPage: NextPageWithLayout = () => {
|
||||
* - selectedTable changes (when a new table is loaded)
|
||||
* - id changes (when URL parameter changes)
|
||||
*/
|
||||
const isTableEditorTabsEnabled = useIsTableEditorTabsEnabled()
|
||||
|
||||
useEffect(() => {
|
||||
// tabs preview flag logic
|
||||
if (isTableEditorTabsEnabled && selectedTable && projectRef) {
|
||||
if (selectedTable && projectRef) {
|
||||
const tabId = createTabId(selectedTable.entity_type, { id: selectedTable.id })
|
||||
if (!store.tabsMap[tabId]) {
|
||||
store.addTab({
|
||||
@@ -52,7 +49,7 @@ const TableEditorPage: NextPageWithLayout = () => {
|
||||
store.makeTabActive(tabId)
|
||||
}
|
||||
}
|
||||
}, [selectedTable, id, projectRef, isTableEditorTabsEnabled])
|
||||
}, [selectedTable, id, projectRef])
|
||||
|
||||
return <TableGridEditor isLoadingSelectedTable={isLoading} selectedTable={selectedTable} />
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useIsTableEditorTabsEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import EmptyState from 'components/interfaces/TableGridEditor/EmptyState'
|
||||
import SidePanelEditor from 'components/interfaces/TableGridEditor/SidePanelEditor/SidePanelEditor'
|
||||
import DefaultLayout from 'components/layouts/DefaultLayout'
|
||||
import { EditorBaseLayout } from 'components/layouts/editors/EditorBaseLayout'
|
||||
import TableEditorLayout from 'components/layouts/TableEditorLayout/TableEditorLayout'
|
||||
import TableEditorMenu from 'components/layouts/TableEditorLayout/TableEditorMenu'
|
||||
import { NewTab } from 'components/layouts/Tabs/NewTab'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
import { editorEntityTypes, useTabsStateSnapshot } from 'state/tabs'
|
||||
import type { NextPageWithLayout } from 'types'
|
||||
@@ -18,7 +17,6 @@ const TableEditorPage: NextPageWithLayout = () => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const tabStore = useTabsStateSnapshot()
|
||||
const appSnap = useAppStateSnapshot()
|
||||
const isTableEditorTabsEnabled = useIsTableEditorTabsEnabled()
|
||||
|
||||
const onTableCreated = (table: { id: number }) => {
|
||||
router.push(`/project/${projectRef}/editor/${table.id}`)
|
||||
@@ -26,25 +24,22 @@ const TableEditorPage: NextPageWithLayout = () => {
|
||||
|
||||
useEffect(() => {
|
||||
const lastOpenedTab = appSnap.dashboardHistory.editor
|
||||
if (isTableEditorTabsEnabled) {
|
||||
const lastTabId = tabStore.openTabs.find((id) =>
|
||||
editorEntityTypes.table.includes(tabStore.tabsMap[id]?.type)
|
||||
)
|
||||
if (lastOpenedTab !== undefined) {
|
||||
router.push(`/project/${projectRef}/editor/${appSnap.dashboardHistory.editor}`)
|
||||
} else if (lastTabId) {
|
||||
// Handle redirect to last opened table tab, or last table tab
|
||||
const lastTab = tabStore.tabsMap[lastTabId]
|
||||
if (lastTab) router.push(`/project/${projectRef}/editor/${lastTab.metadata?.tableId}`)
|
||||
}
|
||||
} else if (lastOpenedTab) {
|
||||
|
||||
const lastTabId = tabStore.openTabs.find((id) =>
|
||||
editorEntityTypes.table.includes(tabStore.tabsMap[id]?.type)
|
||||
)
|
||||
if (lastOpenedTab !== undefined) {
|
||||
router.push(`/project/${projectRef}/editor/${appSnap.dashboardHistory.editor}`)
|
||||
} else if (lastTabId) {
|
||||
// Handle redirect to last opened table tab, or last table tab
|
||||
const lastTab = tabStore.tabsMap[lastTabId]
|
||||
if (lastTab) router.push(`/project/${projectRef}/editor/${lastTab.metadata?.tableId}`)
|
||||
}
|
||||
}, [isTableEditorTabsEnabled])
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
{isTableEditorTabsEnabled ? <NewTab /> : <EmptyState />}
|
||||
<NewTab />
|
||||
<SidePanelEditor onTableCreated={onTableCreated} />
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import { useParams } from 'common/hooks/useParams'
|
||||
import { useIsSQLEditorTabsEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import { SQLEditor } from 'components/interfaces/SQLEditor/SQLEditor'
|
||||
import DefaultLayout from 'components/layouts/DefaultLayout'
|
||||
import { EditorBaseLayout } from 'components/layouts/editors/EditorBaseLayout'
|
||||
@@ -26,7 +25,6 @@ const SqlEditor: NextPageWithLayout = () => {
|
||||
const tabs = useTabsStateSnapshot()
|
||||
const appSnap = useAppStateSnapshot()
|
||||
const snapV2 = useSqlEditorV2StateSnapshot()
|
||||
const isSqlEditorTabsEnabled = useIsSQLEditorTabsEnabled()
|
||||
|
||||
const allSnippets = useSnippets(ref!)
|
||||
const snippet = allSnippets.find((x) => x.id === id)
|
||||
@@ -72,23 +70,21 @@ const SqlEditor: NextPageWithLayout = () => {
|
||||
|
||||
// Watch for route changes
|
||||
useEffect(() => {
|
||||
if (isSqlEditorTabsEnabled) {
|
||||
if (!router.isReady || !id || id === 'new') return
|
||||
if (!router.isReady || !id || id === 'new') return
|
||||
|
||||
const tabId = createTabId('sql', { id })
|
||||
const snippet = allSnippets.find((x) => x.id === id)
|
||||
const tabId = createTabId('sql', { id })
|
||||
const snippet = allSnippets.find((x) => x.id === id)
|
||||
|
||||
tabs.addTab({
|
||||
id: tabId,
|
||||
type: 'sql',
|
||||
label: snippet?.name || 'Untitled Query',
|
||||
metadata: {
|
||||
sqlId: id,
|
||||
name: snippet?.name,
|
||||
},
|
||||
})
|
||||
}
|
||||
}, [router.isReady, id, isSqlEditorTabsEnabled])
|
||||
tabs.addTab({
|
||||
id: tabId,
|
||||
type: 'sql',
|
||||
label: snippet?.name || 'Untitled Query',
|
||||
metadata: {
|
||||
sqlId: id,
|
||||
name: snippet?.name,
|
||||
},
|
||||
})
|
||||
}, [router.isReady, id])
|
||||
|
||||
if (snippetMissing || invalidId) {
|
||||
return (
|
||||
@@ -99,31 +95,27 @@ const SqlEditor: NextPageWithLayout = () => {
|
||||
title={`Unable to find snippet with ID ${id}`}
|
||||
description="This snippet doesn't exist in your project"
|
||||
>
|
||||
{isSqlEditorTabsEnabled && (
|
||||
<>
|
||||
{!!tabId ? (
|
||||
<Button
|
||||
type="default"
|
||||
className="mt-2"
|
||||
onClick={() => {
|
||||
tabs.handleTabClose({
|
||||
id: tabId,
|
||||
router,
|
||||
editor,
|
||||
onClearDashboardHistory: () => {
|
||||
if (ref) appSnap.setDashboardHistory(ref, 'sql', undefined)
|
||||
},
|
||||
})
|
||||
}}
|
||||
>
|
||||
Close tab
|
||||
</Button>
|
||||
) : (
|
||||
<Button asChild type="default" className="mt-2">
|
||||
<Link href={`/project/${ref}/sql`}>Head back</Link>
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
{!!tabId ? (
|
||||
<Button
|
||||
type="default"
|
||||
className="mt-2"
|
||||
onClick={() => {
|
||||
tabs.handleTabClose({
|
||||
id: tabId,
|
||||
router,
|
||||
editor,
|
||||
onClearDashboardHistory: () => {
|
||||
if (ref) appSnap.setDashboardHistory(ref, 'sql', undefined)
|
||||
},
|
||||
})
|
||||
}}
|
||||
>
|
||||
Close tab
|
||||
</Button>
|
||||
) : (
|
||||
<Button asChild type="default" className="mt-2">
|
||||
<Link href={`/project/${ref}/sql`}>Head back</Link>
|
||||
</Button>
|
||||
)}
|
||||
</Admonition>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useIsSQLEditorTabsEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import DefaultLayout from 'components/layouts/DefaultLayout'
|
||||
import { EditorBaseLayout } from 'components/layouts/editors/EditorBaseLayout'
|
||||
import SQLEditorLayout from 'components/layouts/SQLEditorLayout/SQLEditorLayout'
|
||||
import { SQLEditorMenu } from 'components/layouts/SQLEditorLayout/SQLEditorMenu'
|
||||
import { NewTab } from 'components/layouts/Tabs/NewTab'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
import { useTabsStateSnapshot } from 'state/tabs'
|
||||
import type { NextPageWithLayout } from 'types'
|
||||
@@ -16,26 +16,20 @@ const TableEditorPage: NextPageWithLayout = () => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const store = useTabsStateSnapshot()
|
||||
const appSnap = useAppStateSnapshot()
|
||||
const isSqlEditorTabsEnabled = useIsSQLEditorTabsEnabled()
|
||||
|
||||
useEffect(() => {
|
||||
if (!isSqlEditorTabsEnabled) {
|
||||
// Redirect to /new if not using tabs
|
||||
router.push(`/project/${projectRef}/sql/new`)
|
||||
} else {
|
||||
// Handle redirect to last opened snippet tab, or last snippet tab
|
||||
const lastOpenedTab = appSnap.dashboardHistory.sql
|
||||
const lastTabId = store.openTabs.find((id) => store.tabsMap[id]?.type === 'sql')
|
||||
if (lastOpenedTab !== undefined) {
|
||||
router.push(`/project/${projectRef}/sql/${appSnap.dashboardHistory.sql}`)
|
||||
} else if (lastTabId) {
|
||||
const lastTab = store.tabsMap[lastTabId]
|
||||
if (lastTab) router.push(`/project/${projectRef}/sql/${lastTab.id.replace('sql-', '')}`)
|
||||
}
|
||||
// Handle redirect to last opened snippet tab, or last snippet tab
|
||||
const lastOpenedTab = appSnap.dashboardHistory.sql
|
||||
const lastTabId = store.openTabs.find((id) => store.tabsMap[id]?.type === 'sql')
|
||||
if (lastOpenedTab !== undefined) {
|
||||
router.push(`/project/${projectRef}/sql/${appSnap.dashboardHistory.sql}`)
|
||||
} else if (lastTabId) {
|
||||
const lastTab = store.tabsMap[lastTabId]
|
||||
if (lastTab) router.push(`/project/${projectRef}/sql/${lastTab.id.replace('sql-', '')}`)
|
||||
}
|
||||
}, [isSqlEditorTabsEnabled])
|
||||
}, [])
|
||||
|
||||
return isSqlEditorTabsEnabled ? <NewTab /> : null
|
||||
return <NewTab />
|
||||
}
|
||||
|
||||
TableEditorPage.getLayout = (page) => (
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useParams } from 'next/navigation'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import { useIsSQLEditorTabsEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import SQLQuickstarts from 'components/interfaces/SQLEditor/SQLTemplates/SQLQuickstarts'
|
||||
import DefaultLayout from 'components/layouts/DefaultLayout'
|
||||
import { EditorBaseLayout } from 'components/layouts/editors/EditorBaseLayout'
|
||||
@@ -16,25 +15,20 @@ const SqlQuickstarts: NextPageWithLayout = () => {
|
||||
const { ref } = useParams<{ ref: string }>()
|
||||
const tabs = useTabsStateSnapshot()
|
||||
|
||||
const isSqlEditorTabsEnabled = useIsSQLEditorTabsEnabled()
|
||||
|
||||
useEffect(() => {
|
||||
if (isSqlEditorTabsEnabled) {
|
||||
if (!router.isReady) return
|
||||
if (!router.isReady) return
|
||||
|
||||
const tabId = createTabId('sql', { id: 'quickstarts' })
|
||||
|
||||
tabs.addTab({
|
||||
id: tabId,
|
||||
type: 'sql',
|
||||
label: 'Quickstarts',
|
||||
metadata: {
|
||||
sqlId: 'quickstarts',
|
||||
name: 'quickstarts',
|
||||
},
|
||||
})
|
||||
}
|
||||
}, [router.isReady, isSqlEditorTabsEnabled, ref])
|
||||
const tabId = createTabId('sql', { id: 'quickstarts' })
|
||||
tabs.addTab({
|
||||
id: tabId,
|
||||
type: 'sql',
|
||||
label: 'Quickstarts',
|
||||
metadata: {
|
||||
sqlId: 'quickstarts',
|
||||
name: 'quickstarts',
|
||||
},
|
||||
})
|
||||
}, [router.isReady, ref])
|
||||
|
||||
return <SQLQuickstarts />
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useParams } from 'next/navigation'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import { useIsSQLEditorTabsEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import SQLTemplates from 'components/interfaces/SQLEditor/SQLTemplates/SQLTemplates'
|
||||
import DefaultLayout from 'components/layouts/DefaultLayout'
|
||||
import { EditorBaseLayout } from 'components/layouts/editors/EditorBaseLayout'
|
||||
@@ -16,25 +15,20 @@ const SqlTemplates: NextPageWithLayout = () => {
|
||||
const { ref } = useParams<{ ref: string }>()
|
||||
const tabs = useTabsStateSnapshot()
|
||||
|
||||
const isSqlEditorTabsEnabled = useIsSQLEditorTabsEnabled()
|
||||
|
||||
useEffect(() => {
|
||||
if (isSqlEditorTabsEnabled) {
|
||||
if (!router.isReady) return
|
||||
if (!router.isReady) return
|
||||
|
||||
const tabId = createTabId('sql', { id: 'templates' })
|
||||
|
||||
tabs.addTab({
|
||||
id: tabId,
|
||||
type: 'sql',
|
||||
label: 'Templates',
|
||||
metadata: {
|
||||
sqlId: 'templates',
|
||||
name: 'templates',
|
||||
},
|
||||
})
|
||||
}
|
||||
}, [router.isReady, isSqlEditorTabsEnabled, ref])
|
||||
const tabId = createTabId('sql', { id: 'templates' })
|
||||
tabs.addTab({
|
||||
id: tabId,
|
||||
type: 'sql',
|
||||
label: 'Templates',
|
||||
metadata: {
|
||||
sqlId: 'templates',
|
||||
name: 'templates',
|
||||
},
|
||||
})
|
||||
}, [router.isReady, ref])
|
||||
|
||||
return <SQLTemplates />
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { expect } from '@playwright/test'
|
||||
import { env } from '../env.config'
|
||||
import { test } from '../utils/test'
|
||||
import { toUrl } from '../utils/to-url'
|
||||
import { env } from '../env.config'
|
||||
|
||||
test.describe('SQL Editor', () => {
|
||||
test('should check if SQL editor can run simple commands', async ({ page }) => {
|
||||
await page.goto(toUrl(`/project/${env.PROJECT_REF}/sql`))
|
||||
await page.goto(toUrl(`/project/${env.PROJECT_REF}/sql/new?skip=true`))
|
||||
|
||||
const editor = page.getByRole('code').nth(0)
|
||||
|
||||
|
||||
Reference in new issue
Block a user