diff --git a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreview.constants.tsx b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreview.constants.tsx index a18fe30d764..753611839be 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreview.constants.tsx +++ b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreview.constants.tsx @@ -50,4 +50,11 @@ export const FEATURE_PREVIEWS = [ isNew: true, isPlatformOnly: false, }, + { + key: LOCAL_STORAGE_KEYS.UI_PREVIEW_SIDEBAR_TOOLBAR, + name: 'Sidebar Toolbar', + discussionsUrl: 'https://github.com/orgs/supabase/discussions/42462', + isNew: true, + isPlatformOnly: false, + }, ] as const diff --git a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx index 68b5367357a..081a6470700 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx +++ b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx @@ -115,12 +115,20 @@ export const useIsTableFilterBarEnabled = () => { return flags[LOCAL_STORAGE_KEYS.UI_PREVIEW_TABLE_FILTER_BAR] } +export const useIsSidebarToolbarEnabled = () => { + const { flags } = useFeaturePreviewContext() + const showSidebarToolbar = useFlag('enableSidebarToolbar') + + return showSidebarToolbar && flags[LOCAL_STORAGE_KEYS.UI_PREVIEW_SIDEBAR_TOOLBAR] +} + export const useFeaturePreviewModal = () => { const [featurePreviewModal, setFeaturePreviewModal] = useQueryState('featurePreviewModal') const gitlessBranchingEnabled = useFlag('gitlessBranching') const advisorRulesEnabled = useFlag('advisorRules') const isUnifiedLogsPreviewAvailable = useFlag('unifiedLogs') + const isSidebarToolbarAvailable = useFlag('enableSidebarToolbar') const selectedFeatureKeyFromQuery = featurePreviewModal?.trim() ?? null const showFeaturePreviewModal = selectedFeatureKeyFromQuery !== null @@ -135,11 +143,13 @@ export const useFeaturePreviewModal = () => { return advisorRulesEnabled case 'supabase-ui-preview-unified-logs': return isUnifiedLogsPreviewAvailable + case 'supabase-ui-sidebar-toolbar': + return isSidebarToolbarAvailable default: return true } }, - [gitlessBranchingEnabled, advisorRulesEnabled, isUnifiedLogsPreviewAvailable] + [gitlessBranchingEnabled, advisorRulesEnabled, isUnifiedLogsPreviewAvailable, isSidebarToolbarAvailable] ) const selectedFeatureKey = ( diff --git a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx index d3d83963894..9bc299a2770 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx +++ b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx @@ -14,6 +14,7 @@ import { CLSPreview } from './CLSPreview' import { FEATURE_PREVIEWS } from './FeaturePreview.constants' import { useFeaturePreviewContext, useFeaturePreviewModal } from './FeaturePreviewContext' import { QueueOperationsPreview } from './QueueOperationsPreview' +import { SidebarToolbarPreview } from './SidebarToolbarPreview' import { TableFilterBarPreview } from './TableFilterBarPreview' import { UnifiedLogsPreview } from './UnifiedLogsPreview' @@ -27,6 +28,7 @@ const FEATURE_PREVIEW_KEY_TO_CONTENT: { [LOCAL_STORAGE_KEYS.UI_PREVIEW_UNIFIED_LOGS]: , [LOCAL_STORAGE_KEYS.UI_PREVIEW_QUEUE_OPERATIONS]: , [LOCAL_STORAGE_KEYS.UI_PREVIEW_TABLE_FILTER_BAR]: , + [LOCAL_STORAGE_KEYS.UI_PREVIEW_SIDEBAR_TOOLBAR]: , } const FeaturePreviewModal = () => { diff --git a/apps/studio/components/interfaces/App/FeaturePreview/SidebarToolbarPreview.tsx b/apps/studio/components/interfaces/App/FeaturePreview/SidebarToolbarPreview.tsx new file mode 100644 index 00000000000..7938549578d --- /dev/null +++ b/apps/studio/components/interfaces/App/FeaturePreview/SidebarToolbarPreview.tsx @@ -0,0 +1,31 @@ +import { BASE_PATH } from 'lib/constants' +import Image from 'next/image' + +export const SidebarToolbarPreview = () => { + return ( +
+

+ Enable a dedicated vertical toolbar on the right side of the dashboard for accessing side + panels. This creates a consistent, repeatable pattern for opening panels while reducing + clutter in the top navigation bar. +

+ sidebar-toolbar-preview +
+

Enabling this preview will:

+
    +
  • Add a dedicated sidebar toolbar on the right side of the dashboard
  • +
  • + Move the Help, Advisors, SQL Editor, and AI Assistant buttons from the top navigation + bar to the new sidebar toolbar +
  • +
+
+
+ ) +} diff --git a/apps/studio/components/interfaces/UserDropdown.tsx b/apps/studio/components/interfaces/UserDropdown.tsx index 5011055e6d4..5c1db4d518d 100644 --- a/apps/studio/components/interfaces/UserDropdown.tsx +++ b/apps/studio/components/interfaces/UserDropdown.tsx @@ -1,4 +1,3 @@ -import { useFlag } from 'common' import { ProfileImage } from 'components/ui/ProfileImage' import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled' import { IS_PLATFORM } from 'lib/constants' @@ -25,7 +24,10 @@ import { } from 'ui' import { useCommandMenuOpenedTelemetry, useSetCommandMenuOpen } from 'ui-patterns/CommandMenu' -import { useFeaturePreviewModal } from './App/FeaturePreview/FeaturePreviewContext' +import { + useFeaturePreviewModal, + useIsSidebarToolbarEnabled, +} from './App/FeaturePreview/FeaturePreviewContext' export function UserDropdown() { const router = useRouter() @@ -34,7 +36,7 @@ export function UserDropdown() { const profileShowEmailEnabled = useIsFeatureEnabled('profile:show_email') const { username, avatarUrl, primaryEmail, isLoading } = useProfileNameAndPicture() - const showSidebarToolbar = useFlag('enableSidebarToolbar') + const showSidebarToolbar = useIsSidebarToolbarEnabled() const setCommandMenuOpen = useSetCommandMenuOpen() const sendTelemetry = useCommandMenuOpenedTelemetry() const { openFeaturePreviewModal } = useFeaturePreviewModal() diff --git a/apps/studio/components/layouts/DefaultLayout.tsx b/apps/studio/components/layouts/DefaultLayout.tsx index 992e2cb74f8..119af111da1 100644 --- a/apps/studio/components/layouts/DefaultLayout.tsx +++ b/apps/studio/components/layouts/DefaultLayout.tsx @@ -1,4 +1,4 @@ -import { LOCAL_STORAGE_KEYS, useFlag, useParams } from 'common' +import { LOCAL_STORAGE_KEYS, useParams } from 'common' import { AppBannerWrapper } from 'components/interfaces/App/AppBannerWrapper' import { Sidebar } from 'components/interfaces/Sidebar' import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage' @@ -8,6 +8,7 @@ import { PropsWithChildren } from 'react' import { useAppStateSnapshot } from 'state/app-state' import { ResizablePanel, ResizablePanelGroup, SidebarProvider } from 'ui' +import { useIsSidebarToolbarEnabled } from '../interfaces/App/FeaturePreview/FeaturePreviewContext' import { LayoutHeader } from './ProjectLayout/LayoutHeader/LayoutHeader' import { LayoutSidebar } from './ProjectLayout/LayoutSidebar' import { LayoutSidebarProvider } from './ProjectLayout/LayoutSidebar/LayoutSidebarProvider' @@ -39,7 +40,7 @@ export const DefaultLayout = ({ const router = useRouter() const appSnap = useAppStateSnapshot() const showProductMenu = !!ref && router.pathname !== '/project/[ref]' - const showSidebarToolbar = useFlag('enableSidebarToolbar') + const showSidebarToolbar = useIsSidebarToolbarEnabled() const [lastVisitedOrganization] = useLocalStorageQuery( LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, diff --git a/apps/studio/components/layouts/ProjectLayout/LayoutHeader/LayoutHeader.tsx b/apps/studio/components/layouts/ProjectLayout/LayoutHeader/LayoutHeader.tsx index fb066a47a13..2f3aeaaaf60 100644 --- a/apps/studio/components/layouts/ProjectLayout/LayoutHeader/LayoutHeader.tsx +++ b/apps/studio/components/layouts/ProjectLayout/LayoutHeader/LayoutHeader.tsx @@ -1,5 +1,8 @@ -import { LOCAL_STORAGE_KEYS, useFlag, useParams } from 'common' -import { useIsBranching2Enabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' +import { LOCAL_STORAGE_KEYS, useParams } from 'common' +import { + useIsBranching2Enabled, + useIsSidebarToolbarEnabled, +} from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' import { LocalDropdown } from 'components/interfaces/LocalDropdown' import { UserDropdown } from 'components/interfaces/UserDropdown' import { AdvisorButton } from 'components/layouts/AppLayout/AdvisorButton' @@ -74,7 +77,7 @@ export const LayoutHeader = ({ const { setMobileMenuOpen } = useAppStateSnapshot() const gitlessBranching = useIsBranching2Enabled() - const showSidebarToolbar = useFlag('enableSidebarToolbar') + const showSidebarToolbar = useIsSidebarToolbarEnabled() const connectSheetFlag = usePHFlag('connectSheet') const isFlagResolved = connectSheetFlag !== undefined const isConnectSheetEnabled = connectSheetFlag === true || connectSheetFlag === 'variation' diff --git a/apps/studio/components/ui/ProfileImage.tsx b/apps/studio/components/ui/ProfileImage.tsx index 2534e060853..7128ad3f819 100644 --- a/apps/studio/components/ui/ProfileImage.tsx +++ b/apps/studio/components/ui/ProfileImage.tsx @@ -13,7 +13,7 @@ interface ProfileImageProps { export const ProfileImage = ({ alt, src, placeholder, className }: ProfileImageProps) => { const [hasInvalidImg, setHasInvalidImg] = useState(false) - return !!src && !hasInvalidImg ? ( + return !src && !hasInvalidImg ? (