From 581ae071201724c9e9fe596d0247b876a6a0884b Mon Sep 17 00:00:00 2001 From: Ivan Vasilov Date: Wed, 10 Dec 2025 19:12:15 +0200 Subject: [PATCH] fix: Hide favourites and share snippets on self-hosted variant (#41227) * Hide favorite and share actions for self-hosted version. * Rename the query on save only on platform. * Simplify useCheckOpenAiKeyQuery. * Rename with AI now depends if the OPENAI_API_KEY is set. * Minor fixes. * Fix the tests to use .skip for skipping tests. Remove extra port params. * Make the test for favourites work only on platform variant. --- .../interfaces/SQLEditor/RenameQueryModal.tsx | 20 +- .../interfaces/SQLEditor/SQLEditor.tsx | 10 +- .../SQLEditor/UtilityPanel/UtilityActions.tsx | 38 ++- .../SQLEditorNavV2/SQLEditorNav.tsx | 310 +++++++++--------- .../SQLEditorNavV2/SQLEditorTreeViewItem.tsx | 51 +-- .../ui/AIAssistantPanel/AIAssistant.tsx | 2 +- apps/studio/data/ai/check-api-key-query.ts | 6 +- .../data/content/content-upsert-mutation.ts | 3 +- apps/studio/pages/project/[ref]/sql/index.tsx | 5 +- apps/studio/state/tabs.tsx | 3 + e2e/studio/features/sql-editor.spec.ts | 111 +++---- package.json | 4 +- 12 files changed, 297 insertions(+), 266 deletions(-) diff --git a/apps/studio/components/interfaces/SQLEditor/RenameQueryModal.tsx b/apps/studio/components/interfaces/SQLEditor/RenameQueryModal.tsx index 60f4fafec62..c1f7675a84a 100644 --- a/apps/studio/components/interfaces/SQLEditor/RenameQueryModal.tsx +++ b/apps/studio/components/interfaces/SQLEditor/RenameQueryModal.tsx @@ -2,6 +2,8 @@ import { useEffect, useState } from 'react' import { toast } from 'sonner' import { useParams } from 'common' +import { ButtonTooltip } from 'components/ui/ButtonTooltip' +import { useCheckOpenAIKeyQuery } from 'data/ai/check-api-key-query' 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' @@ -13,6 +15,7 @@ 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 { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization' +import { useRouter } from 'next/router' import { useSqlEditorV2StateSnapshot } from 'state/sql-editor-v2' import { createTabId, useTabsStateSnapshot } from 'state/tabs' import { AiIconAnimation, Button, Form, Input, Modal } from 'ui' @@ -32,6 +35,7 @@ const RenameQueryModal = ({ onComplete, }: RenameQueryModalProps) => { const { ref } = useParams() + const router = useRouter() const { data: organization } = useSelectedOrganizationQuery() const snapV2 = useSqlEditorV2StateSnapshot() @@ -61,6 +65,8 @@ const RenameQueryModal = ({ toast.error(`Failed to rename query: ${error.message}`) }, }) + const { data: check } = useCheckOpenAIKeyQuery() + const isApiKeySet = !!check?.hasKey const generateTitle = async () => { if ('content' in snippet && isSQLSnippet) { @@ -149,11 +155,19 @@ const RenameQueryModal = ({ />
{!hasHipaaAddon && ( - + )}
{ return } - if (!isHipaaProjectDisallowed && snippet?.snippet.name === untitledSnippetTitle) { + if ( + !isHipaaProjectDisallowed && + snippet?.snippet.name.startsWith(untitledSnippetTitle) && + IS_PLATFORM + ) { // Intentionally don't await title gen (lazy) setAiTitle(id, sql) } diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityActions.tsx b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityActions.tsx index 1de2e9d886e..aaa9cdcd4c1 100644 --- a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityActions.tsx +++ b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityActions.tsx @@ -92,23 +92,27 @@ const UtilityActions = ({ {intellisenseEnabled && } - - { - if (isFavorite) removeFavorite() - else addFavorite() - }} - > - - {isFavorite ? 'Remove from' : 'Add to'} favorites - + {IS_PLATFORM && ( + <> + + { + if (isFavorite) removeFavorite() + else addFavorite() + }} + > + + {isFavorite ? 'Remove from' : 'Add to'} favorites + + + )} Prettify SQL diff --git a/apps/studio/components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorNav.tsx b/apps/studio/components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorNav.tsx index 25e3866604d..5eab1c04aaf 100644 --- a/apps/studio/components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorNav.tsx +++ b/apps/studio/components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorNav.tsx @@ -1,10 +1,10 @@ +import { keepPreviousData } from '@tanstack/react-query' import { Heart } from 'lucide-react' import { useRouter } from 'next/router' import { useEffect, useMemo, useState } from 'react' import { toast } from 'sonner' -import { keepPreviousData } from '@tanstack/react-query' -import { LOCAL_STORAGE_KEYS, useParams } from 'common' +import { IS_PLATFORM, LOCAL_STORAGE_KEYS, useParams } from 'common' import DownloadSnippetModal from 'components/interfaces/SQLEditor/DownloadSnippetModal' import { MoveQueryModal } from 'components/interfaces/SQLEditor/MoveQueryModal' import RenameQueryModal from 'components/interfaces/SQLEditor/RenameQueryModal' @@ -440,160 +440,168 @@ export const SQLEditorNav = ({ sort = 'inserted_at' }: SQLEditorNavProps) => { return ( <> - - { - setSectionVisibility({ ...(sectionVisibility ?? DEFAULT_SECTION_STATE), shared: value }) - }} - > - 0 ? ` (${numProjectSnippets})` : ''}`} - /> - - {isLoadingSharedSqlSnippets ? ( - - ) : sharedSnippets.length === 0 ? ( - + { + setSectionVisibility({ + ...(sectionVisibility ?? DEFAULT_SECTION_STATE), + shared: value, + }) + }} + > + 0 ? ` (${numProjectSnippets})` : ''}`} /> - ) : ( - { - 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 = tabs.previewTabId === tabId - const isActive = !isPreview && element.metadata?.id === id - const isSelected = selectedSnippets.some((x) => x.id === element.metadata?.id) + + {isLoadingSharedSqlSnippets ? ( + + ) : sharedSnippets.length === 0 ? ( + + ) : ( + { + 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 = tabs.previewTabId === tabId + const isActive = !isPreview && element.metadata?.id === id + const isSelected = selectedSnippets.some((x) => x.id === element.metadata?.id) - return ( - { - e.preventDefault() - tabs.makeTabPermanent(tabId) - }} - element={element} - onSelectDelete={() => { - setShowDeleteModal(true) - setSelectedSnippets([element.metadata as unknown as Snippet]) - }} - onSelectRename={() => { - setShowRenameModal(true) - setSelectedSnippetToRename(element.metadata as Snippet) - }} - onSelectDownload={() => { - setSelectedSnippetToDownload(element.metadata as Snippet) - }} - onSelectUnshare={() => { - setSelectedSnippetToUnshare(element.metadata as Snippet) - }} - isLastItem={projectSnippetsLastItemIds.has(element.id as string)} - hasNextPage={hasMoreSharedSqlSnippets} - fetchNextPage={fetchNextSharedSqlSnippets} - isFetchingNextPage={isFetchingMoreSharedSqlSnippets} - /> - ) - }} + return ( + { + e.preventDefault() + tabs.makeTabPermanent(tabId) + }} + element={element} + onSelectDelete={() => { + setShowDeleteModal(true) + setSelectedSnippets([element.metadata as unknown as Snippet]) + }} + onSelectRename={() => { + setShowRenameModal(true) + setSelectedSnippetToRename(element.metadata as Snippet) + }} + onSelectDownload={() => { + setSelectedSnippetToDownload(element.metadata as Snippet) + }} + onSelectUnshare={() => { + setSelectedSnippetToUnshare(element.metadata as Snippet) + }} + isLastItem={projectSnippetsLastItemIds.has(element.id as string)} + hasNextPage={hasMoreSharedSqlSnippets} + fetchNextPage={fetchNextSharedSqlSnippets} + isFetchingNextPage={isFetchingMoreSharedSqlSnippets} + /> + ) + }} + /> + )} + + + + + + { + setSectionVisibility({ + ...(sectionVisibility ?? DEFAULT_SECTION_STATE), + favorite: value, + }) + }} + > + 0 ? ` (${numFavoriteSnippets})` : ''}`} /> - )} - - + + {isLoadingFavoriteSqlSnippets ? ( + + ) : favoriteSnippets.length === 0 ? ( + + Save a query to favorites for easy accessibility by clicking the{' '} + {' '} + icon. + + } + /> + ) : ( + { + 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 = tabs.previewTabId === tabId + const isActive = !isPreview && element.metadata?.id === id + const isSelected = selectedSnippets.some((x) => x.id === element.metadata?.id) - - - { - setSectionVisibility({ ...(sectionVisibility ?? DEFAULT_SECTION_STATE), favorite: value }) - }} - > - 0 ? ` (${numFavoriteSnippets})` : ''}`} - /> - - {isLoadingFavoriteSqlSnippets ? ( - - ) : favoriteSnippets.length === 0 ? ( - - Save a query to favorites for easy accessibility by clicking the{' '} - {' '} - icon. - - } - /> - ) : ( - { - 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 = tabs.previewTabId === tabId - const isActive = !isPreview && element.metadata?.id === id - const isSelected = selectedSnippets.some((x) => x.id === element.metadata?.id) - - return ( - { - e.preventDefault() - tabs.makeTabPermanent(tabId) - }} - element={element} - onSelectDelete={() => { - setShowDeleteModal(true) - setSelectedSnippets([element.metadata as unknown as Snippet]) - }} - onSelectRename={() => { - setShowRenameModal(true) - setSelectedSnippetToRename(element.metadata as Snippet) - }} - onSelectDownload={() => { - setSelectedSnippetToDownload(element.metadata as Snippet) - }} - onSelectShare={() => setSelectedSnippetToShare(element.metadata as Snippet)} - onSelectUnshare={() => { - setSelectedSnippetToUnshare(element.metadata as Snippet) - }} - isLastItem={favoriteSnippetsLastItemIds.has(element.id as string)} - hasNextPage={hasMoreFavoriteSqlSnippets} - fetchNextPage={fetchNextFavoriteSqlSnippets} - isFetchingNextPage={isFetchingMoreFavoriteSqlSnippets} - /> - ) - }} - /> - )} - - - - + return ( + { + e.preventDefault() + tabs.makeTabPermanent(tabId) + }} + element={element} + onSelectDelete={() => { + setShowDeleteModal(true) + setSelectedSnippets([element.metadata as unknown as Snippet]) + }} + onSelectRename={() => { + setShowRenameModal(true) + setSelectedSnippetToRename(element.metadata as Snippet) + }} + onSelectDownload={() => { + setSelectedSnippetToDownload(element.metadata as Snippet) + }} + onSelectShare={() => setSelectedSnippetToShare(element.metadata as Snippet)} + onSelectUnshare={() => { + setSelectedSnippetToUnshare(element.metadata as Snippet) + }} + isLastItem={favoriteSnippetsLastItemIds.has(element.id as string)} + hasNextPage={hasMoreFavoriteSqlSnippets} + fetchNextPage={fetchNextFavoriteSqlSnippets} + isFetchingNextPage={isFetchingMoreFavoriteSqlSnippets} + /> + ) + }} + /> + )} + + + + + )} { diff --git a/apps/studio/components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorTreeViewItem.tsx b/apps/studio/components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorTreeViewItem.tsx index 3753976bfca..222bf17ac5f 100644 --- a/apps/studio/components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorTreeViewItem.tsx +++ b/apps/studio/components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorTreeViewItem.tsx @@ -354,16 +354,19 @@ export const SQLEditorTreeViewItem = ({ Move query )} - {onSelectShare !== undefined && !isSharedSnippet && canCreateSQLSnippet && ( - onSelectShare()} - onFocusCapture={(e) => e.stopPropagation()} - > - - Share query with team - - )} + {onSelectShare !== undefined && + !isSharedSnippet && + canCreateSQLSnippet && + IS_PLATFORM && ( + onSelectShare()} + onFocusCapture={(e) => e.stopPropagation()} + > + + Share query with team + + )} {onSelectUnshare !== undefined && isSharedSnippet && isOwner && ( )} - onToggleFavorite()} - onFocusCapture={(e) => e.stopPropagation()} - > - - {isFavorite ? 'Remove from' : 'Add to'} favorites - + {IS_PLATFORM && ( + onToggleFavorite()} + onFocusCapture={(e) => e.stopPropagation()} + > + + {isFavorite ? 'Remove from' : 'Add to'} favorites + + )} {onSelectDownload !== undefined && IS_PLATFORM && ( { const [messageRatings, setMessageRatings] = useState>({}) const { data: check, isSuccess } = useCheckOpenAIKeyQuery() - const isApiKeySet = IS_PLATFORM || !!check?.hasKey + const isApiKeySet = !!check?.hasKey const { mutateAsync: rateMessage } = useRateMessageMutation() diff --git a/apps/studio/data/ai/check-api-key-query.ts b/apps/studio/data/ai/check-api-key-query.ts index 53a8816961a..f1f74a5d4f0 100644 --- a/apps/studio/data/ai/check-api-key-query.ts +++ b/apps/studio/data/ai/check-api-key-query.ts @@ -9,6 +9,10 @@ import { aiKeys } from './keys' // so we can disable the chat editor and add a warning about manually adding the key export async function checkOpenAIKey(signal?: AbortSignal) { + if (IS_PLATFORM) { + return { hasKey: true } + } + const headers = await constructHeaders() const response = await fetchHandler(`${BASE_PATH}/api/ai/sql/check-api-key`, { headers, @@ -37,6 +41,6 @@ export const useCheckOpenAIKeyQuery = ({ useQuery({ queryKey: aiKeys.apiKey(), queryFn: ({ signal }) => checkOpenAIKey(signal), - enabled: !IS_PLATFORM && enabled, + enabled: enabled, ...options, }) diff --git a/apps/studio/data/content/content-upsert-mutation.ts b/apps/studio/data/content/content-upsert-mutation.ts index ae00ca5607f..3455eb2ac40 100644 --- a/apps/studio/data/content/content-upsert-mutation.ts +++ b/apps/studio/data/content/content-upsert-mutation.ts @@ -6,6 +6,7 @@ import { handleError, put } from 'data/fetchers' import type { ResponseError, UseCustomMutationOptions } from 'types' import type { Content } from './content-query' import { contentKeys } from './keys' +import type { Snippet } from './sql-folders-query' export type UpsertContentPayload = Omit & { content: Partial @@ -29,7 +30,7 @@ export async function upsertContent( }) if (error) handleError(error) - return data + return data as Snippet | null } export type UpsertContentData = Awaited> diff --git a/apps/studio/pages/project/[ref]/sql/index.tsx b/apps/studio/pages/project/[ref]/sql/index.tsx index 79aff70fbf1..6a1062d86fd 100644 --- a/apps/studio/pages/project/[ref]/sql/index.tsx +++ b/apps/studio/pages/project/[ref]/sql/index.tsx @@ -22,12 +22,13 @@ const SQLEditorIndexPage: NextPageWithLayout = () => { // Handle redirect to last opened snippet tab, or last snippet tab const lastOpenedTab = history.sql const lastTabId = store.openTabs.find((id) => store.tabsMap[id]?.type === 'sql') - if (lastOpenedTab !== undefined) { router.push(`/project/${projectRef}/sql/${history.sql}`) } else if (lastTabId) { const lastTab = store.tabsMap[lastTabId] - if (lastTab) router.push(`/project/${projectRef}/sql/${lastTab.id.replace('sql-', '')}`) + if (lastTab) { + router.push(`/project/${projectRef}/sql/${lastTab.id.replace('sql-', '')}`) + } } else { router.push(`/project/${projectRef}/sql/new`) } diff --git a/apps/studio/state/tabs.tsx b/apps/studio/state/tabs.tsx index 7b282f2128b..3064047b4d7 100644 --- a/apps/studio/state/tabs.tsx +++ b/apps/studio/state/tabs.tsx @@ -169,6 +169,9 @@ function createTabsState(projectRef: string) { tabsMap, previewTabId, + hasTab: (id: string) => { + return !!store.tabsMap[id] + }, addTab: (tab: Tab) => { // If tab exists and is active, don't do anything if (store.tabsMap[tab.id] && store.activeTab === tab.id) { diff --git a/e2e/studio/features/sql-editor.spec.ts b/e2e/studio/features/sql-editor.spec.ts index a7e40af32eb..db689ed1b5d 100644 --- a/e2e/studio/features/sql-editor.spec.ts +++ b/e2e/studio/features/sql-editor.spec.ts @@ -1,12 +1,12 @@ import { expect, Page } from '@playwright/test' import fs from 'fs' +import { env } from '../env.config.js' import { isCLI } from '../utils/is-cli.js' import { resetLocalStorage } from '../utils/reset-local-storage.js' import { test } from '../utils/test.js' import { toUrl } from '../utils/to-url.js' import { waitForApiResponseWithTimeout } from '../utils/wait-for-response-with-timeout.js' import { waitForApiResponse } from '../utils/wait-for-response.js' -import { env } from '../env.config.js' const sqlSnippetName = 'pw_sql_snippet' const sqlSnippetNameDuplicate = 'pw_sql_snippet (Duplicate)' @@ -215,23 +215,23 @@ hello world`) }) test('snippet favourite works as expected', async ({ ref }) => { - if (!isCLI()) { - // clean up private snippets and snippets shared with the team - await waitForApiResponseWithTimeout( - page, - (response) => response.url().includes('query?key=table-columns'), - 3000 - ) - const privateSnippetSection = page.getByLabel('private-snippets') - if ((await privateSnippetSection.getByText(newSqlSnippetName, { exact: true }).count()) > 0) { - await deleteSqlSnippet(page, ref, newSqlSnippetName) - } + test.skip(isCLI(), 'This test does not work in self-hosted environments.') - if ( - (await privateSnippetSection.getByText(sqlSnippetNameFavorite, { exact: true }).count()) > 0 - ) { - await deleteSqlSnippet(page, ref, sqlSnippetNameFavorite) - } + // clean up private snippets and snippets shared with the team + await waitForApiResponseWithTimeout( + page, + (response) => response.url().includes('query?key=table-columns'), + 3000 + ) + const privateSnippetSection = page.getByLabel('private-snippets') + if ((await privateSnippetSection.getByText(newSqlSnippetName, { exact: true }).count()) > 0) { + await deleteSqlSnippet(page, ref, newSqlSnippetName) + } + + if ( + (await privateSnippetSection.getByText(sqlSnippetNameFavorite, { exact: true }).count()) > 0 + ) { + await deleteSqlSnippet(page, ref, sqlSnippetNameFavorite) } // create sql snippet @@ -242,7 +242,6 @@ hello world`) await page.getByTestId('sql-run-button').click() // rename snippet - const privateSnippetSection = page.getByLabel('private-snippets') await privateSnippetSection.getByText(newSqlSnippetName).click({ button: 'right' }) await page.getByRole('menuitem', { name: 'Rename query', exact: true }).click() await expect(page.getByRole('heading', { name: 'Rename' })).toBeVisible() @@ -283,10 +282,7 @@ hello world`) }) test('share with team works as expected', async ({ ref }) => { - if (!isCLI()) { - console.log('Sharing and unsharing SQL snippet has issues in staging') - return - } + test.skip(isCLI(), 'Sharing and unsharing SQL snippet has issues in staging') // clean up private snippets and snippets shared with the team await waitForApiResponseWithTimeout( @@ -379,25 +375,21 @@ hello world`) }) test('folders works as expected', async ({ ref }) => { - if (!isCLI()) { - // clean up folders and snippets - await waitForApiResponseWithTimeout( - page, - (response) => response.url().includes('query?key=table-columns'), - 3000 - ) - const privateSnippetSection = page.getByLabel('private-snippets') - if ((await privateSnippetSection.getByText(sqlFolderName, { exact: true }).count()) > 0) { - await deleteFolder(page, ref, sqlFolderName) - } - if ( - (await privateSnippetSection.getByText(sqlFolderNameUpdated, { exact: true }).count()) > 0 - ) { - await deleteFolder(page, ref, sqlFolderNameUpdated) - } - } else { - console.log('This test does not work in self-hosted environments.') - return + test.skip(isCLI(), 'This test does not work in self-hosted environments.') + // clean up folders and snippets + await waitForApiResponseWithTimeout( + page, + (response) => response.url().includes('query?key=table-columns'), + 3000 + ) + const privateSnippetSection = page.getByLabel('private-snippets') + if ((await privateSnippetSection.getByText(sqlFolderName, { exact: true }).count()) > 0) { + await deleteFolder(page, ref, sqlFolderName) + } + if ( + (await privateSnippetSection.getByText(sqlFolderNameUpdated, { exact: true }).count()) > 0 + ) { + await deleteFolder(page, ref, sqlFolderNameUpdated) } // create sql snippet @@ -408,7 +400,6 @@ hello world`) await page.getByTestId('sql-run-button').click() // rename snippet - const privateSnippetSection = page.getByLabel('private-snippets') await privateSnippetSection.getByText(newSqlSnippetName).click({ button: 'right' }) await page.getByRole('menuitem', { name: 'Rename query', exact: true }).click() await expect(page.getByRole('heading', { name: 'Rename' })).toBeVisible() @@ -473,26 +464,22 @@ hello world`) }) test('other SQL snippets actions work as expected', async ({ ref }) => { - if (!isCLI()) { - // clean up 'Untitled query', 'pw_sql_snippet' and 'pw_sql_snippet (Duplicate)' snippets if exists - await waitForApiResponseWithTimeout( - page, - (response) => response.url().includes('query?key=table-columns'), - 3000 - ) - const privateSnippet = page.getByLabel('private-snippets') - if ((await privateSnippet.getByText(newSqlSnippetName).count()) > 0) { - deleteSqlSnippet(page, ref, newSqlSnippetName) - } - if ((await privateSnippet.getByText(sqlSnippetNameDuplicate, { exact: true }).count()) > 0) { - await deleteSqlSnippet(page, ref, sqlSnippetNameDuplicate) - } - if ((await privateSnippet.getByText(sqlSnippetName, { exact: true }).count()) > 0) { - await deleteSqlSnippet(page, ref, sqlSnippetName) - } - } else { - console.log('This test does not work in self-hosted environments.') - return + test.skip(isCLI(), 'This test does not work in self-hosted environments.') + // clean up 'Untitled query', 'pw_sql_snippet' and 'pw_sql_snippet (Duplicate)' snippets if exists + await waitForApiResponseWithTimeout( + page, + (response) => response.url().includes('query?key=table-columns'), + 3000 + ) + const privateSnippet = page.getByLabel('private-snippets') + if ((await privateSnippet.getByText(newSqlSnippetName).count()) > 0) { + deleteSqlSnippet(page, ref, newSqlSnippetName) + } + if ((await privateSnippet.getByText(sqlSnippetNameDuplicate, { exact: true }).count()) > 0) { + await deleteSqlSnippet(page, ref, sqlSnippetNameDuplicate) + } + if ((await privateSnippet.getByText(sqlSnippetName, { exact: true }).count()) > 0) { + await deleteSqlSnippet(page, ref, sqlSnippetName) } // create sql snippet diff --git a/package.json b/package.json index 39559ad051b..ac42d0ed66b 100644 --- a/package.json +++ b/package.json @@ -30,8 +30,8 @@ "test:studio": "turbo run test --filter=studio", "test:studio:watch": "turbo run test --filter=studio -- watch", "e2e:setup:cli": "supabase stop --all --no-backup ; supabase start --exclude studio && supabase db reset && supabase status --output json > keys.json && node scripts/generateLocalEnv.js", - "e2e:setup:selfhosted": "SKIP_ASSET_UPLOAD=1 pnpm e2e:setup:cli && NODE_ENV=test NODE_OPTIONS=\"--max-old-space-size=4096\" pnpm run build:studio && NODE_ENV=test pnpm --prefix ./apps/studio start --port 8082", - "e2e:setup:platform": "SKIP_ASSET_UPLOAD=1 NODE_OPTIONS=\"--max-old-space-size=4096\" pnpm run build:studio && pnpm --prefix ./apps/studio start --port 8082", + "e2e:setup:selfhosted": "SKIP_ASSET_UPLOAD=1 pnpm e2e:setup:cli && NODE_ENV=test NODE_OPTIONS=\"--max-old-space-size=4096\" pnpm run build:studio && NODE_ENV=test pnpm --prefix ./apps/studio start", + "e2e:setup:platform": "SKIP_ASSET_UPLOAD=1 NODE_OPTIONS=\"--max-old-space-size=4096\" pnpm run build:studio && pnpm --prefix ./apps/studio start", "e2e": "pnpm --prefix e2e/studio run e2e", "e2e:ui": "pnpm --prefix e2e/studio run e2e:ui", "perf:kong": "ab -t 5 -c 20 -T application/json http://localhost:8000/",