diff --git a/apps/studio/components/interfaces/SQLEditor/MonacoEditor.tsx b/apps/studio/components/interfaces/SQLEditor/MonacoEditor.tsx
index dc954c5088a..a44e6a8b63c 100644
--- a/apps/studio/components/interfaces/SQLEditor/MonacoEditor.tsx
+++ b/apps/studio/components/interfaces/SQLEditor/MonacoEditor.tsx
@@ -19,6 +19,7 @@ import { SHORTCUT_IDS } from '@/state/shortcuts/registry'
import { useIsShortcutEnabled } from '@/state/shortcuts/useIsShortcutEnabled'
import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state'
import { useSqlEditorV2StateSnapshot } from '@/state/sql-editor-v2'
+import { wasNeverPersisted } from '@/state/sql-editor/sql-editor-lifecycle'
import { canEditSnippet } from '@/state/sql-editor/sql-editor-rules'
import { useTabsStateSnapshot } from '@/state/tabs'
@@ -237,7 +238,7 @@ export const MonacoEditor = ({
useEffect(() => {
if (debouncedValue.length > 0 && snippet) {
- const shouldInvalidate = snippet.snippet.isNotSavedInDatabaseYet
+ const shouldInvalidate = wasNeverPersisted(snippet.snippet.status)
snapV2.setSql({ id, sql: value, shouldInvalidate })
}
// eslint-disable-next-line react-hooks/exhaustive-deps
diff --git a/apps/studio/components/interfaces/SQLEditor/MoveQueryModal.tsx b/apps/studio/components/interfaces/SQLEditor/MoveQueryModal.tsx
index 7fd3ea7ae7e..af39f60b7ea 100644
--- a/apps/studio/components/interfaces/SQLEditor/MoveQueryModal.tsx
+++ b/apps/studio/components/interfaces/SQLEditor/MoveQueryModal.tsx
@@ -41,11 +41,8 @@ import { getContentById } from '@/data/content/content-id-query'
import { useContentUpsertMutation } from '@/data/content/content-upsert-mutation'
import { useSQLSnippetFolderCreateMutation } from '@/data/content/sql-folder-create-mutation'
import { Snippet } from '@/data/content/sql-folders-query'
-import {
- SnippetWithContent,
- useSnippetFolders,
- useSqlEditorV2StateSnapshot,
-} from '@/state/sql-editor-v2'
+import type { SnippetWithContent } from '@/data/content/sql-folders-query'
+import { useSnippetFolders, useSqlEditorV2StateSnapshot } from '@/state/sql-editor-v2'
import { createTabId, useTabsStateSnapshot } from '@/state/tabs'
interface MoveQueryModalProps {
diff --git a/apps/studio/components/interfaces/SQLEditor/RenameQueryModal.tsx b/apps/studio/components/interfaces/SQLEditor/RenameQueryModal.tsx
index fa5da761acf..1f92fc58090 100644
--- a/apps/studio/components/interfaces/SQLEditor/RenameQueryModal.tsx
+++ b/apps/studio/components/interfaces/SQLEditor/RenameQueryModal.tsx
@@ -26,7 +26,7 @@ import * as z from 'zod'
import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
import { useCheckOpenAIKeyQuery } from '@/data/ai/check-api-key-query'
import { useSqlTitleGenerateMutation } from '@/data/ai/sql-title-mutation'
-import { getContentById } from '@/data/content/content-id-query'
+import { getContentById, getSqlSnippetById } from '@/data/content/content-id-query'
import {
UpsertContentPayload,
useContentUpsertMutation,
@@ -109,8 +109,9 @@ export const RenameQueryModal = ({
// [Joshen] For SQL V2 - content is loaded on demand so we need to fetch the data if its not already loaded in the valtio state
if (!('content' in localSnippet)) {
- localSnippet = await getContentById({ projectRef: ref, id })
- snapV2.addSnippet({ projectRef: ref, snippet: localSnippet })
+ const fetched = await getSqlSnippetById({ projectRef: ref, id })
+ snapV2.addSnippet({ projectRef: ref, snippet: fetched })
+ localSnippet = fetched
}
const changedSnippet = await upsertContent({
diff --git a/apps/studio/components/interfaces/SQLEditor/SQLEditor.utils.ts b/apps/studio/components/interfaces/SQLEditor/SQLEditor.utils.ts
index 0e497cca467..9e01e8c24a2 100644
--- a/apps/studio/components/interfaces/SQLEditor/SQLEditor.utils.ts
+++ b/apps/studio/components/interfaces/SQLEditor/SQLEditor.utils.ts
@@ -9,11 +9,11 @@ import {
updateWithoutWhereRegex,
} from './SQLEditor.constants'
import { ContentDiff } from './SQLEditor.types'
+import type { SnippetWithContent } from '@/data/content/sql-folders-query'
import type { DatabaseEventTrigger } from '@/data/database-event-triggers/database-event-triggers-query'
import { generateUuid } from '@/lib/api/snippets.browser'
import { removeCommentsFromSql } from '@/lib/helpers'
import { sqlEventParser } from '@/lib/sql-event-parser'
-import type { SnippetWithContent } from '@/state/sql-editor-v2'
export type CreateTableWithoutRLS = {
schema?: string
@@ -83,7 +83,7 @@ export const createSqlSnippetSkeletonV2 = ({
content_id: id ?? '',
unchecked_sql: untrustedSql(sql ?? ''),
} as any,
- isNotSavedInDatabaseYet: true,
+ status: 'new',
}
}
diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/SavingIndicator.tsx b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/SavingIndicator.tsx
index 12c34a4214d..dd62160f012 100644
--- a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/SavingIndicator.tsx
+++ b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/SavingIndicator.tsx
@@ -6,6 +6,7 @@ import { Button, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
import ReadOnlyBadge from './ReadOnlyBadge'
import { useProfile } from '@/lib/profile'
import { useSqlEditorV2StateSnapshot } from '@/state/sql-editor-v2'
+import { isSaveFailed, isSaving } from '@/state/sql-editor/sql-editor-lifecycle'
import { isSnippetOwner } from '@/state/sql-editor/sql-editor-rules'
export type SavingIndicatorProps = { id: string }
@@ -14,17 +15,19 @@ const SavingIndicator = ({ id }: SavingIndicatorProps) => {
const { profile } = useProfile()
const snapV2 = useSqlEditorV2StateSnapshot()
- const savingState = snapV2.savingStates[id]
- const previousState = usePrevious(savingState)
+ const snippet = snapV2.snippets[id]
+ const status = snippet?.snippet.status
+ const saving = isSaving(status)
+ const saveFailed = isSaveFailed(status)
+ const previousSaving = usePrevious(saving)
const [showSavedText, setShowSavedText] = useState(false)
- const snippet = snapV2.snippets[id]
const snippetIsOwned = !!snippet && isSnippetOwner(snippet.snippet, profile?.id)
useEffect(() => {
let cancel = false
- if (previousState === 'UPDATING' && savingState === 'IDLE') {
+ if (previousSaving && status === 'saved') {
setShowSavedText(true)
setTimeout(() => {
if (!cancel) setShowSavedText(false)
@@ -34,14 +37,14 @@ const SavingIndicator = ({ id }: SavingIndicatorProps) => {
return () => {
cancel = true
}
- }, [savingState])
+ }, [status, previousSaving])
const retry = () => snapV2.addNeedsSaving(id)
return (
<>
- {snippetIsOwned && savingState === 'UPDATING_FAILED' && (
+ {snippetIsOwned && saveFailed && (