@@ -158,7 +162,9 @@ export default function RealtimeLimitsEstimater({}) {
.filter((v, i, a) => a.indexOf(v) === i)
.map((computeAddOn) => (
-
{COMPUTE_LABELS[computeAddOn]}
+
+ {COMPUTE_LABELS[computeAddOn]}
+
diff --git a/apps/docs/content/_partials/social_provider_setup.mdx b/apps/docs/content/_partials/social_provider_setup.mdx
index 399d31eda5707..aa87b887f57dc 100644
--- a/apps/docs/content/_partials/social_provider_setup.mdx
+++ b/apps/docs/content/_partials/social_provider_setup.mdx
@@ -5,9 +5,7 @@ The next step requires a callback URL, which looks like this: `https://
-
-#### Local development
+### Local development
When testing OAuth locally with the Supabase CLI, ensure your OAuth provider
is configured with the local Supabase Auth callback URL:
@@ -19,5 +17,3 @@ If this callback URL is missing or misconfigured, OAuth sign-in may fail or not
See the [local development docs](/docs/guides/local-development) for more details.
For testing OAuth locally with the Supabase CLI see the [local development docs](/docs/guides/local-development).
-
-
diff --git a/apps/docs/content/guides/auth/quickstarts/astrojs.mdx b/apps/docs/content/guides/auth/quickstarts/astrojs.mdx
index 1baa7521c4394..c43992fc6ce0d 100644
--- a/apps/docs/content/guides/auth/quickstarts/astrojs.mdx
+++ b/apps/docs/content/guides/auth/quickstarts/astrojs.mdx
@@ -5,6 +5,8 @@ breadcrumb: 'Auth Quickstarts'
hideToc: true
---
+## Quickstart
+
diff --git a/apps/docs/content/guides/auth/quickstarts/nextjs.mdx b/apps/docs/content/guides/auth/quickstarts/nextjs.mdx
index 30912b80e7e9f..eb56a6c7710a7 100644
--- a/apps/docs/content/guides/auth/quickstarts/nextjs.mdx
+++ b/apps/docs/content/guides/auth/quickstarts/nextjs.mdx
@@ -5,6 +5,8 @@ breadcrumb: 'Auth Quickstarts'
hideToc: true
---
+## Quickstart
+
diff --git a/apps/docs/content/guides/auth/quickstarts/react-native.mdx b/apps/docs/content/guides/auth/quickstarts/react-native.mdx
index d8ed113a8840c..46c2c79c3395e 100644
--- a/apps/docs/content/guides/auth/quickstarts/react-native.mdx
+++ b/apps/docs/content/guides/auth/quickstarts/react-native.mdx
@@ -5,6 +5,8 @@ breadcrumb: 'Auth Quickstarts'
hideToc: true
---
+## Quickstart
+
diff --git a/apps/docs/content/guides/auth/quickstarts/react.mdx b/apps/docs/content/guides/auth/quickstarts/react.mdx
index 63cc239e11740..f624e8d03eced 100644
--- a/apps/docs/content/guides/auth/quickstarts/react.mdx
+++ b/apps/docs/content/guides/auth/quickstarts/react.mdx
@@ -5,6 +5,8 @@ breadcrumb: 'Auth Quickstarts'
hideToc: true
---
+## Quickstart
+
diff --git a/apps/docs/content/guides/database/functions.mdx b/apps/docs/content/guides/database/functions.mdx
index e02dfed95a62d..f7a3520362096 100644
--- a/apps/docs/content/guides/database/functions.mdx
+++ b/apps/docs/content/guides/database/functions.mdx
@@ -164,7 +164,7 @@ For example, if we had a database with some Star Wars data inside:
>
-
Planets
+### Planets
```
| id | name |
@@ -174,7 +174,7 @@ For example, if we had a database with some Star Wars data inside:
| 3 | Kashyyyk |
```
-
People
+### People
```
| id | name | planet_id |
diff --git a/apps/docs/content/guides/integrations/vercel-marketplace.mdx b/apps/docs/content/guides/integrations/vercel-marketplace.mdx
index ac3c21bbf610e..26c4be43088f0 100644
--- a/apps/docs/content/guides/integrations/vercel-marketplace.mdx
+++ b/apps/docs/content/guides/integrations/vercel-marketplace.mdx
@@ -23,7 +23,7 @@ Vercel Marketplace is currently in Public Alpha. If you encounter any issues or
### Via template
-
Deploy a Next.js app with Supabase Vercel Storage now
+
Deploy a Next.js app with Supabase Vercel Storage now
}
+ />
+ )
+ expect(screen.getByText('Custom fallback')).toBeInTheDocument()
+ })
+
+ it('ignores the caller-provided fallback when the error is classified', () => {
+ const error = new ConnectionTimeoutError('CONNECTION TERMINATED DUE TO CONNECTION TIMEOUT')
+ render(
+ Custom fallback}
+ />
+ )
+ expect(screen.queryByText('Custom fallback')).not.toBeInTheDocument()
+ expect(screen.getByText('Try restarting your project')).toBeInTheDocument()
+ })
+
it('accepts error as object with message property', () => {
render(
- {Troubleshooting && }
+ {Troubleshooting ? : fallback}
)
}
diff --git a/apps/studio/components/interfaces/ErrorHandling/RestartTroubleshootingFallback.tsx b/apps/studio/components/interfaces/ErrorHandling/RestartTroubleshootingFallback.tsx
new file mode 100644
index 0000000000000..6d715d98ff663
--- /dev/null
+++ b/apps/studio/components/interfaces/ErrorHandling/RestartTroubleshootingFallback.tsx
@@ -0,0 +1,15 @@
+import { TroubleshootingAccordion } from './TroubleshootingAccordion'
+import { RestartDatabaseTroubleshootingSection } from './TroubleshootingSections'
+
+const ERROR_TYPE = 'unknown'
+
+export function RestartTroubleshootingFallback() {
+ return (
+
+
+
+ )
+}
diff --git a/apps/studio/components/interfaces/Integrations/Queues/SingleQueue/QueueSettings.tsx b/apps/studio/components/interfaces/Integrations/Queues/SingleQueue/QueueSettings.tsx
index b1496a1dc3c0b..05cfc78cf3737 100644
--- a/apps/studio/components/interfaces/Integrations/Queues/SingleQueue/QueueSettings.tsx
+++ b/apps/studio/components/interfaces/Integrations/Queues/SingleQueue/QueueSettings.tsx
@@ -214,7 +214,7 @@ export const QueueSettings = ({}: QueueSettingsProps) => {
toast.success('Successfully updated permissions')
setOpen(false)
} catch (error: unknown) {
- toast.error(`Failed to update permissions: ${getErrorMessage(error)}`)
+ toast.error(`Failed to update permissions: ${getErrorMessage(error, 'unknown error')}`)
} finally {
setIsSaving(false)
}
diff --git a/apps/studio/components/interfaces/Reports/ReportBlock/LogsSnippetReportBlock.tsx b/apps/studio/components/interfaces/Reports/ReportBlock/LogsSnippetReportBlock.tsx
new file mode 100644
index 0000000000000..c6114a476139d
--- /dev/null
+++ b/apps/studio/components/interfaces/Reports/ReportBlock/LogsSnippetReportBlock.tsx
@@ -0,0 +1,37 @@
+import { ScrollText } from 'lucide-react'
+import { ReactNode } from 'react'
+
+import { ReportBlockContainer } from './ReportBlockContainer'
+
+interface LogsSnippetReportBlockProps {
+ label: string
+ actions?: ReactNode
+}
+
+/**
+ * Stands in for a snippet that queries the logs backend. Reports only run SQL
+ * against the user's database, so a `log_sql` snippet reference renders this
+ * instead of executing — see ReportBlock, which never issues a query for one.
+ */
+export const LogsSnippetReportBlock = ({ label, actions }: LogsSnippetReportBlockProps) => {
+ return (
+ }
+ label={label}
+ actions={actions}
+ >
+
+
+ Logs snippets aren't supported in reports yet
+
+
+ Reports can't run queries against the logs backend yet. Open this snippet in the SQL
+ editor to view results, or remove it from this report.
+
+
+
+ )
+}
diff --git a/apps/studio/components/interfaces/Reports/ReportBlock/ReportBlock.tsx b/apps/studio/components/interfaces/Reports/ReportBlock/ReportBlock.tsx
index ba68a57a12723..2fea6cc8265ac 100644
--- a/apps/studio/components/interfaces/Reports/ReportBlock/ReportBlock.tsx
+++ b/apps/studio/components/interfaces/Reports/ReportBlock/ReportBlock.tsx
@@ -9,6 +9,7 @@ import { applyAutoLimit } from '../../SQLEditor/SQLEditor.utils'
import { BURSTABLE_IO_METRIC_KEYS, DEPRECATED_REPORTS } from '../Reports.constants'
import { ChartBlock } from './ChartBlock'
import { DeprecatedChartBlock } from './DeprecatedChartBlock'
+import { LogsSnippetReportBlock } from './LogsSnippetReportBlock'
import { UnavailableChartBlock } from './UnavailableChartBlock'
import { hasBurstableIO } from '@/components/interfaces/DiskManagement/DiskManagement.utils'
import { ChartConfig } from '@/components/interfaces/SQLEditor/UtilityPanel/ChartConfig'
@@ -79,8 +80,11 @@ export const ReportBlock = ({
}
)
+ const isLogsSnippet = data?.type === 'log_sql'
+
const autoLimit = 100
- const sql = isSnippet ? (data?.content as SqlSnippets.Content)?.unchecked_sql : undefined
+ const sql =
+ isSnippet && !isLogsSnippet ? (data?.content as SqlSnippets.Content)?.unchecked_sql : undefined
// acceptUntrustedSql is usually not allowed outside a user-action event
// handler, but it's explicitly fine here: adding this block to a report is
// itself the user action that approves running its SQL.
@@ -125,7 +129,7 @@ export const ReportBlock = ({
sql: formattedSql,
})
},
- enabled: !isLoadingContent && contentError == null,
+ enabled: !isLoadingContent && contentError == null && !isLogsSnippet,
refetchOnWindowFocus: false,
})
@@ -151,6 +155,25 @@ export const ReportBlock = ({
}
}, [isRefreshing, refetch])
+ if (isLogsSnippet) {
+ return (
+ }
+ className="w-7 h-7"
+ onClick={() => onRemoveChart({ metric: { key: item.attribute } })}
+ tooltip={{ content: { side: 'bottom', text: 'Remove chart' } }}
+ />
+ ) : null
+ }
+ />
+ )
+ }
+
return (
<>
{isSnippet ? (
diff --git a/apps/studio/components/interfaces/SQLEditor/LegacyLogsRewriteBanner.tsx b/apps/studio/components/interfaces/SQLEditor/LegacyLogsRewriteBanner.tsx
new file mode 100644
index 0000000000000..9bb41fe5430d9
--- /dev/null
+++ b/apps/studio/components/interfaces/SQLEditor/LegacyLogsRewriteBanner.tsx
@@ -0,0 +1,77 @@
+import { useDebounce } from '@uidotdev/usehooks'
+import { useFlag } from 'common'
+import { useMemo } from 'react'
+
+import { DiffType } from './SQLEditor.types'
+import { useSqlEditorAssistant, useSqlEditorRun, useSqlEditorSnippet } from './SQLEditorControllers'
+import { LegacyLogsRewriteAdmonition } from '@/components/interfaces/Settings/Logs/LegacyLogsRewriteAdmonition'
+import {
+ LEGACY_LOGS_DIALECT_CHECK_DEBOUNCE_MS,
+ shouldOfferLegacyLogsRewrite,
+} from '@/data/logs/logs-sql-rewrite'
+import { useLegacyLogsRewrite } from '@/hooks/analytics/useLegacyLogsRewrite'
+import {
+ getSqlEditorV2StateSnapshot,
+ useSqlEditorV2StateSnapshot,
+} from '@/state/sql-editor/sql-editor-state'
+
+/**
+ * Offers to rewrite a logs snippet still written in the old BigQuery dialect
+ * (per-service `FROM` tables, `unnest(metadata)` joins) to ClickHouse SQL. Legacy
+ * Logs Explorer saved queries open in the SQL editor as `log_sql` snippets, and
+ * those queries error against the ClickHouse-backed endpoint the editor runs them
+ * on — this is the in-editor path out.
+ *
+ * The request itself is `useLegacyLogsRewrite` (shared with the Logs Explorer);
+ * this decides when to offer it and routes the result into the editor's existing
+ * AI diff view, so the user accepts or discards it the same way as any other AI
+ * edit rather than having the snippet rewritten under them.
+ *
+ * Mount with `key={id}` so the offer resets when the user switches snippets. This
+ * component must NOT be conditionally mounted by its parent — it hides itself, so
+ * that opening a diff doesn't unmount it and throw away a dismissal.
+ */
+export const LegacyLogsRewriteBanner = () => {
+ const { id } = useSqlEditorSnippet()
+ const { runSource } = useSqlEditorRun()
+ const {
+ diff: { isDiffOpen, setSourceSqlDiff, setSelectedDiffType },
+ } = useSqlEditorAssistant()
+
+ const isOtelLogsEnabled = useFlag('otelLegacyLogs')
+ const snapV2 = useSqlEditorV2StateSnapshot()
+
+ // The store is written on every keystroke, so debounce before running the
+ // dialect heuristics — the banner's visibility doesn't need per-character
+ // precision, and a settled value avoids flapping mid-edit.
+ const liveSql = snapV2.snippets[id]?.snippet.content?.unchecked_sql ?? ''
+ const settledSql = useDebounce(liveSql, LEGACY_LOGS_DIALECT_CHECK_DEBOUNCE_MS)
+
+ const isLogsSnippetNeedingRewrite = useMemo(
+ () =>
+ runSource.type === 'logs' &&
+ shouldOfferLegacyLogsRewrite({ sql: settledSql, isClickhouseLogsEnabled: isOtelLogsEnabled }),
+ [runSource.type, settledSql, isOtelLogsEnabled]
+ )
+
+ const { state, requestRewrite, dismiss } = useLegacyLogsRewrite({
+ // Rewrite exactly what's in the editor now, not the debounced value the
+ // visibility check used — they differ if the user clicked mid-edit.
+ readSql: () => getSqlEditorV2StateSnapshot().snippets[id]?.snippet.content?.unchecked_sql ?? '',
+ onProposal: ({ original, modified }) => {
+ setSourceSqlDiff({ original, modified })
+ setSelectedDiffType(DiffType.Modification)
+ },
+ })
+
+ // An outcome the user hasn't acknowledged stays up even once the query no longer
+ // looks legacy — otherwise a successful proposal would yank its own result away.
+ const hasUnacknowledgedOutcome = state.status === 'failed' || state.status === 'noRewriteNeeded'
+ const canShowBanner = !isDiffOpen && (isLogsSnippetNeedingRewrite || hasUnacknowledgedOutcome)
+
+ if (!canShowBanner) return null
+
+ return (
+
+ )
+}
diff --git a/apps/studio/components/interfaces/SQLEditor/SQLEditor.utils.test.ts b/apps/studio/components/interfaces/SQLEditor/SQLEditor.utils.test.ts
index 982ef10bb1606..d981a2da927dd 100644
--- a/apps/studio/components/interfaces/SQLEditor/SQLEditor.utils.test.ts
+++ b/apps/studio/components/interfaces/SQLEditor/SQLEditor.utils.test.ts
@@ -29,6 +29,7 @@ import {
resolveConnectionString,
resolveDiffKeyAction,
shouldAutoGenerateTitle,
+ sqlSourceToDialect,
trimTrailingSemicolons,
} from './SQLEditor.utils'
import type { DatabaseEventTrigger } from '@/data/database-event-triggers/database-event-triggers-query'
@@ -392,13 +393,26 @@ describe('SQLEditor.utils.ts:buildDebugChatArgs', () => {
test('builds the newChat payload from the snippet sql and error message', () => {
const snippet = buildDebugSnippet('select 1;')
const result = { error: { message: 'relation does not exist' } }
- expect(buildDebugChatArgs(snippet, result)).toEqual({
+ expect(buildDebugChatArgs(snippet, result, 'database')).toEqual({
name: 'Debug SQL snippet',
- sqlSnippets: ['select 1;'],
+ sqlSnippets: [{ label: 'Current Query', content: 'select 1;', source: 'database' }],
initialInput:
'Help me to debug the attached sql snippet which gives the following error: \n\nrelation does not exist',
})
})
+
+ // The attachment is what puts sqlSource on the message the user then submits, so
+ // the debug flow has to attach a sourced snippet, not a bare string.
+ test('attaches the query with its source and names the dialect', () => {
+ const snippet = buildDebugSnippet('select count(*) from logs;')
+ const result = { error: { message: 'Unknown expression identifier' } }
+ expect(buildDebugChatArgs(snippet, result, 'logs').sqlSnippets).toEqual([
+ { label: 'Current Query', content: 'select count(*) from logs;', source: 'logs' },
+ ])
+ expect(buildDebugChatArgs(snippet, result, 'logs').initialInput).toEqual(
+ 'Help me to debug the attached sql snippet which gives the following error: \n\nUnknown expression identifier\n\nThis query runs against the Supabase logs table on a ClickHouse-backed engine, not Postgres.'
+ )
+ })
})
describe('SQLEditor.utils.ts:buildCompletionRequestBody', () => {
@@ -432,6 +446,31 @@ describe('SQLEditor.utils.ts:buildCompletionRequestBody', () => {
completionMetadata: { prompt: 'add a where clause' },
})
})
+ test('omits dialect when not provided, so the route keeps its Postgres default', () => {
+ const body = buildCompletionRequestBody({
+ projectRef: 'default',
+ connectionString: null,
+ orgSlug: 'acme',
+ })
+ expect(body).not.toHaveProperty('dialect')
+ })
+ test('includes the dialect when provided', () => {
+ expect(
+ buildCompletionRequestBody({
+ projectRef: 'default',
+ connectionString: null,
+ orgSlug: 'acme',
+ dialect: 'clickhouse',
+ }).dialect
+ ).toBe('clickhouse')
+ })
+})
+
+describe('SQLEditor.utils.ts:sqlSourceToDialect', () => {
+ test('logs snippets get ClickHouse, database snippets get Postgres', () => {
+ expect(sqlSourceToDialect('logs')).toBe('clickhouse')
+ expect(sqlSourceToDialect('database')).toBe('postgres')
+ })
})
describe('SQLEditor.utils.ts:createSqlSnippetSkeletonV2', () => {
@@ -1438,9 +1477,21 @@ describe('SQLEditor.utils:assembleCompletionDiff', () => {
describe('SQLEditor.utils:buildDebugPromptText', () => {
it('builds the debug prompt with the error message and SQL block', () => {
- const result = buildDebugPromptText('select 1;', 'relation does not exist')
+ const result = buildDebugPromptText('select 1;', 'relation does not exist', 'database')
expect(result).toContain('relation does not exist')
expect(result).toContain('```sql\nselect 1;\n```')
+ expect(result).not.toContain('ClickHouse')
+ })
+
+ // This text is copyable and gets pasted into external models, so it has to name
+ // the dialect itself rather than relying on the message metadata.
+ it('names the dialect for a logs snippet', () => {
+ const sql = "select count() from logs where source = 'edge_logs'"
+ const result = buildDebugPromptText(sql, 'Unknown expression identifier', 'logs')
+ expect(result).toContain('Unknown expression identifier')
+ expect(result).toContain('ClickHouse')
+ expect(result).toContain('not Postgres')
+ expect(result).toContain('```clickhouse\n' + sql + '\n```')
})
})
diff --git a/apps/studio/components/interfaces/SQLEditor/SQLEditor.utils.ts b/apps/studio/components/interfaces/SQLEditor/SQLEditor.utils.ts
index aa1ba9120804b..188c8c0fdcef3 100644
--- a/apps/studio/components/interfaces/SQLEditor/SQLEditor.utils.ts
+++ b/apps/studio/components/interfaces/SQLEditor/SQLEditor.utils.ts
@@ -7,7 +7,7 @@ import {
} from '@supabase/pg-meta'
import { TABLE_EVENT_ACTIONS } from 'common/telemetry-constants'
-import type { SqlSnippetSource } from './querySource'
+import { isLogsSource, sqlSourceToFenceLanguage, type SqlSnippetSource } from './querySource'
import {
alterDatabasePreventConnectionStatements,
destructiveSqlRegex,
@@ -497,25 +497,46 @@ export function assembleCompletionDiff(
}
/**
- * Builds the request body sent to the AI completion endpoint. `options` is
- * the caller-provided extra fields (e.g. `completionMetadata`), merged in
- * last so it can override the defaults if it ever needs to.
+ * The SQL dialect the AI writes. Mirrors the `dialect` enum the completion API
+ * route accepts — a snippet's dialect follows its source and never flips, so a
+ * logs snippet always gets ClickHouse SQL and a database snippet Postgres.
+ */
+export type SqlDialect = 'postgres' | 'clickhouse'
+
+/**
+ * Maps a snippet's query source to the dialect the AI should write in. Logs
+ * snippets run against the ClickHouse-backed analytics endpoint; everything
+ * else runs against the user's Postgres database.
+ */
+export function sqlSourceToDialect(source: SqlSnippetSource): SqlDialect {
+ return isLogsSource(source) ? 'clickhouse' : 'postgres'
+}
+
+/**
+ * Builds the request body sent to the AI completion endpoint. `dialect` is
+ * omitted when undefined so callers that don't care keep the route's Postgres
+ * default. `options` is the caller-provided extra fields (e.g.
+ * `completionMetadata`), merged in last so it can override the defaults if it
+ * ever needs to.
*/
export function buildCompletionRequestBody({
projectRef,
connectionString,
orgSlug,
+ dialect,
options,
}: {
projectRef: string | undefined
connectionString: string | undefined | null
orgSlug: string | undefined
+ dialect?: SqlDialect
options?: { completionMetadata?: unknown }
}): {
projectRef: string | undefined
connectionString: string | undefined | null
language: 'sql'
orgSlug: string | undefined
+ dialect?: SqlDialect
completionMetadata?: unknown
} {
return {
@@ -523,16 +544,37 @@ export function buildCompletionRequestBody({
connectionString,
language: 'sql',
orgSlug,
+ ...(dialect !== undefined && { dialect }),
...(options ?? {}),
}
}
/**
- * Builds the prompt text used to ask the assistant to debug a failing snippet.
+ * Names the dialect for a logs snippet, whose SQL is ClickHouse against the `logs`
+ * table. The in-app assistant also learns this from the message's `sqlSource`
+ * metadata, but the same text is offered as "Copy prompt" and pasted into external
+ * models, so it has to stand on its own — otherwise a logs error gets Postgres advice.
+ */
+const CLICKHOUSE_LOGS_DEBUG_HINT =
+ 'This query runs against the Supabase logs table on a ClickHouse-backed engine, not Postgres.'
+
+/** The shared ask + error + dialect preamble behind both debug entry points. */
+function buildDebugRequestText(errorMessage: string, source: SqlSnippetSource): string {
+ const ask = `Help me to debug the attached sql snippet which gives the following error: \n\n${errorMessage}`
+ return isLogsSource(source) ? `${ask}\n\n${CLICKHOUSE_LOGS_DEBUG_HINT}` : ask
+}
+
+/**
+ * Builds the prompt text used to ask the assistant to debug a failing snippet, and
+ * offered verbatim as the dropdown's copyable prompt.
*/
-export function buildDebugPromptText(sql: string, errorMessage: string): string {
- const prompt = `Help me to debug the attached sql snippet which gives the following error: \n\n${errorMessage}`
- return `${prompt}\n\nSQL Query:\n\`\`\`sql\n${sql}\n\`\`\``
+export function buildDebugPromptText(
+ sql: string,
+ errorMessage: string,
+ source: SqlSnippetSource
+): string {
+ const fence = sqlSourceToFenceLanguage(source)
+ return `${buildDebugRequestText(errorMessage, source)}\n\nSQL Query:\n\`\`\`${fence}\n${sql}\n\`\`\``
}
// Accepts either brand: the debug flow only reads the SQL as text (it's stripped
@@ -564,13 +606,18 @@ export function extractDebugContext(
*/
export function buildDebugChatArgs(
snippet: DebugSnippet,
- result: DebugResult
-): { name: string; sqlSnippets: string[]; initialInput: string } {
+ result: DebugResult,
+ source: SqlSnippetSource
+): {
+ name: string
+ sqlSnippets: Array<{ label: string; content: string; source: SqlSnippetSource }>
+ initialInput: string
+} {
const { sql, errorMessage } = extractDebugContext(snippet, result)
return {
name: 'Debug SQL snippet',
- sqlSnippets: [sql],
- initialInput: `Help me to debug the attached sql snippet which gives the following error: \n\n${errorMessage}`,
+ sqlSnippets: [{ label: 'Current Query', content: sql, source }],
+ initialInput: buildDebugRequestText(errorMessage, source),
}
}
diff --git a/apps/studio/components/interfaces/SQLEditor/SQLEditorControllers.tsx b/apps/studio/components/interfaces/SQLEditor/SQLEditorControllers.tsx
index 0aa70a05313fc..f4738c230a98e 100644
--- a/apps/studio/components/interfaces/SQLEditor/SQLEditorControllers.tsx
+++ b/apps/studio/components/interfaces/SQLEditor/SQLEditorControllers.tsx
@@ -191,7 +191,7 @@ export const SQLEditorControllersProvider = ({ children }: PropsWithChildren) =>
const isExecuting = isExecutingDb || isExecutingLogs
- const ai = useSqlEditorAi({ id, editorMountCount, diff, prompt })
+ const ai = useSqlEditorAi({ id, editorMountCount, diff, prompt, sqlSource: runSource.type })
const { acceptAiHandler, discardAiHandler } = ai
useSqlEditorShortcuts({
diff --git a/apps/studio/components/interfaces/SQLEditor/SQLEditorEditorPanel.tsx b/apps/studio/components/interfaces/SQLEditor/SQLEditorEditorPanel.tsx
index 149a713f4e540..6215f6580d67a 100644
--- a/apps/studio/components/interfaces/SQLEditor/SQLEditorEditorPanel.tsx
+++ b/apps/studio/components/interfaces/SQLEditor/SQLEditorEditorPanel.tsx
@@ -4,6 +4,7 @@ import dynamic from 'next/dynamic'
import { useCallback } from 'react'
import { cn } from 'ui'
+import { LegacyLogsRewriteBanner } from './LegacyLogsRewriteBanner'
import { useSQLEditorContext } from './SQLEditorContext'
import {
useSqlEditorAssistant,
@@ -171,23 +172,32 @@ const SQLEditorMainView = () => {
)
}
+function LoadingSpinner() {
+ return (
+