mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 01:45:10 +03:00
feat(studio): remove unified logs banner and deprioritise tos banner (#49239)
## What kind of change does this PR introduce? Studio UI cleanup for sidebar BannerStack items and Unified Logs preview defaults. ## What is the current behavior? The sidebar BannerStack shows both a Unified Logs promo banner and a Terms of Service update notice. Unified Logs has been default opt-in for a while, and the ToS banner currently shares priority with other higher-value notices. The default opt-in behaviour is still gated behind the `unifiedLogsDefaultOptIn` feature flag. Closes [DEPR-646](https://linear.app/supabase/issue/DEPR-646/remove-unified-logs-banner-and-deprioritise-tos-banner). | Before | | --- | | <img width="1024" height="759" alt="5717" src="https://github.com/user-attachments/assets/1a19e6f6-0c7f-49e8-8e7e-9f83196b2353" /> | ## What is the new behavior? - Removes the Unified Logs BannerStack item and its component - Keeps the ToS update banner but lowers its priority so other banners surface first - Sets Unified Logs `isDefaultOptIn` to `true` and removes `unifiedLogsDefaultOptIn` flag usage ## To test - Open any project in Studio (e.g. `/project/<ref>`) - Confirm the sidebar BannerStack no longer shows the "Unified Logs is here" banner - If you have not dismissed the ToS notice and it is still before the expiry date, confirm it still appears but sits behind higher-priority banners (e.g. free micro upgrade on eligible projects) - Open `/project/<ref>/logs` and confirm Unified Logs loads by default for users who have not previously toggled the preview off ## After merge - [ ] Retire the `unifiedLogsDefaultOptIn` PostHog flag <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Unified Logs preview is now enabled by default when available, while preserving individual user choices. - **Bug Fixes** - Terms of Service update notifications now appear with higher priority. - **Changes** - Removed the Unified Logs promotional banner, including related navigation, dismissal, and tracking behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
1 parent
7bac134fa5
commit
b3edaa02f0
7 files changed
+4
-216
No files matched your search
@@ -30,7 +30,7 @@ export const AppBannerWrapper = ({ children }: PropsWithChildren<{}>) => {
|
||||
id: 'tos-update-banner',
|
||||
isDismissed: false,
|
||||
content: <BannerTOSUpdate />,
|
||||
priority: 2,
|
||||
priority: 0,
|
||||
})
|
||||
} else {
|
||||
dismissBanner('tos-update-banner')
|
||||
|
||||
@@ -98,15 +98,13 @@ export const useIsColumnLevelPrivilegesEnabled = () => {
|
||||
}
|
||||
|
||||
export const useUnifiedLogsPreview = () => {
|
||||
const unifiedLogsDefaultOptIn = useFlag('unifiedLogsDefaultOptIn')
|
||||
const { flags, isInitialized, onUpdateFlag } = useFeaturePreviewContext()
|
||||
|
||||
const isLoading = !isInitialized
|
||||
const isEnabled = IS_PLATFORM && flags[LOCAL_STORAGE_KEYS.UI_PREVIEW_UNIFIED_LOGS]
|
||||
|
||||
const hasToggledPreview = !!safeLocalStorage.getItem(LOCAL_STORAGE_KEYS.UI_PREVIEW_UNIFIED_LOGS)
|
||||
const isDefaultOptIn =
|
||||
IS_PLATFORM && isInitialized && unifiedLogsDefaultOptIn && !hasToggledPreview
|
||||
const isDefaultOptIn = IS_PLATFORM && !hasToggledPreview
|
||||
|
||||
const enable = () => onUpdateFlag(LOCAL_STORAGE_KEYS.UI_PREVIEW_UNIFIED_LOGS, true)
|
||||
const disable = () => onUpdateFlag(LOCAL_STORAGE_KEYS.UI_PREVIEW_UNIFIED_LOGS, false)
|
||||
|
||||
@@ -36,7 +36,6 @@ export const useFeaturePreviews = (): FeaturePreview[] => {
|
||||
const isMarketplaceEnabled = useFlag('marketplaceIntegrations')
|
||||
const isDatabaseConnectionsEnabled = useFlag('topForPostgres')
|
||||
|
||||
const unifiedLogsDefaultOptIn = useFlag('unifiedLogsDefaultOptIn')
|
||||
const isSqlEditorManualSaveForced = useFlag('sqlEditorManualSaveForced')
|
||||
|
||||
return useMemo(() => {
|
||||
@@ -49,7 +48,7 @@ export const useFeaturePreviews = (): FeaturePreview[] => {
|
||||
enabled: true,
|
||||
isNew: true,
|
||||
isPlatformOnly: true,
|
||||
isDefaultOptIn: unifiedLogsDefaultOptIn,
|
||||
isDefaultOptIn: true,
|
||||
getRoute: (ref?: string) => `/project/${ref}/logs`,
|
||||
},
|
||||
{
|
||||
@@ -142,7 +141,6 @@ export const useFeaturePreviews = (): FeaturePreview[] => {
|
||||
|
||||
return previews.sort((a, b) => Number(b.isNew) - Number(a.isNew))
|
||||
}, [
|
||||
unifiedLogsDefaultOptIn,
|
||||
isSqlEditorManualSaveForced,
|
||||
isPlatformWebhooksEnabled,
|
||||
jitDbAccessEnabled,
|
||||
|
||||
@@ -79,7 +79,6 @@ vi.mock('common', () => ({
|
||||
`free-micro-upgrade-banner-dismissed-${ref}`,
|
||||
PROJECT_INTEGRATION_BANNER_DISMISSED: (ref: string, integrationSource: string) =>
|
||||
`project-integration-banner-dismissed-${ref}-${integrationSource}`,
|
||||
UNIFIED_LOGS_BANNER_DISMISSED: 'unified-logs-banner-dismissed',
|
||||
},
|
||||
isFeatureEnabled: () => false,
|
||||
}))
|
||||
@@ -177,7 +176,6 @@ vi.mock('@/hooks/misc/useLocalStorage', () => ({
|
||||
vi.mock('@/components/ui/BannerStack/BannerStackProvider', () => ({
|
||||
BANNER_ID: {
|
||||
FREE_MICRO_UPGRADE: 'free-micro-upgrade-banner',
|
||||
UNIFIED_LOGS: 'unified-logs-banner',
|
||||
},
|
||||
useBannerStack: () => ({
|
||||
addBanner: mockAddBanner,
|
||||
@@ -190,19 +188,6 @@ vi.mock('@/components/ui/BannerStack/Banners/BannerFreeMicroUpgrade', () => ({
|
||||
BannerFreeMicroUpgrade: () => null,
|
||||
}))
|
||||
|
||||
vi.mock('@/components/ui/BannerStack/Banners/BannerUnifiedLogs', () => ({
|
||||
BannerUnifiedLogs: () => null,
|
||||
}))
|
||||
|
||||
vi.mock('@/components/interfaces/App/FeaturePreview/FeaturePreviewContext', () => ({
|
||||
useUnifiedLogsPreview: () => ({
|
||||
isEnabled: false,
|
||||
isLoading: false,
|
||||
enable: () => {},
|
||||
disable: () => {},
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/data/usage/resource-warnings-query', () => ({
|
||||
useResourceWarningsQuery: () => ({ data: mockResourceWarningsState.current }),
|
||||
}))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { IS_PLATFORM, LOCAL_STORAGE_KEYS, mergeRefs, useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, mergeRefs, useParams } from 'common'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import { XIcon } from 'lucide-react'
|
||||
import Head from 'next/head'
|
||||
@@ -43,7 +43,6 @@ import { UpgradingState } from './UpgradingState'
|
||||
import { CreateBranchModal } from '@/components/interfaces/BranchManagement/CreateBranchModal'
|
||||
import { ProjectAPIDocs } from '@/components/interfaces/ProjectAPIDocs/ProjectAPIDocs'
|
||||
import { BannerFreeMicroUpgrade } from '@/components/ui/BannerStack/Banners/BannerFreeMicroUpgrade'
|
||||
import { BannerUnifiedLogs } from '@/components/ui/BannerStack/Banners/BannerUnifiedLogs'
|
||||
import { BANNER_ID, useBannerStack } from '@/components/ui/BannerStack/BannerStackProvider'
|
||||
import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
|
||||
import PartnerIcon from '@/components/ui/PartnerIcon'
|
||||
@@ -155,10 +154,6 @@ export const ProjectLayout = forwardRef<HTMLDivElement, PropsWithChildren<Projec
|
||||
LOCAL_STORAGE_KEYS.FREE_MICRO_UPGRADE_BANNER_DISMISSED(selectedProject?.ref ?? ''),
|
||||
false
|
||||
)
|
||||
const [isUnifiedLogsBannerDismissed] = useLocalStorageQuery(
|
||||
LOCAL_STORAGE_KEYS.UNIFIED_LOGS_BANNER_DISMISSED,
|
||||
false
|
||||
)
|
||||
const [isProjectIntegrationBannerDismissed, setIsProjectIntegrationBannerDismissed] =
|
||||
useLocalStorageQuery(
|
||||
getProjectIntegrationBannerDismissKey({
|
||||
@@ -236,20 +231,6 @@ export const ProjectLayout = forwardRef<HTMLDivElement, PropsWithChildren<Projec
|
||||
dismissBanner,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedProject?.ref) return
|
||||
if (IS_PLATFORM && !isUnifiedLogsBannerDismissed) {
|
||||
addBanner({
|
||||
id: BANNER_ID.UNIFIED_LOGS,
|
||||
isDismissed: false,
|
||||
content: <BannerUnifiedLogs />,
|
||||
priority: 1,
|
||||
})
|
||||
} else {
|
||||
dismissBanner(BANNER_ID.UNIFIED_LOGS)
|
||||
}
|
||||
}, [selectedProject?.ref, isUnifiedLogsBannerDismissed, addBanner, dismissBanner])
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const unregister = registerOpenMenu(() => {
|
||||
setMobileSheetContent(
|
||||
|
||||
@@ -7,7 +7,6 @@ export const BANNER_ID = {
|
||||
RLS_EVENT_TRIGGER: 'rls-event-trigger-banner',
|
||||
FREE_MICRO_UPGRADE: 'free-micro-upgrade-banner',
|
||||
TOS_UPDATE: 'tos-update-banner',
|
||||
UNIFIED_LOGS: 'unified-logs-banner',
|
||||
} as const
|
||||
|
||||
export type BannerId = (typeof BANNER_ID)[keyof typeof BANNER_ID]
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
import { useParams } from 'common/hooks'
|
||||
import dayjs from 'dayjs'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import Link from 'next/link'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { Badge, Button, cn } from 'ui'
|
||||
|
||||
import { BannerCard } from '../BannerCard'
|
||||
import { useBannerStack } from '../BannerStackProvider'
|
||||
import {
|
||||
useFeaturePreviewModal,
|
||||
useUnifiedLogsPreview,
|
||||
} from '@/components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage'
|
||||
import { useTrack } from '@/lib/telemetry/track'
|
||||
|
||||
// Number of rows visible in the carousel viewport. We keep one extra row in
|
||||
// state so the row sliding out of view has something to animate towards.
|
||||
const VISIBLE_ROWS = 3
|
||||
const ROW_HEIGHT = 28
|
||||
const TICK_MS = 3000
|
||||
|
||||
const SAMPLES = [200, 200, 201, 200, 304, 400, 200, 500] as const
|
||||
|
||||
interface LogEntry {
|
||||
id: number
|
||||
timestamp: string
|
||||
status: number
|
||||
}
|
||||
|
||||
const makeEntry = (id: number, offsetSeconds = 0): LogEntry => ({
|
||||
id,
|
||||
timestamp: dayjs().subtract(offsetSeconds, 'second').format('DD MMM YY HH:mm:ss'),
|
||||
status: SAMPLES[id % SAMPLES.length],
|
||||
})
|
||||
|
||||
const LogRow = ({ entry }: { entry: LogEntry }) => {
|
||||
const isDestructive = entry.status >= 500
|
||||
const isWarning = entry.status >= 400 && entry.status < 500
|
||||
return (
|
||||
<div
|
||||
className="flex items-center gap-x-3 font-mono text-xs whitespace-nowrap text-foreground-light"
|
||||
style={{ height: ROW_HEIGHT }}
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
'size-1.5 shrink-0 rounded-full bg-foreground-muted',
|
||||
isWarning && 'bg-warning',
|
||||
isDestructive && 'bg-destructive'
|
||||
)}
|
||||
/>
|
||||
<span
|
||||
className={cn(
|
||||
'tabular-nums',
|
||||
isWarning && 'text-warning',
|
||||
isDestructive && 'text-destructive'
|
||||
)}
|
||||
>
|
||||
{entry.timestamp}
|
||||
</span>
|
||||
<span
|
||||
className={cn(
|
||||
'tabular-nums',
|
||||
isWarning && 'text-warning',
|
||||
isDestructive && 'text-destructive'
|
||||
)}
|
||||
>
|
||||
{entry.status}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const UnifiedLogsCarousel = () => {
|
||||
const counter = useRef(VISIBLE_ROWS)
|
||||
const [logs, setLogs] = useState<LogEntry[]>(() =>
|
||||
Array.from({ length: VISIBLE_ROWS + 1 }, (_, i) => makeEntry(VISIBLE_ROWS - i, i))
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
counter.current += 1
|
||||
const next = makeEntry(counter.current)
|
||||
setLogs((prev) => [next, ...prev].slice(0, VISIBLE_ROWS + 1))
|
||||
}, TICK_MS)
|
||||
return () => clearInterval(interval)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="relative w-full overflow-hidden" style={{ height: ROW_HEIGHT * VISIBLE_ROWS }}>
|
||||
<AnimatePresence initial={false}>
|
||||
{logs.map((entry, index) => (
|
||||
<motion.div
|
||||
key={entry.id}
|
||||
layout
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: Math.max(1 - index * 0.4, 0) }}
|
||||
exit={{ opacity: 0 }}
|
||||
>
|
||||
<LogRow entry={entry} />
|
||||
</motion.div>
|
||||
))}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const BannerUnifiedLogs = () => {
|
||||
const { ref } = useParams()
|
||||
const track = useTrack()
|
||||
const { dismissBanner } = useBannerStack()
|
||||
const { isEnabled } = useUnifiedLogsPreview()
|
||||
const { selectFeaturePreview } = useFeaturePreviewModal()
|
||||
const [, setIsDismissed] = useLocalStorageQuery(
|
||||
LOCAL_STORAGE_KEYS.UNIFIED_LOGS_BANNER_DISMISSED,
|
||||
false
|
||||
)
|
||||
|
||||
return (
|
||||
<BannerCard
|
||||
onDismiss={() => {
|
||||
setIsDismissed(true)
|
||||
dismissBanner('unified-logs-banner')
|
||||
track('unified_logs_banner_dismiss_button_clicked')
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-col gap-y-4">
|
||||
<div className="flex flex-col gap-y-2 items-start">
|
||||
<Badge variant="success" className="-ml-0.5 uppercase inline-flex items-center">
|
||||
Beta
|
||||
</Badge>
|
||||
<div className="-mx-6 w-[calc(100%+3rem)] bg-linear-to-t from-background to-transparent px-6 py-2 border-b">
|
||||
<UnifiedLogsCarousel />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-y-1 mb-2">
|
||||
<p className="text-sm font-medium">Unified Logs is here</p>
|
||||
<p className="text-xs text-foreground-lighter text-balance">
|
||||
Search and correlate logs across all of your services from a single place.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
{isEnabled ? (
|
||||
<Button variant="default" size="tiny" asChild>
|
||||
<Link
|
||||
href={`/project/${ref}/logs`}
|
||||
onClick={() => {
|
||||
track('unified_logs_banner_cta_button_clicked', { is_enabled: true })
|
||||
setIsDismissed(true)
|
||||
dismissBanner('unified-logs-banner')
|
||||
}}
|
||||
>
|
||||
Explore Unified Logs
|
||||
</Link>
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
variant="default"
|
||||
size="tiny"
|
||||
onClick={() => {
|
||||
track('unified_logs_banner_cta_button_clicked', { is_enabled: false })
|
||||
selectFeaturePreview(LOCAL_STORAGE_KEYS.UI_PREVIEW_UNIFIED_LOGS)
|
||||
}}
|
||||
>
|
||||
Enable Unified Logs
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</BannerCard>
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user