From 26b3db830215b2e80c657aaa33b9d75d366945f0 Mon Sep 17 00:00:00 2001 From: Ali Waseem Date: Wed, 8 Apr 2026 08:40:05 -0600 Subject: [PATCH] fix: remove API Docs nav item after transition period (#44637) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Removes the "API Docs" navigation item from the sidebar and mobile menu - Removes the `UI_PREVIEW_API_SIDE_PANEL` feature preview flag since the feature is fully rolled out - Makes API docs buttons unconditionally visible across Auth Users, Storage, Edge Functions, and SecondLevelNav ## Test plan - [x] `NavigationBar.utils` tests pass (26 tests) - [x] `FileExplorerHeader` tests pass (6 tests) - [x] TypeScript compiles with no errors - [ ] Verify sidebar no longer shows "API Docs" nav item - [ ] Verify API docs buttons still appear in Auth Users, Storage, and Edge Functions pages - [ ] Verify feature preview modal no longer lists "Project API documentation" Resolves FE-2759 ## Summary by CodeRabbit * **New Features** * APIDocs button can optionally display a label and use a custom tooltip. * **Chores** * Removed the API docs side-panel feature flag and its localStorage key. * “API Docs” navigation entry removed; sidebar no longer special-cases that route. * Back links and API Docs buttons now render consistently across the app (no flag gating). * **Tests** * Tests updated to stop depending on the removed feature-flag behavior. --- .../FeaturePreview/FeaturePreviewContext.tsx | 5 --- .../App/FeaturePreview/useFeaturePreviews.ts | 9 ----- .../interfaces/Auth/Users/UsersV2.tsx | 6 --- .../ProjectAPIDocs/SecondLevelNav.Layout.tsx | 7 +--- apps/studio/components/interfaces/Sidebar.tsx | 39 +------------------ .../FileExplorerHeader.test.tsx | 11 +----- .../StorageExplorer/FileExplorerHeader.tsx | 12 ------ .../layouts/DocsLayout/DocsLayout.tsx | 4 +- .../EdgeFunctionDetailsLayout.tsx | 13 ------- .../NavigationBar.utils.test.tsx | 15 +------ .../NavigationBar/NavigationBar.utils.tsx | 18 +-------- .../MobileMenuContent/MobileMenuContent.tsx | 9 +---- apps/studio/components/ui/APIDocsButton.tsx | 12 ++++-- packages/common/constants/local-storage.ts | 2 - 14 files changed, 17 insertions(+), 145 deletions(-) diff --git a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx index 55017c38630..5c76070c05b 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx +++ b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx @@ -70,11 +70,6 @@ export const FeaturePreviewContextProvider = ({ children }: PropsWithChildren<{} // Helpers -export const useIsAPIDocsSidePanelEnabled = () => { - const { flags } = useFeaturePreviewContext() - return flags[LOCAL_STORAGE_KEYS.UI_PREVIEW_API_SIDE_PANEL] -} - export const useIsColumnLevelPrivilegesEnabled = () => { const { flags } = useFeaturePreviewContext() return flags[LOCAL_STORAGE_KEYS.UI_PREVIEW_CLS] diff --git a/apps/studio/components/interfaces/App/FeaturePreview/useFeaturePreviews.ts b/apps/studio/components/interfaces/App/FeaturePreview/useFeaturePreviews.ts index 042a99567e4..292ce5aa2ad 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/useFeaturePreviews.ts +++ b/apps/studio/components/interfaces/App/FeaturePreview/useFeaturePreviews.ts @@ -77,15 +77,6 @@ export const useFeaturePreviews = (): FeaturePreview[] => { isDefaultOptIn: false, enabled: jitDbAccessEnabled, }, - { - key: LOCAL_STORAGE_KEYS.UI_PREVIEW_API_SIDE_PANEL, - name: 'Project API documentation', - discussionsUrl: 'https://github.com/orgs/supabase/discussions/18038', - enabled: true, - isNew: false, - isPlatformOnly: false, - isDefaultOptIn: false, - }, { key: LOCAL_STORAGE_KEYS.UI_PREVIEW_CLS, name: 'Column-level privileges', diff --git a/apps/studio/components/interfaces/Auth/Users/UsersV2.tsx b/apps/studio/components/interfaces/Auth/Users/UsersV2.tsx index 35b98bd2090..30ef78fdcb3 100644 --- a/apps/studio/components/interfaces/Auth/Users/UsersV2.tsx +++ b/apps/studio/components/interfaces/Auth/Users/UsersV2.tsx @@ -54,9 +54,7 @@ import { import { formatUserColumns, formatUsersData } from './Users.utils' import { UsersFooter } from './UsersFooter' import { UsersSearch } from './UsersSearch' -import { useIsAPIDocsSidePanelEnabled } from '@/components/interfaces/App/FeaturePreview/FeaturePreviewContext' import { AlertError } from '@/components/ui/AlertError' -import { APIDocsButton } from '@/components/ui/APIDocsButton' import { ButtonTooltip } from '@/components/ui/ButtonTooltip' import { FilterPopover } from '@/components/ui/FilterPopover' import { FormHeader } from '@/components/ui/Forms/FormHeader' @@ -99,7 +97,6 @@ export const UsersV2 = () => { const { data: selectedOrg } = useSelectedOrganizationQuery() const gridRef = useRef(null) const xScroll = useRef(0) - const isNewAPIDocsEnabled = useIsAPIDocsSidePanelEnabled() const { mutate: sendEvent } = useSendEventMutation() const { @@ -722,9 +719,6 @@ export const UsersV2 = () => {
- {isNewAPIDocsEnabled && ( - - )} } diff --git a/apps/studio/components/interfaces/ProjectAPIDocs/SecondLevelNav.Layout.tsx b/apps/studio/components/interfaces/ProjectAPIDocs/SecondLevelNav.Layout.tsx index d3f5196b5eb..f0a6b7c9791 100644 --- a/apps/studio/components/interfaces/ProjectAPIDocs/SecondLevelNav.Layout.tsx +++ b/apps/studio/components/interfaces/ProjectAPIDocs/SecondLevelNav.Layout.tsx @@ -11,7 +11,6 @@ import { PopoverTrigger_Shadcn_, } from 'ui' -import { useIsAPIDocsSidePanelEnabled } from '../App/FeaturePreview/FeaturePreviewContext' import { navigateToSection } from './Content/Content.utils' import { DOCS_RESOURCE_CONTENT } from './ProjectAPIDocs.constants' import { DocsButton } from '@/components/ui/DocsButton' @@ -90,8 +89,6 @@ type NavTitleProps = { } const NavTitle = ({ title, category }: NavTitleProps) => { - const isNewAPIDocsEnabled = useIsAPIDocsSidePanelEnabled() - const snap = useAppStateSnapshot() const handleBack = () => { snap.setActiveDocsSection([category]) @@ -99,9 +96,7 @@ const NavTitle = ({ title, category }: NavTitleProps) => { return (
- {isNewAPIDocsEnabled && ( -
) diff --git a/apps/studio/components/interfaces/Sidebar.tsx b/apps/studio/components/interfaces/Sidebar.tsx index aa9010f9800..b97f2fd143c 100644 --- a/apps/studio/components/interfaces/Sidebar.tsx +++ b/apps/studio/components/interfaces/Sidebar.tsx @@ -29,7 +29,6 @@ import { import { Route } from '../ui/ui.types' import { - useIsAPIDocsSidePanelEnabled, useIsPlatformWebhooksEnabled, useUnifiedLogsPreview, } from './App/FeaturePreview/FeaturePreviewContext' @@ -225,7 +224,6 @@ const ProjectLinks = () => { const showReports = useIsFeatureEnabled('reports:all') const { mutate: sendEvent } = useSendEventMutation() - const isNewAPIDocsEnabled = useIsAPIDocsSidePanelEnabled() const platformWebhooksEnabled = useIsPlatformWebhooksEnabled() const { isEnabled: isUnifiedLogsEnabled } = useUnifiedLogsPreview() @@ -256,7 +254,6 @@ const ProjectLinks = () => { const otherRoutes = generateOtherRoutes(ref, project, { unifiedLogs: isUnifiedLogsEnabled, showReports, - apiDocsSidePanel: isNewAPIDocsEnabled, }) const settingsRoutes = generateSettingsRoutes(ref) @@ -295,41 +292,7 @@ const ProjectLinks = () => { {otherRoutes.map((route, i) => { - if (route.key === 'api') { - const handleApiClick = () => { - if (isNewAPIDocsEnabled) { - snap.setShowProjectApiDocs(true) - } - sendEvent({ - action: 'api_docs_opened', - properties: { - source: 'sidebar', - }, - groups: { - project: ref ?? 'Unknown', - organization: org?.slug ?? 'Unknown', - }, - }) - } - - return ( - - ) - } else if (route.key === 'advisors') { + if (route.key === 'advisors') { return (
{!route.disabled && ( diff --git a/apps/studio/components/interfaces/Storage/StorageExplorer/FileExplorerHeader.test.tsx b/apps/studio/components/interfaces/Storage/StorageExplorer/FileExplorerHeader.test.tsx index c0b4623d00c..48aebd88953 100644 --- a/apps/studio/components/interfaces/Storage/StorageExplorer/FileExplorerHeader.test.tsx +++ b/apps/studio/components/interfaces/Storage/StorageExplorer/FileExplorerHeader.test.tsx @@ -10,13 +10,11 @@ const { mockTrack, mockUseStorageExplorerStateSnapshot, mockUseAsyncCheckPermissions, - mockIsAPIDocsSidePanelEnabled, mockUseStoragePreference, } = vi.hoisted(() => ({ mockTrack: vi.fn(), mockUseStorageExplorerStateSnapshot: vi.fn(), mockUseAsyncCheckPermissions: vi.fn(), - mockIsAPIDocsSidePanelEnabled: vi.fn(), mockUseStoragePreference: vi.fn(), })) @@ -27,12 +25,7 @@ vi.mock('@/state/storage-explorer', () => ({ vi.mock('@/hooks/misc/useCheckPermissions', () => ({ useAsyncCheckPermissions: () => mockUseAsyncCheckPermissions(), })) -vi.mock('@/components/interfaces/App/FeaturePreview/FeaturePreviewContext', () => ({ - useIsAPIDocsSidePanelEnabled: () => mockIsAPIDocsSidePanelEnabled(), -})) -vi.mock('@/components/ui/APIDocsButton', () => ({ - APIDocsButton: () => null, -})) + vi.mock('./useStoragePreference', () => ({ useStoragePreference: (...args: any[]) => mockUseStoragePreference(...args), })) @@ -83,13 +76,11 @@ describe('FileExplorerHeader', () => { mockTrack.mockReset() mockUseStorageExplorerStateSnapshot.mockReset() mockUseAsyncCheckPermissions.mockReset() - mockIsAPIDocsSidePanelEnabled.mockReset() mockUseStoragePreference.mockReset() mockUseStorageExplorerStateSnapshot.mockReturnValue(createSnapshot()) mockUseStoragePreference.mockReturnValue(createPreference()) mockUseAsyncCheckPermissions.mockReturnValue({ can: true }) - mockIsAPIDocsSidePanelEnabled.mockReturnValue(false) }) it('renders full breadcrumbs in column view and places Navigate before Reload', () => { diff --git a/apps/studio/components/interfaces/Storage/StorageExplorer/FileExplorerHeader.tsx b/apps/studio/components/interfaces/Storage/StorageExplorer/FileExplorerHeader.tsx index 16787b60fa0..5d09e535150 100644 --- a/apps/studio/components/interfaces/Storage/StorageExplorer/FileExplorerHeader.tsx +++ b/apps/studio/components/interfaces/Storage/StorageExplorer/FileExplorerHeader.tsx @@ -47,8 +47,6 @@ import { Input } from 'ui-patterns/DataInputs/Input' import { STORAGE_SORT_BY, STORAGE_SORT_BY_ORDER, STORAGE_VIEWS } from '../Storage.constants' import { useStoragePreference } from './useStoragePreference' -import { useIsAPIDocsSidePanelEnabled } from '@/components/interfaces/App/FeaturePreview/FeaturePreviewContext' -import { APIDocsButton } from '@/components/ui/APIDocsButton' import { ButtonTooltip } from '@/components/ui/ButtonTooltip' import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions' import { useTrack } from '@/lib/telemetry/track' @@ -208,7 +206,6 @@ export const FileExplorerHeader = ({ onFilesUpload = noop, }: FileExplorerHeader) => { const snap = useStorageExplorerStateSnapshot() - const isNewAPIDocsEnabled = useIsAPIDocsSidePanelEnabled() const track = useTrack() const [pathString, setPathString] = useState('') @@ -545,15 +542,6 @@ export const FileExplorerHeader = ({ /> )}
- - {isNewAPIDocsEnabled && ( - <> -
-
- -
- - )}
diff --git a/apps/studio/components/layouts/DocsLayout/DocsLayout.tsx b/apps/studio/components/layouts/DocsLayout/DocsLayout.tsx index 11af7eb8510..ec7141c664c 100644 --- a/apps/studio/components/layouts/DocsLayout/DocsLayout.tsx +++ b/apps/studio/components/layouts/DocsLayout/DocsLayout.tsx @@ -4,7 +4,6 @@ import { ReactElement } from 'react' import { ProjectLayout } from '../ProjectLayout' import { generateDocsMenu, getActivePage } from './DocsLayout.utils' -import { useIsAPIDocsSidePanelEnabled } from '@/components/interfaces/App/FeaturePreview/FeaturePreviewContext' import Error from '@/components/ui/Error' import { ProductMenu } from '@/components/ui/ProductMenu' import { useOpenAPISpecQuery } from '@/data/open-api/api-spec-query' @@ -25,8 +24,7 @@ function DocsLayout({ title, children }: { title: string; children: ReactElement error, } = useOpenAPISpecQuery({ projectRef: ref }, { enabled: !isPaused }) - const isNewAPIDocsEnabled = useIsAPIDocsSidePanelEnabled() - const hideMenu = isNewAPIDocsEnabled && router.pathname.endsWith('/graphiql') + const hideMenu = router.pathname.endsWith('/graphiql') const { projectAuthAll: authEnabled } = useIsFeatureEnabled(['project_auth:all']) diff --git a/apps/studio/components/layouts/EdgeFunctionsLayout/EdgeFunctionDetailsLayout.tsx b/apps/studio/components/layouts/EdgeFunctionsLayout/EdgeFunctionDetailsLayout.tsx index fc88f2985b4..aac67d9e5ff 100644 --- a/apps/studio/components/layouts/EdgeFunctionsLayout/EdgeFunctionDetailsLayout.tsx +++ b/apps/studio/components/layouts/EdgeFunctionsLayout/EdgeFunctionDetailsLayout.tsx @@ -39,9 +39,7 @@ import { import { ProjectLayout } from '../ProjectLayout' import EdgeFunctionsLayout from './EdgeFunctionsLayout' -import { useIsAPIDocsSidePanelEnabled } from '@/components/interfaces/App/FeaturePreview/FeaturePreviewContext' import { EdgeFunctionTesterSheet } from '@/components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionTesterSheet' -import { APIDocsButton } from '@/components/ui/APIDocsButton' import CopyButton from '@/components/ui/CopyButton' import { DocsButton } from '@/components/ui/DocsButton' import NoPermission from '@/components/ui/NoPermission' @@ -69,7 +67,6 @@ const EdgeFunctionDetailsLayout = ({ const { functionSlug, ref } = useParams() const { mutate: sendEvent } = useSendEventMutation() - const isNewAPIDocsEnabled = useIsAPIDocsSidePanelEnabled() const { isLoading, can: canReadFunctions } = useAsyncCheckPermissions( PermissionAction.FUNCTIONS_READ, '*' @@ -332,16 +329,6 @@ const EdgeFunctionDetailsLayout = ({
- {isNewAPIDocsEnabled && ( - - )} diff --git a/apps/studio/components/layouts/Navigation/NavigationBar/NavigationBar.utils.test.tsx b/apps/studio/components/layouts/Navigation/NavigationBar/NavigationBar.utils.test.tsx index 343838d2515..5d2d3776f8f 100644 --- a/apps/studio/components/layouts/Navigation/NavigationBar/NavigationBar.utils.test.tsx +++ b/apps/studio/components/layouts/Navigation/NavigationBar/NavigationBar.utils.test.tsx @@ -140,19 +140,8 @@ describe('generateOtherRoutes', () => { expect(keys(routes)).not.toContain('observability') }) - it('includes API Docs when apiDocsSidePanel is enabled', () => { - const routes = generateOtherRoutes(REF, activeProject, { - isPlatform: true, - apiDocsSidePanel: true, - }) - expect(keys(routes)).toContain('api') - }) - - it('excludes API Docs when apiDocsSidePanel is disabled', () => { - const routes = generateOtherRoutes(REF, activeProject, { - isPlatform: true, - apiDocsSidePanel: false, - }) + it('does not include API Docs nav item', () => { + const routes = generateOtherRoutes(REF, activeProject, { isPlatform: true }) expect(keys(routes)).not.toContain('api') }) diff --git a/apps/studio/components/layouts/Navigation/NavigationBar/NavigationBar.utils.tsx b/apps/studio/components/layouts/Navigation/NavigationBar/NavigationBar.utils.tsx index 0139208b175..5925d256e55 100644 --- a/apps/studio/components/layouts/Navigation/NavigationBar/NavigationBar.utils.tsx +++ b/apps/studio/components/layouts/Navigation/NavigationBar/NavigationBar.utils.tsx @@ -1,5 +1,5 @@ import { Auth, Database, EdgeFunctions, Realtime, SqlEditor, Storage, TableEditor } from 'icons' -import { Blocks, FileText, Lightbulb, List, Settings, Telescope } from 'lucide-react' +import { Blocks, Lightbulb, List, Settings, Telescope } from 'lucide-react' import { ICON_SIZE, ICON_STROKE_WIDTH } from '@/components/interfaces/Sidebar' import type { Route } from '@/components/ui/ui.types' @@ -26,7 +26,6 @@ interface OtherFeatures { isPlatform?: boolean unifiedLogs?: boolean showReports?: boolean - apiDocsSidePanel?: boolean } interface SettingsFeatures { @@ -154,8 +153,6 @@ export const generateOtherRoutes = ( const isPlatform = features?.isPlatform ?? IS_PLATFORM const unifiedLogsEnabled = features?.unifiedLogs ?? false const reportsEnabled = features?.showReports ?? true - const apiDocsSidePanelEnabled = features?.apiDocsSidePanel ?? false - return [ { key: 'advisors', @@ -183,19 +180,6 @@ export const generateOtherRoutes = ( icon: , link: ref && (unifiedLogsEnabled ? `/project/${ref}/logs` : `/project/${ref}/logs/explorer`), }, - ...(apiDocsSidePanelEnabled - ? [ - { - key: 'api', - label: 'API Docs', - disabled: !isProjectActive, - icon: , - link: - ref && - (isProjectBuilding ? buildingUrl : `/project/${ref}/integrations/data_api/docs`), - }, - ] - : []), { key: 'integrations', label: 'Integrations', diff --git a/apps/studio/components/layouts/ProjectLayout/LayoutHeader/MobileMenuContent/MobileMenuContent.tsx b/apps/studio/components/layouts/ProjectLayout/LayoutHeader/MobileMenuContent/MobileMenuContent.tsx index 5e4cf69c862..59680950551 100644 --- a/apps/studio/components/layouts/ProjectLayout/LayoutHeader/MobileMenuContent/MobileMenuContent.tsx +++ b/apps/studio/components/layouts/ProjectLayout/LayoutHeader/MobileMenuContent/MobileMenuContent.tsx @@ -12,10 +12,7 @@ import { resolveSectionDisplay } from './MobileMenuContent.utils' import { getProductMenuComponent } from './mobileProductMenuRegistry' import { TopLevelRouteItem } from './TopLevelRouteItem' import { routeHasSubmenu, useMobileMenuNavigation } from './useMobileMenuNavigation' -import { - useIsAPIDocsSidePanelEnabled, - useUnifiedLogsPreview, -} from '@/components/interfaces/App/FeaturePreview/FeaturePreviewContext' +import { useUnifiedLogsPreview } from '@/components/interfaces/App/FeaturePreview/FeaturePreviewContext' import { ICON_SIZE, ICON_STROKE_WIDTH } from '@/components/interfaces/Sidebar' import { generateOtherRoutes, @@ -67,7 +64,6 @@ export function MobileMenuContent({ ]) const authOverviewPageEnabled = useFlag('authOverviewPage') const showReports = useIsFeatureEnabled('reports:all') - const isNewAPIDocsEnabled = useIsAPIDocsSidePanelEnabled() const { isEnabled: isUnifiedLogsEnabled } = useUnifiedLogsPreview() const toolRoutes = useMemo(() => generateToolRoutes(ref, project), [ref, project]) @@ -95,9 +91,8 @@ export function MobileMenuContent({ generateOtherRoutes(ref, project, { unifiedLogs: isUnifiedLogsEnabled, showReports, - apiDocsSidePanel: isNewAPIDocsEnabled, }), - [ref, project, isUnifiedLogsEnabled, showReports, isNewAPIDocsEnabled] + [ref, project, isUnifiedLogsEnabled, showReports] ) const settingsRoutes = useMemo(() => generateSettingsRoutes(ref), [ref]) diff --git a/apps/studio/components/ui/APIDocsButton.tsx b/apps/studio/components/ui/APIDocsButton.tsx index 894a2dad196..5eb6ac714b8 100644 --- a/apps/studio/components/ui/APIDocsButton.tsx +++ b/apps/studio/components/ui/APIDocsButton.tsx @@ -9,9 +9,11 @@ import { useAppStateSnapshot } from '@/state/app-state' interface APIDocsButtonProps { section?: string[] source: string + label?: string + tooltip?: string } -export const APIDocsButton = ({ section, source }: APIDocsButtonProps) => { +export const APIDocsButton = ({ section, source, label, tooltip }: APIDocsButtonProps) => { const snap = useAppStateSnapshot() const { ref } = useParams() const { data: org } = useSelectedOrganizationQuery() @@ -37,13 +39,15 @@ export const APIDocsButton = ({ section, source }: APIDocsButtonProps) => { }) }} icon={} - className="w-7" + className={label ? undefined : 'w-7'} tooltip={{ content: { side: 'bottom', - text: 'API Docs', + text: tooltip ?? 'API Docs', }, }} - /> + > + {label} + ) } diff --git a/packages/common/constants/local-storage.ts b/packages/common/constants/local-storage.ts index 37b9daa710e..a3561693600 100644 --- a/packages/common/constants/local-storage.ts +++ b/packages/common/constants/local-storage.ts @@ -15,7 +15,6 @@ export const LOCAL_STORAGE_KEYS = { MAINTENANCE_BANNER_DISMISSED: (id: string) => `maintenance-banner-dismissed-${id}`, DASHBOARD_PREFERENCES: (ref: string) => `dashboard-preferences-${ref}`, - UI_PREVIEW_API_SIDE_PANEL: 'supabase-ui-api-side-panel', UI_PREVIEW_CLS: 'supabase-ui-cls', UI_PREVIEW_INLINE_EDITOR: 'supabase-ui-preview-inline-editor', UI_PREVIEW_UNIFIED_LOGS: 'supabase-ui-preview-unified-logs', @@ -153,7 +152,6 @@ const LOCAL_STORAGE_KEYS_ALLOWLIST = [ 'supabase.dashboard.auth.debug', 'supabase.dashboard.auth.navigatorLock.disabled', LOCAL_STORAGE_KEYS.TELEMETRY_CONSENT, - LOCAL_STORAGE_KEYS.UI_PREVIEW_API_SIDE_PANEL, LOCAL_STORAGE_KEYS.UI_PREVIEW_INLINE_EDITOR, LOCAL_STORAGE_KEYS.UI_PREVIEW_QUEUE_OPERATIONS, LOCAL_STORAGE_KEYS.UI_PREVIEW_CLS,