import { IS_PLATFORM, useParams } from 'common' import { ChevronRight, Plus } from 'lucide-react' import Link from 'next/link' import { useRouter } from 'next/router' import React, { useState } from 'react' import { Button, cn, Collapsible, CollapsibleContent, CollapsibleTrigger, Separator } from 'ui' import { InnerSideBarEmptyPanel, InnerSideBarFilters, InnerSideBarFilterSearchInput, InnerSideMenuItem, } from 'ui-patterns/InnerSideMenu' import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader' import { FeaturePreviewSidebarPanel } from '../../ui/FeaturePreviewSidebarPanel' import { useIsETLPrivateAlpha } from '@/components/interfaces/Database/Replication/useIsETLPrivateAlpha' import { LOG_DRAIN_TYPES } from '@/components/interfaces/LogDrains/LogDrains.constants' import { SavedQueriesItem } from '@/components/interfaces/Settings/Logs/Logs.SavedQueriesItem' import { LogsSidebarItem } from '@/components/interfaces/Settings/Logs/SidebarV2/SidebarItem' import { UnifiedLogsBanner } from '@/components/interfaces/UnifiedLogs/UnifiedLogsBanner' import { ButtonTooltip } from '@/components/ui/ButtonTooltip' import { useContentQuery } from '@/data/content/content-query' import { useReplicationSourcesQuery } from '@/data/replication/sources-query' import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements' import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled' import { useShowMultigresLogs } from '@/hooks/misc/useShowMultigresLogs' import { useShowPostgresUpgradeLogs } from '@/hooks/misc/useShowPostgresUpgradeLogs' export function SidebarCollapsible({ children, title, defaultOpen, }: { children: React.ReactNode title: string defaultOpen?: boolean }) { return ( {title} {children} ) } export function LogsSidebarMenuV2() { const router = useRouter() const { ref } = useParams() as { ref: string } const [searchText, setSearchText] = useState('') const { projectAuthAll: authEnabled, projectStorageAll: storageEnabled, realtimeAll: realtimeEnabled, logsTemplates: templatesEnabled, logsCollections: collectionsEnabled, } = useIsFeatureEnabled([ 'project_storage:all', 'project_auth:all', 'realtime:all', 'logs:templates', 'logs:collections', ]) const enablePgReplicate = useIsETLPrivateAlpha() const { data: etlData, isPending: isETLLoading } = useReplicationSourcesQuery( { projectRef: ref, }, { enabled: enablePgReplicate, retry: false, refetchOnMount: false, refetchOnWindowFocus: false, } ) // [Jordi] We only want to show ETL logs if the user has the feature enabled AND they're using the feature aka they've created a source. const showETLLogs = enablePgReplicate && (etlData?.sources?.length ?? 0) > 0 && !isETLLoading const { hasAccess: hasDedicatedPooler } = useCheckEntitlements('dedicated_pooler') const showMultigresLogs = useShowMultigresLogs() const showPostgresUpgradeLogs = useShowPostgresUpgradeLogs() const { data: savedQueriesRes, isPending: savedQueriesLoading } = useContentQuery({ projectRef: ref, type: 'log_sql', }) const savedQueries = [...(savedQueriesRes?.content ?? [])] .filter((c) => c.type === 'log_sql') .sort((a, b) => a.name.localeCompare(b.name)) function isActive(path: string) { return router.asPath.includes(path) } const BASE_COLLECTIONS = [ { name: 'API Gateway', key: 'edge-logs', url: `/project/${ref}/logs/edge-logs`, items: [], }, { name: 'Postgres', key: 'postgres-logs', url: `/project/${ref}/logs/postgres-logs`, items: [], }, { name: 'PostgREST', key: 'postgrest-logs', url: `/project/${ref}/logs/postgrest-logs`, items: [], }, IS_PLATFORM ? { name: hasDedicatedPooler ? 'Shared Pooler' : 'Pooler', key: 'pooler-logs', url: `/project/${ref}/logs/pooler-logs`, items: [], } : null, hasDedicatedPooler && IS_PLATFORM ? { name: 'Dedicated Pooler', key: 'dedicated-pooler-logs', url: `/project/${ref}/logs/dedicated-pooler-logs`, items: [], } : null, authEnabled ? { name: 'Auth', key: 'auth-logs', url: `/project/${ref}/logs/auth-logs`, items: [], } : null, storageEnabled ? { name: 'Storage', key: 'storage-logs', url: `/project/${ref}/logs/storage-logs`, items: [], } : null, realtimeEnabled ? { name: 'Realtime', key: 'realtime-logs', url: `/project/${ref}/logs/realtime-logs`, items: [], } : null, { name: 'Edge Functions', key: 'edge-functions-logs', url: `/project/${ref}/logs/edge-functions-logs`, items: [], }, { name: 'Cron', key: 'pg_cron', url: `/project/${ref}/logs/pgcron-logs`, items: [], }, showETLLogs ? { name: 'Replication', key: 'replication_logs', url: `/project/${ref}/logs/replication-logs`, items: [], } : null, showMultigresLogs ? { name: 'Multigres', key: 'multigres-logs', url: `/project/${ref}/logs/multigres-logs`, items: [], } : null, ].filter((x) => x !== null) const OPERATIONAL_COLLECTIONS = IS_PLATFORM && showPostgresUpgradeLogs ? [ { name: 'Postgres Version Upgrade', key: 'pg-upgrade-logs', url: `/project/${ref}/logs/pg-upgrade-logs`, items: [], }, ] : [] const filteredLogs = BASE_COLLECTIONS.filter((collection) => { return collection?.name.toLowerCase().includes(searchText.toLowerCase()) }) const filteredOperationalLogs = OPERATIONAL_COLLECTIONS.filter((collection) => { return collection?.name.toLowerCase().includes(searchText.toLowerCase()) }) return (
setSearchText(e.target.value)} /> } className="w-[26px]" tooltip={{ content: { text: 'New query', side: 'bottom' } }} >
{templatesEnabled && (
Templates
)} {collectionsEnabled && ( <> {filteredLogs.map((collection) => { const isItemActive = isActive(collection?.url ?? '') return ( ) })} {OPERATIONAL_COLLECTIONS.length > 0 && ( <> {filteredOperationalLogs.map((collection) => ( ))} )} )} {savedQueriesLoading && (
)} {savedQueries.length === 0 && ( Create query } /> )} {savedQueries.map((query) => ( ))}
{LOG_DRAIN_TYPES.filter((t) => ['datadog', 'sentry', 'webhook', 'loki'].includes(t.value) ).map((type) => React.cloneElement(type.icon, { key: type.name, height: 20, width: 20 }) )}
} actions={ } /> ) }