Files
supabase/apps/studio/data/content/content-query.ts
Charis 8bdfe03fe7 refactor(studio): drop notebook type widening now that the API supports it (#49272)
## Summary

- Regenerates `packages/api-types` for the content endpoints now that
the Platform API's `notebook` content type has landed (list/get/upsert
`type` enums, plus `UpsertContentBody`'s notebook cell shape with
`_id`/`y_series`). Unrelated schema drift from the same regen
(Warehouse, SSO, notification exceptions, etc.) is excluded — only the
content-endpoint hunks are applied.
- Removes every local widening cast added while the API support was
pending (`content-query.ts`, `content-infinite-query.ts`,
`notebook-query.ts`, `notebook-upsert-mutation.ts`,
`sql-folders-query.ts`).
- What remains is scoped and renamed to match: draft ids
(`generateDraftId`/`isDraftId`), used only for cells created client-side
in the editor before their first save, dropped before they'd ever reach
the backend as a fake `_id`.

## Test plan

- [x] `pnpm typecheck` — clean
- [x] `pnpm --filter studio test` — full suite passes (518 files / 5471
tests)
- [x] `pnpm --filter studio run lint:ratchet` — no new warnings
- [x] `pnpm format` / prettier — clean

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved notebook cell tracking during editing, reordering, insertion,
and deletion.
* Preserved existing cell identifiers while removing temporary draft
identifiers before saving.
* Improved chart configuration for selecting and displaying multiple
Y-axis series.
  * Strengthened notebook validation and content persistence behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-08-20 13:06:41 +08:00

91 lines
2.5 KiB
TypeScript

import { useQuery } from '@tanstack/react-query'
import { components } from 'api-types'
import { remapSqlContentFields } from './content-remap'
import { contentKeys } from './keys'
import { get, handleError } from '@/data/fetchers'
import type {
Dashboards,
LogSqlSnippets,
Notebooks,
SqlSnippets,
UseCustomQueryOptions,
} from '@/types'
export type ContentBase = components['schemas']['GetUserContentResponse']['data'][number]
export type Content = Omit<ContentBase, 'content' | 'type'> &
(
| {
type: 'sql'
content: SqlSnippets.Content
}
| {
type: 'report'
content: Dashboards.Content
}
| {
type: 'log_sql'
content: LogSqlSnippets.Content
}
| {
type: 'notebook'
content: Notebooks.Content
}
)
export type ContentType = Content['type']
// Narrows the full Content union down to a single content type — for call sites that already
// know (from the `type` they queried with) which member they're holding, since useContentQuery
// et al. don't parameterize their return type by the `type` argument.
export type ContentOfType<T extends ContentType> = Extract<Content, { type: T }>
interface GetContentVariables {
projectRef?: string
type: ContentType
name?: string
limit?: number
}
export async function getContent(
{ projectRef, type, name, limit = 10 }: GetContentVariables,
signal?: AbortSignal,
headers?: HeadersInit
) {
if (typeof projectRef === 'undefined') {
throw new Error('projectRef is required for getContent')
}
const { data, error } = await get('/platform/projects/{ref}/content', {
params: {
path: { ref: projectRef },
query: { type, name, limit: limit.toString() },
},
headers,
signal,
})
if (error) handleError(error)
return {
cursor: data.cursor,
content: remapSqlContentFields(data.data as unknown as Content[]),
}
}
export type ContentData = Awaited<ReturnType<typeof getContent>>
export type ContentError = unknown
/** @deprecated Use useContentInfiniteQuery from content-infinite-query instead */
export const useContentQuery = <TData = ContentData>(
{ projectRef, type, name, limit }: GetContentVariables,
{ enabled = true, ...options }: UseCustomQueryOptions<ContentData, ContentError, TData> = {}
) =>
useQuery<ContentData, ContentError, TData>({
queryKey: contentKeys.list(projectRef, { type, name, limit }),
queryFn: ({ signal }) => getContent({ projectRef, type, name, limit }, signal),
enabled: enabled && typeof projectRef !== 'undefined',
...options,
})