import { IS_PLATFORM, useFlag, useParams } from 'common' import { ChevronRight, CircleHelpIcon, Plus } from 'lucide-react' import Link from 'next/link' import { useRouter } from 'next/router' import React, { useState } from 'react' import { Badge, 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 { useFeaturePreviewModal, useUnifiedLogsPreview, } from '@/components/interfaces/App/FeaturePreview/FeaturePreviewContext' 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 { 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' 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 unifiedLogsFlagEnabled = useFlag('unifiedLogs') const { selectFeaturePreview } = useFeaturePreviewModal() const { enable: enableUnifiedLogs, isEligible: isUnifiedLogsEligible } = useUnifiedLogsPreview() 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 { 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, ].filter((x) => x !== null) const OPERATIONAL_COLLECTIONS = IS_PLATFORM ? [ { 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 (
{IS_PLATFORM && !unifiedLogsFlagEnabled && ( Coming soon} title="New logs" description="Get early access" actions={ } /> )} {isUnifiedLogsEligible && ( New} actions={ <> } onClick={() => selectFeaturePreview('briven-ui-preview-unified-logs')} tooltip={{ content: { side: 'bottom', text: 'More information' } }} /> } /> )}
setSearchText(e.target.value)} >
{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={ } /> ) }