diff --git a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.hooks.ts b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.hooks.ts index d751f9673b0..1661458a027 100644 --- a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.hooks.ts +++ b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.hooks.ts @@ -1,18 +1,8 @@ -import { useInfiniteQuery } from '@tanstack/react-query' -import { useParams } from 'next/navigation' -import { useQueryState, useQueryStates } from 'nuqs' +import { useQueryState } from 'nuqs' import { useEffect, useMemo, useRef } from 'react' -import SuperJSON from 'superjson' import { useHotKey } from 'hooks/ui/useHotKey' -import { createApiQueryString } from './QueryOptions' import { SEARCH_PARAMS_PARSER } from './UnifiedLogs.constants' -import { - InfiniteQueryResponse, - PageParam, - UnifiedLogSchema, - UnifiedLogsMeta, -} from './UnifiedLogs.types' export const useResetFocus = () => { useHotKey(() => { @@ -52,84 +42,3 @@ export const useLiveMode = (data: TData[]) => { return { row: anchorRow, timestamp: liveTimestamp.current } } - -// [Joshen] This isn't currently being used - check if can deprecate -export function useUnifiedLogs() { - // Get project ref from URL params - const { ref: projectRef } = useParams<{ ref: string }>() - - // Use your existing search params - const [search, setSearch] = useQueryStates(SEARCH_PARAMS_PARSER) - - // Add log_type to search params if needed - const queryParams = useMemo(() => { - return { - ...search, - // Add any unified logs specific params - } - }, [search]) - - // Create the query - // @ts-ignore - const result = useInfiniteQuery({ - queryKey: ['unified-logs', projectRef, JSON.stringify(queryParams)], - queryFn: async ({ pageParam }) => { - const cursor = pageParam?.cursor ? new Date(pageParam.cursor) : undefined - const direction = pageParam?.direction - - // Construct API params - const apiParams = { - ...queryParams, - uuid: null, // Explicitly remove for API call - live: null, // Explicitly remove for API call - ...(cursor && { cursor }), - ...(direction && { direction }), - } - - // Define endpoint for unified logs - const endpoint = `/api/projects/${projectRef}/logs/unified` - const queryString = createApiQueryString(apiParams) - - const response = await fetch(`${endpoint}${queryString}`) - - if (!response.ok) { - throw new Error('Failed to fetch unified logs') - } - - const jsonString = await response.text() - return SuperJSON.parse>(jsonString) - }, - initialPageParam: { cursor: new Date().getTime(), direction: 'next' } as PageParam, - getPreviousPageParam: (firstPage) => { - if (!firstPage.prevCursor) return null - return { cursor: firstPage.prevCursor, direction: 'prev' } as PageParam - }, - getNextPageParam: (lastPage) => { - if (!lastPage.nextCursor) return null - return { cursor: lastPage.nextCursor, direction: 'next' } as PageParam - }, - refetchOnWindowFocus: false, - }) - - // Helper functions for the unified logs - const addLogTypeFilter = (logType: UnifiedLogSchema['log_type']) => { - const currentLogTypes = search.log_type || [] - setSearch({ - log_type: [...currentLogTypes, logType], - }) - } - - const removeLogTypeFilter = (logType: UnifiedLogSchema['log_type']) => { - const currentLogTypes = search.log_type || [] - setSearch({ - log_type: currentLogTypes.filter((type) => type !== logType), - }) - } - - // Return query results and helper functions - return { - ...result, - addLogTypeFilter, - removeLogTypeFilter, - } -} diff --git a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx index efadc189a1c..754cdeae771 100644 --- a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx +++ b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx @@ -85,6 +85,7 @@ export const UnifiedLogsTable = () => { [] ) + // [Joshen] This needs to move to the data folder to follow our proper RQ structure const { data, isFetching, isLoading, fetchNextPage, hasNextPage, fetchPreviousPage, refetch } = // @ts-ignore useInfiniteQuery(dataOptions(search, projectRef ?? '')) diff --git a/apps/studio/components/ui/DataTable/DataTableFilters/DataTableFilterCommand.tsx b/apps/studio/components/ui/DataTable/DataTableFilters/DataTableFilterCommand.tsx index 977b98aabd3..b29d2410f19 100644 --- a/apps/studio/components/ui/DataTable/DataTableFilters/DataTableFilterCommand.tsx +++ b/apps/studio/components/ui/DataTable/DataTableFilters/DataTableFilterCommand.tsx @@ -321,26 +321,23 @@ export function DataTableFilterCommand({ searchParamsParser }: DataTableFilterCo No results found. -
+
- Use ↑ ↓ to navigate + Use ↑ ↓ to navigate - Enter to query + Enter to query - Esc to close + Esc to close - Union: regions:a,b + Union: regions:a,b - Range: p95:59-340 + Range: p95:59-340
{lastSearches.length ? ( diff --git a/apps/studio/components/ui/DataTable/DataTableSheetDetails.tsx b/apps/studio/components/ui/DataTable/DataTableSheetDetails.tsx index 972df2a633c..922d38bc3ee 100644 --- a/apps/studio/components/ui/DataTable/DataTableSheetDetails.tsx +++ b/apps/studio/components/ui/DataTable/DataTableSheetDetails.tsx @@ -93,7 +93,7 @@ export function DataTableSheetDetails({

- Navigate ↑ + Navigate ↑

@@ -112,7 +112,7 @@ export function DataTableSheetDetails({

- Navigate ↓ + Navigate ↓

diff --git a/apps/studio/components/ui/DataTable/DatePickerWithRange.tsx b/apps/studio/components/ui/DataTable/DatePickerWithRange.tsx index 7dd0013b814..18354bd7415 100644 --- a/apps/studio/components/ui/DataTable/DatePickerWithRange.tsx +++ b/apps/studio/components/ui/DataTable/DatePickerWithRange.tsx @@ -24,7 +24,7 @@ import { import { presets as defaultPresets } from './DataTable.constants' import type { DatePreset } from './DataTable.types' import { useDebounce } from './hooks/useDebounce' -import { kbdVariants } from './primitives/Kbd' +import { kdbClassName } from './primitives/Kbd' interface DatePickerWithRangeProps extends HTMLAttributes { date: DateRange | undefined @@ -129,11 +129,10 @@ function DatePresets({ size="small" onClick={() => onSelect({ from, to })} className="text-left" - // className={cn(!isActive && 'border border-transparent')} >
{label} - {shortcut} + {shortcut}
) @@ -187,7 +186,7 @@ function DatePresetsSelect({ className="flex items-center justify-between [&>span:last-child]:flex [&>span:last-child]:w-full [&>span:last-child]:justify-between" > {label} - + {shortcut} diff --git a/apps/studio/components/ui/DataTable/primitives/DatePickerWithRange.tsx b/apps/studio/components/ui/DataTable/primitives/DatePickerWithRange.tsx index 291b4e916cd..ecf10e81396 100644 --- a/apps/studio/components/ui/DataTable/primitives/DatePickerWithRange.tsx +++ b/apps/studio/components/ui/DataTable/primitives/DatePickerWithRange.tsx @@ -24,7 +24,7 @@ import { import { presets as defaultPresets } from '../DataTable.constants' import type { DatePreset } from '../DataTable.types' import { useDebounce } from '../hooks/useDebounce' -import { kbdVariants } from './Kbd' +import { kdbClassName } from './Kbd' interface DatePickerWithRangeProps extends HTMLAttributes { date: DateRange | undefined @@ -132,7 +132,7 @@ function DatePresets({ >
{label} - {shortcut} + {shortcut}
) @@ -186,7 +186,7 @@ function DatePresetsSelect({ className="flex items-center justify-between [&>span:last-child]:flex [&>span:last-child]:w-full [&>span:last-child]:justify-between" > {label} - + {shortcut} diff --git a/apps/studio/components/ui/DataTable/primitives/Kbd.tsx b/apps/studio/components/ui/DataTable/primitives/Kbd.tsx index 3b169c6540d..550bed2e290 100644 --- a/apps/studio/components/ui/DataTable/primitives/Kbd.tsx +++ b/apps/studio/components/ui/DataTable/primitives/Kbd.tsx @@ -1,51 +1,21 @@ // Copy Pasta from: https://github.com/sadmann7/shadcn-table/blob/main/src/components/kbd.tsx#L54 -import { type VariantProps, cva } from 'class-variance-authority' -import { forwardRef } from 'react' +import { ComponentPropsWithoutRef, forwardRef } from 'react' import { cn } from 'ui' -export const kbdVariants = cva( +export const kdbClassName = cn( 'select-none rounded border px-1.5 py-px font-mono text-[0.7rem] font-normal font-mono shadow-sm disabled:opacity-50', - { - variants: { - variant: { - default: 'bg-accent text-accent-foreground', - outline: 'bg-background text-foreground', - }, - }, - defaultVariants: { - variant: 'default', - }, - } + 'bg-background text-foreground' ) -export interface KbdProps - extends React.ComponentPropsWithoutRef<'kbd'>, - VariantProps { - /** - * The title of the `abbr` element inside the `kbd` element. - * @default undefined - * @type string | undefined - * @example title="Command" - */ - abbrTitle?: string -} - -const Kbd = forwardRef( - ({ abbrTitle, children, className, variant, ...props }, ref) => { +export const Kbd = forwardRef>( + ({ children, className, ...props }, ref) => { return ( - - {abbrTitle ? ( - - {children} - - ) : ( - children - )} + + {children} ) } ) -Kbd.displayName = 'Kbd' -export { Kbd } +Kbd.displayName = 'Kbd' diff --git a/apps/studio/hooks/analytics/useLogsPreview.tsx b/apps/studio/hooks/analytics/useLogsPreview.tsx index 9adefd316d6..6cce624ec51 100644 --- a/apps/studio/hooks/analytics/useLogsPreview.tsx +++ b/apps/studio/hooks/analytics/useLogsPreview.tsx @@ -1,6 +1,6 @@ import { useInfiniteQuery, useQuery } from '@tanstack/react-query' import dayjs from 'dayjs' -import { useMemo, useState, useCallback } from 'react' +import { useCallback, useMemo, useState } from 'react' import { LogsTableName, @@ -22,8 +22,8 @@ import { genDefaultQuery, } from 'components/interfaces/Settings/Logs/Logs.utils' import { get } from 'data/fetchers' -import { useLogsUrlState } from './useLogsUrlState' import { useFillTimeseriesSorted } from './useFillTimeseriesSorted' +import { useLogsUrlState } from './useLogsUrlState' import useTimeseriesUnixToIso from './useTimeseriesUnixToIso' interface LogsPreviewHook { @@ -92,10 +92,6 @@ function useLogsPreview({ const queryKey = useMemo(() => ['projects', projectRef, 'logs', params], [projectRef, params]) - console.log('table:', table) - - console.log('useLogsPreview SQL:', params.sql) - const { data, isSuccess, @@ -151,17 +147,10 @@ function useLogsPreview({ } }) - // Log unified logs data for debugging - if (table === 'unified_logs' && logData.length > 0) { - console.log('Unified Logs Data:', logData) - console.log('Sample log record:', logData[0]) - console.log('Sample log record metadata:', logData[0]?.metadata) - } - const oldestTimestamp = logData.length > 0 ? logData[logData.length - 1]?.timestamp : undefined return { logData, error, oldestTimestamp } - }, [data?.pages, table]) + }, [data?.pages]) const countQuerySql = useMemo(() => genCountQuery(table, mergedFilters), [table, mergedFilters]) const countQueryKey = useMemo( diff --git a/apps/studio/hooks/analytics/useUnifiedLogs.tsx b/apps/studio/hooks/analytics/useUnifiedLogs.tsx deleted file mode 100644 index 91c8c3af811..00000000000 --- a/apps/studio/hooks/analytics/useUnifiedLogs.tsx +++ /dev/null @@ -1,291 +0,0 @@ -import { useInfiniteQuery, useQuery } from '@tanstack/react-query' -import dayjs from 'dayjs' -import { useMemo, useState, useCallback } from 'react' - -import { - LogsTableName, - PREVIEWER_DATEPICKER_HELPERS, - getDefaultHelper, -} from 'components/interfaces/Settings/Logs/Logs.constants' -import type { - Count, - EventChart, - EventChartData, - Filters, - LogData, - Logs, - LogsEndpointParams, -} from 'components/interfaces/Settings/Logs/Logs.types' -import { - genChartQuery, - genCountQuery, - genDefaultQuery, -} from 'components/interfaces/Settings/Logs/Logs.utils' -import { get } from 'data/fetchers' -import { useLogsUrlState } from './useLogsUrlState' -import { useFillTimeseriesSorted } from './useFillTimeseriesSorted' -import useTimeseriesUnixToIso from './useTimeseriesUnixToIso' - -interface UnifiedLogsHook { - logData: LogData[] - error: string | Object | null - newCount: number - isSuccess: boolean - isLoading: boolean - isLoadingOlder: boolean - filters: Filters - params: LogsEndpointParams - oldestTimestamp?: string - eventChartData: EventChartData[] - loadOlder: () => void - refresh: () => void -} - -function useUnifiedLogs({ - projectRef, - filterOverride, - limit, -}: { - projectRef: string - filterOverride?: Filters - limit?: number -}): UnifiedLogsHook { - const defaultHelper = getDefaultHelper(PREVIEWER_DATEPICKER_HELPERS) - const [latestRefresh, setLatestRefresh] = useState(new Date().toISOString()) - - const { - timestampStart: urlTimestampStart, - timestampEnd: urlTimestampEnd, - filters: urlFilters, - search, - } = useLogsUrlState() - - const timestampStart = useMemo( - () => urlTimestampStart || defaultHelper.calcFrom(), - [urlTimestampStart, defaultHelper] - ) - const timestampEnd = useMemo( - () => urlTimestampEnd || defaultHelper.calcTo(), - [urlTimestampEnd, defaultHelper] - ) - - const mergedFilters = useMemo( - () => ({ - ...urlFilters, - ...filterOverride, - ...(search ? { search_query: search } : {}), - }), - [JSON.stringify(urlFilters), JSON.stringify(filterOverride), search] - ) - - const params: LogsEndpointParams = useMemo(() => { - const currentSql = genDefaultQuery(LogsTableName.UNIFIED, mergedFilters, limit) - return { - project: projectRef, - iso_timestamp_start: timestampStart, - iso_timestamp_end: timestampEnd, - sql: currentSql, - } - }, [projectRef, timestampStart, timestampEnd, mergedFilters, limit]) - - const queryKey = useMemo( - () => ['projects', projectRef, 'unified-logs', params], - [projectRef, params] - ) - - console.log('useUnifiedLogs SQL:', params.sql) - - const { - data, - isSuccess, - isLoading, - isRefetching, - error: rqError, - fetchNextPage, - isFetchingNextPage, - refetch, - } = useInfiniteQuery( - queryKey, - async ({ signal, pageParam }) => { - const { data, error } = await get(`/platform/projects/{ref}/analytics/endpoints/logs.all`, { - params: { - path: { ref: projectRef }, - query: { - ...params, - iso_timestamp_end: pageParam || params.iso_timestamp_end, - }, - }, - signal, - }) - if (error) { - throw error - } - - return data as unknown as Logs - }, - { - refetchOnWindowFocus: false, - getNextPageParam(lastPage) { - if ((lastPage.result?.length ?? 0) === 0) { - return undefined - } - const len = lastPage.result.length - const { timestamp: tsLimit }: LogData = lastPage.result[len - 1] - const isoTsLimit = dayjs.utc(Number(tsLimit / 1000)).toISOString() - return isoTsLimit - }, - } - ) - - const { logData, error, oldestTimestamp } = useMemo(() => { - let logData: LogData[] = [] - let error: null | string | object = rqError ? (rqError as any).message : null - - data?.pages?.forEach((response) => { - if (response?.result) { - logData = [...logData, ...response.result] - } - if (!error && response?.error) { - error = response.error - } - }) - - // Log unified logs data for debugging - if (logData.length > 0) { - console.log('Unified Logs Data Sample:', logData.slice(0, 1)) - } - - const oldestTimestamp = logData.length > 0 ? logData[logData.length - 1]?.timestamp : undefined - - return { logData, error, oldestTimestamp } - }, [data?.pages]) - - const countQuerySql = useMemo( - () => genCountQuery(LogsTableName.UNIFIED, mergedFilters), - [mergedFilters] - ) - const countQueryKey = useMemo( - () => [ - 'projects', - projectRef, - 'unified-logs-count', - { - projectRef, - sql: countQuerySql, - iso_timestamp_start: latestRefresh, - iso_timestamp_end: timestampEnd, - mergedFilters, - }, - ], - [projectRef, countQuerySql, latestRefresh, timestampEnd, mergedFilters] - ) - - const { data: countData } = useQuery( - countQueryKey, - async ({ signal }) => { - const { data, error } = await get(`/platform/projects/{ref}/analytics/endpoints/logs.all`, { - params: { - path: { ref: projectRef }, - query: { - project: projectRef, - sql: countQuerySql, - iso_timestamp_start: latestRefresh, - iso_timestamp_end: timestampEnd, - }, - }, - signal, - }) - if (error) { - throw error - } - - return data as unknown as Count - }, - { - refetchOnWindowFocus: false, - refetchInterval: 60000, - enabled: !error && data && data?.pages?.length > 0 ? true : false, - } - ) - - const newCount = countData?.result?.[0]?.count ?? 0 - - const chartQuery = useMemo( - () => genChartQuery(LogsTableName.UNIFIED, params, mergedFilters), - [params, mergedFilters] - ) - const chartQueryKey = useMemo( - () => [ - 'projects', - projectRef, - 'unified-logs-chart', - { - projectRef, - sql: chartQuery, - iso_timestamp_start: timestampStart, - iso_timestamp_end: timestampEnd, - }, - ], - [projectRef, chartQuery, timestampStart, timestampEnd] - ) - - const { data: eventChartResponse, refetch: refreshEventChart } = useQuery( - chartQueryKey, - async ({ signal }) => { - const { data, error } = await get(`/platform/projects/{ref}/analytics/endpoints/logs.all`, { - params: { - path: { ref: projectRef }, - query: { - iso_timestamp_start: timestampStart, - iso_timestamp_end: timestampEnd, - project: projectRef, - sql: chartQuery, - }, - }, - signal, - }) - if (error) { - throw error - } - - return data as unknown as EventChart - }, - { refetchOnWindowFocus: false } - ) - - const refresh = useCallback(async () => { - setLatestRefresh(new Date().toISOString()) - refreshEventChart() - refetch() - }, [refetch, refreshEventChart]) - - const normalizedEventChartData = useTimeseriesUnixToIso( - eventChartResponse?.result ?? [], - 'timestamp' - ) - - const { data: eventChartData, error: eventChartError } = useFillTimeseriesSorted( - normalizedEventChartData, - 'timestamp', - 'count', - 0, - timestampStart, - timestampEnd || new Date().toISOString() - ) - - return { - newCount, - logData, - isSuccess, - isLoading: isLoading || isRefetching, - isLoadingOlder: isFetchingNextPage, - error: error || eventChartError, - filters: mergedFilters, - params, - oldestTimestamp: oldestTimestamp ? String(oldestTimestamp) : undefined, - eventChartData, - refresh, - loadOlder: () => fetchNextPage(), - } -} -export default useUnifiedLogs diff --git a/apps/studio/middleware.ts b/apps/studio/middleware.ts index ca470aeaed3..8debcfdb5ee 100644 --- a/apps/studio/middleware.ts +++ b/apps/studio/middleware.ts @@ -17,7 +17,6 @@ const HOSTED_SUPPORTED_API_URLS = [ '/get-utc-time', '/edge-functions/test', '/edge-functions/body', - '/api/data-table/light', ] export function middleware(request: NextRequest) {