From b3edaa02f0464c49b290ffc2afeff8982291e741 Mon Sep 17 00:00:00 2001 From: Danny White <3104761+dnywh@users.noreply.github.com> Date: Wed, 19 Aug 2026 17:37:14 +1000 Subject: [PATCH] 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 | | --- | | 5717 | ## 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/`) - 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//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 ## 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. --- .../interfaces/App/AppBannerWrapper.tsx | 2 +- .../FeaturePreview/FeaturePreviewContext.tsx | 4 +- .../App/FeaturePreview/useFeaturePreviews.ts | 4 +- .../layouts/ProjectLayout/index.test.tsx | 15 -- .../layouts/ProjectLayout/index.tsx | 21 +-- .../ui/BannerStack/BannerStackProvider.tsx | 1 - .../BannerStack/Banners/BannerUnifiedLogs.tsx | 173 ------------------ 7 files changed, 4 insertions(+), 216 deletions(-) delete mode 100644 apps/studio/components/ui/BannerStack/Banners/BannerUnifiedLogs.tsx diff --git a/apps/studio/components/interfaces/App/AppBannerWrapper.tsx b/apps/studio/components/interfaces/App/AppBannerWrapper.tsx index 832f2769a75..dbb1d6cef96 100644 --- a/apps/studio/components/interfaces/App/AppBannerWrapper.tsx +++ b/apps/studio/components/interfaces/App/AppBannerWrapper.tsx @@ -30,7 +30,7 @@ export const AppBannerWrapper = ({ children }: PropsWithChildren<{}>) => { id: 'tos-update-banner', isDismissed: false, content: , - priority: 2, + priority: 0, }) } else { dismissBanner('tos-update-banner') diff --git a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx index 03691172a71..2eeb77a318f 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx +++ b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx @@ -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) diff --git a/apps/studio/components/interfaces/App/FeaturePreview/useFeaturePreviews.ts b/apps/studio/components/interfaces/App/FeaturePreview/useFeaturePreviews.ts index a30be45c941..607337c5384 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/useFeaturePreviews.ts +++ b/apps/studio/components/interfaces/App/FeaturePreview/useFeaturePreviews.ts @@ -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, diff --git a/apps/studio/components/layouts/ProjectLayout/index.test.tsx b/apps/studio/components/layouts/ProjectLayout/index.test.tsx index d7bd6257232..e02dcd5f7dd 100644 --- a/apps/studio/components/layouts/ProjectLayout/index.test.tsx +++ b/apps/studio/components/layouts/ProjectLayout/index.test.tsx @@ -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 }), })) diff --git a/apps/studio/components/layouts/ProjectLayout/index.tsx b/apps/studio/components/layouts/ProjectLayout/index.tsx index d9d487962d3..85a04b89b60 100644 --- a/apps/studio/components/layouts/ProjectLayout/index.tsx +++ b/apps/studio/components/layouts/ProjectLayout/index.tsx @@ -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 { - if (!selectedProject?.ref) return - if (IS_PLATFORM && !isUnifiedLogsBannerDismissed) { - addBanner({ - id: BANNER_ID.UNIFIED_LOGS, - isDismissed: false, - content: , - priority: 1, - }) - } else { - dismissBanner(BANNER_ID.UNIFIED_LOGS) - } - }, [selectedProject?.ref, isUnifiedLogsBannerDismissed, addBanner, dismissBanner]) - useLayoutEffect(() => { const unregister = registerOpenMenu(() => { setMobileSheetContent( diff --git a/apps/studio/components/ui/BannerStack/BannerStackProvider.tsx b/apps/studio/components/ui/BannerStack/BannerStackProvider.tsx index 5049cd000e0..60615a56078 100644 --- a/apps/studio/components/ui/BannerStack/BannerStackProvider.tsx +++ b/apps/studio/components/ui/BannerStack/BannerStackProvider.tsx @@ -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] diff --git a/apps/studio/components/ui/BannerStack/Banners/BannerUnifiedLogs.tsx b/apps/studio/components/ui/BannerStack/Banners/BannerUnifiedLogs.tsx deleted file mode 100644 index 9d417dfcebc..00000000000 --- a/apps/studio/components/ui/BannerStack/Banners/BannerUnifiedLogs.tsx +++ /dev/null @@ -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 ( -
- - - {entry.timestamp} - - - {entry.status} - -
- ) -} - -const UnifiedLogsCarousel = () => { - const counter = useRef(VISIBLE_ROWS) - const [logs, setLogs] = useState(() => - 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 ( -
- - {logs.map((entry, index) => ( - - - - ))} - -
- ) -} - -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 ( - { - setIsDismissed(true) - dismissBanner('unified-logs-banner') - track('unified_logs_banner_dismiss_button_clicked') - }} - > -
-
- - Beta - -
- -
-
-
-

Unified Logs is here

-

- Search and correlate logs across all of your services from a single place. -

-
-
- {isEnabled ? ( - - ) : ( - - )} -
-
-
- ) -}