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.
+
+
+
+
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 ? (