Files
supabase/apps/studio/hooks/analytics/useLogsQuery.tsx
Joshen Lim 944c5862f3 Chore/small refactors (#47740)
## Context

Just extracting the fixes which I think are applicable from this
[PR](https://github.com/supabase/supabase/pull/47695)

Main files are
- `apps/studio/hooks/analytics/useLogsQuery.tsx`
- `packages/common/auth.tsx`
- `packages/common/feature-flags.tsx`

## Changes involved
- Adjust `useLogsQuery` to accept an object as prop, rather than 4
individual params
- This one doesn't address any Sentry issues, but is just a improvement
to the function's API imo, more readable
- Adjust how user email is retrieved in `feature-flags`
- Related Sentry issue
[here](https://supabase.sentry.io/issues/7592718607/?project=5459134)
- The error is a bit vague, but Claude's attempt to fix looks alright in
general IMO
  - Minimally verified that feature flags are loading as expected still

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

## Summary by CodeRabbit

* **Bug Fixes**
* Improved log-related screens and queries for more reliable loading and
filtering across the app.
* Fixed profile and account data handling so identity details are
retrieved more consistently.
* Improved authentication handling to better recognize missing user data
and keep the app stable.
* Updated feature flag personalization to use more accurate account
information.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-08 23:21:48 +08:00

146 lines
4.2 KiB
TypeScript

import { useQuery } from '@tanstack/react-query'
import { IS_PLATFORM } from 'common'
import { Dispatch, SetStateAction, useEffect, useState } from 'react'
import {
EXPLORER_DATEPICKER_HELPERS,
getDefaultHelper,
} from '@/components/interfaces/Settings/Logs/Logs.constants'
import type {
LogData,
Logs,
LogsEndpointParams,
} from '@/components/interfaces/Settings/Logs/Logs.types'
import {
checkForILIKEClause,
checkForWithClause,
} from '@/components/interfaces/Settings/Logs/Logs.utils'
import { get } from '@/data/fetchers'
import { logsAllEndpointUrl } from '@/data/logs/logs-endpoint'
import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
import { DOCS_URL } from '@/lib/constants'
export interface LogsQueryHook {
params: LogsEndpointParams
isLoading: boolean
logData: LogData[]
data?: never
error: string | Object | null
changeQuery: (newQuery?: string) => void
runQuery: () => void
setParams: Dispatch<SetStateAction<LogsEndpointParams>>
enabled?: boolean
}
export const useLogsQuery = ({
projectRef,
initialParams = {},
enabled = true,
options = {},
}: {
projectRef?: string
initialParams?: Partial<LogsEndpointParams>
enabled?: boolean
options?: { useOtel?: boolean }
}): LogsQueryHook => {
const { useOtel = false } = options
const defaultHelper = getDefaultHelper(EXPLORER_DATEPICKER_HELPERS)
const [params, setParams] = useState<LogsEndpointParams>({
sql: initialParams?.sql || '',
iso_timestamp_start: initialParams.iso_timestamp_start
? initialParams.iso_timestamp_start
: defaultHelper.calcFrom(),
iso_timestamp_end: initialParams.iso_timestamp_end
? initialParams.iso_timestamp_end
: defaultHelper.calcTo(),
})
const { logsMetadata } = useIsFeatureEnabled(['logs:metadata'])
useEffect(() => {
setParams((prev) => ({
...prev,
...initialParams,
sql: initialParams?.sql ?? prev.sql,
iso_timestamp_start: initialParams.iso_timestamp_start ?? prev.iso_timestamp_start,
iso_timestamp_end: initialParams.iso_timestamp_end ?? prev.iso_timestamp_end,
}))
}, [initialParams.sql, initialParams.iso_timestamp_start, initialParams.iso_timestamp_end])
const _enabled = enabled && typeof projectRef !== 'undefined' && Boolean(params.sql)
const usesWith = checkForWithClause(params.sql || '')
const usesILIKE = checkForILIKEClause(params.sql || '')
const {
data,
error: rqError,
isPending: isLoading,
isRefetching,
refetch,
} = useQuery({
queryKey: ['projects', projectRef, 'logs', params, { otel: useOtel }],
queryFn: async ({ signal }) => {
const { data, error } = await get(logsAllEndpointUrl(useOtel), {
params: {
path: { ref: projectRef! },
query: params,
},
signal,
})
if (error) {
throw error
}
return data as unknown as Logs
},
enabled: _enabled,
refetchOnWindowFocus: false,
})
let error: null | string | object = rqError ? (rqError as any).message : null
if (!error && data?.error) {
error = data?.error
}
// BigQuery-specific parser limitations don't apply to the ClickHouse-backed
// OTEL endpoint, so skip these warnings when querying it.
if (IS_PLATFORM && !useOtel) {
if (usesWith) {
error = {
message: 'The parser does not yet support WITH and subquery statements.',
docs: `${DOCS_URL}/guides/platform/advanced-log-filtering#the-with-keyword-and-subqueries-are-not-supported`,
}
}
if (usesILIKE) {
error = {
message: 'BigQuery does not support ILIKE. Use REGEXP_CONTAINS instead.',
docs: `${DOCS_URL}/guides/platform/advanced-log-filtering#the-ilike-and-similar-to-keywords-are-not-supported`,
}
}
}
const changeQuery = (newQuery = '') => {
setParams((prev) => ({ ...prev, sql: newQuery }))
}
const logData = (data?.result ?? []).map((x) => {
if (logsMetadata) {
return x
} else {
const { metadata, ...log } = x
return log
}
})
return {
params,
isLoading: (_enabled && isLoading) || isRefetching,
logData: logData,
error,
changeQuery,
runQuery: () => refetch(),
setParams,
}
}