import { Rewind } from 'lucide-react' import { useRouter } from 'next/router' import { PropsWithChildren, useEffect, useState } from 'react' import { useParams } from 'common' import PreviewFilterPanel from 'components/interfaces/Settings/Logs/PreviewFilterPanel' import LoadingOpacity from 'components/ui/LoadingOpacity' import ShimmerLine from 'components/ui/ShimmerLine' import { useReadReplicasQuery } from 'data/read-replicas/replicas-query' import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' import useLogsPreview from 'hooks/analytics/useLogsPreview' import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' import { useUpgradePrompt } from 'hooks/misc/useUpgradePrompt' import { useDatabaseSelectorStateSnapshot } from 'state/database-selector' import { Button, cn } from 'ui' import LogEventChart from './LogEventChart' import LogTable from './LogTable' import { LOGS_TABLES, LOG_ROUTES_WITH_REPLICA_SUPPORT, LogsTableName } from './Logs.constants' import type { Filters, LogSearchCallback, LogTemplate, QueryType } from './Logs.types' import { ensureNoTimestampConflict, maybeShowUpgradePrompt } from './Logs.utils' import UpgradePrompt from './UpgradePrompt' import { useSelectedLog } from 'hooks/analytics/useSelectedLog' import useSingleLog from 'hooks/analytics/useSingleLog' /** * Acts as a container component for the entire log display * * ## Query Params Syncing * Query params are synced on query submission. * * params used are: * - `s` for search query. * - `te` for timestamp start value. */ interface LogsPreviewerProps { projectRef: string queryType: QueryType filterOverride?: Filters condensedLayout?: boolean tableName?: LogsTableName EmptyState?: React.ReactNode } export const LogsPreviewer = ({ projectRef, queryType, filterOverride, condensedLayout = false, tableName, children, EmptyState, }: PropsWithChildren) => { const router = useRouter() const { s, ite, its, db } = useParams() const [showChart, setShowChart] = useState(true) const organization = useSelectedOrganization() const state = useDatabaseSelectorStateSnapshot() const { data: databases, isSuccess } = useReadReplicasQuery({ projectRef }) const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug }) const table = !tableName ? LOGS_TABLES[queryType] : tableName const { error, logData, params, newCount, filters, isLoading, eventChartData, isLoadingOlder, loadOlder, setFilters, refresh, setParams, } = useLogsPreview({ projectRef, table, filterOverride }) const [selectedLogId, setSelectedLogId] = useSelectedLog() const { data: selectedLog, isLoading: isSelectedLogLoading, error: selectedLogError, } = useSingleLog({ projectRef, id: selectedLogId ?? undefined, queryType, paramsToMerge: params, }) const { showUpgradePrompt, setShowUpgradePrompt } = useUpgradePrompt( params.iso_timestamp_start as string ) useEffect(() => { setFilters((prev) => ({ ...prev, search_query: s, database: db, })) if (ite || its) { setParams((prev) => ({ ...prev, iso_timestamp_start: its || '', iso_timestamp_end: ite || '', })) } }, [db, s, ite, its]) // Show the prompt on page load based on query params useEffect(() => { if (its) { const shouldShowUpgradePrompt = maybeShowUpgradePrompt(its as string, subscription?.plan?.id) if (shouldShowUpgradePrompt) { setShowUpgradePrompt(!showUpgradePrompt) } } }, [its, subscription]) useEffect(() => { if (db !== undefined) { const database = databases?.find((d) => d.identifier === db) if (database !== undefined) state.setSelectedDatabaseId(db) } else if (state.selectedDatabaseId !== undefined && state.selectedDatabaseId !== projectRef) { if (LOG_ROUTES_WITH_REPLICA_SUPPORT.includes(router.pathname)) { router.push({ pathname: router.pathname, query: { ...router.query, db: state.selectedDatabaseId }, }) } else { state.setSelectedDatabaseId(projectRef) } } }, [db, isSuccess]) const onSelectTemplate = (template: LogTemplate) => { setFilters((prev: any) => ({ ...prev, search_query: template.searchString })) } const handleRefresh = () => { refresh() router.push({ pathname: router.pathname, query: { ...router.query, ite: undefined, its: undefined, // ...whereFilters, }, }) } const handleSearch: LogSearchCallback = async (event, { query, to, from }) => { if (event === 'search-input-change') { setFilters((prev) => ({ ...prev, search_query: query })) router.push({ pathname: router.pathname, query: { ...router.query, s: query }, }) } else if (event === 'event-chart-bar-click') { const [nextStart, nextEnd] = ensureNoTimestampConflict( [params.iso_timestamp_start || '', params.iso_timestamp_end || ''], [from || '', to || ''] ) setParams((prev) => ({ ...prev, iso_timestamp_start: nextStart, iso_timestamp_end: nextEnd, })) router.push({ pathname: router.pathname, query: { ...router.query, its: nextStart, ite: nextEnd, }, }) } else if (event === 'datepicker-change') { const shouldShowUpgradePrompt = maybeShowUpgradePrompt(from, subscription?.plan?.id) if (shouldShowUpgradePrompt) { setShowUpgradePrompt(!showUpgradePrompt) } else { setParams((prev) => ({ ...prev, iso_timestamp_start: from || '', iso_timestamp_end: to || '', })) router.push({ pathname: router.pathname, query: { ...router.query, its: from || '', ite: to || '', }, }) } } } return (
setShowChart(!showChart)} onSelectedDatabaseChange={(id: string) => { setFilters((prev) => ({ ...prev, database: id !== projectRef ? undefined : id, })) const { db, ...params } = router.query router.push({ pathname: router.pathname, query: id !== projectRef ? { ...router.query, db: id } : params, }) }} /> {children}
0 ? 'mb-4 h-28 opacity-100' : 'h-0 opacity-0') } >
{showChart && ( { handleSearch('event-chart-bar-click', { query: filters.search_query as string, to: isoTimestamp as string, from: null, }) }} /> )}
setShowChart(!showChart)} error={error} EmptyState={EmptyState} onSelectedLogChange={(log) => setSelectedLogId(log?.id ?? null)} selectedLog={selectedLog} isSelectedLogLoading={isSelectedLogLoading} selectedLogError={selectedLogError ?? undefined} />
{!error && logData.length > 0 && (
Showing {logData.length} results
)}
) } export default LogsPreviewer