fix: remove API Docs nav item after transition period (#44637)

## 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

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## 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.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Ali Waseem authored and GitHub committed 2026-04-08 14:40:05 +00:00
1 parent 69b6a4b273
commit 26b3db8302
14 files changed
+17 -145

No files matched your search

@@ -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]
@@ -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',
@@ -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<DataGridHandle>(null)
const xScroll = useRef<number>(0)
const isNewAPIDocsEnabled = useIsAPIDocsSidePanelEnabled()
const { mutate: sendEvent } = useSendEventMutation()
const {
@@ -722,9 +719,6 @@ export const UsersV2 = () => {
</div>
<div className="flex items-center gap-x-2">
{isNewAPIDocsEnabled && (
<APIDocsButton section={['user-management']} source="auth-users" />
)}
<ButtonTooltip
size="tiny"
icon={<RefreshCw />}
@@ -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 (
<div className="flex items-center space-x-2 mb-2">
{isNewAPIDocsEnabled && (
<Button type="text" icon={<ChevronLeft />} className="px-1" onClick={handleBack} />
)}
<Button type="text" icon={<ChevronLeft />} className="px-1" onClick={handleBack} />
<p className="text-sm text-foreground-light capitalize">{title}</p>
</div>
)
+1 -38
View File
@@ -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 = () => {
<Separator className="w-[calc(100%-1rem)] mx-auto" />
<SidebarGroup className="gap-0.5">
{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 (
<SideBarNavLink
key={route.key}
route={
isNewAPIDocsEnabled
? {
label: route.label,
icon: route.icon,
key: route.key,
disabled: route.disabled,
}
: route
}
active={activeRoute === route.key}
onClick={handleApiClick}
/>
)
} else if (route.key === 'advisors') {
if (route.key === 'advisors') {
return (
<div className="relative" key={route.key}>
{!route.disabled && (
@@ -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', () => {
@@ -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 = ({
/>
)}
</div>
{isNewAPIDocsEnabled && (
<>
<div className="h-6 shrink-0 border-r border-control" />
<div className="mx-2 shrink-0">
<APIDocsButton section={['storage', selectedBucket.name]} source="storage" />
</div>
</>
)}
</div>
</div>
</div>
@@ -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'])
@@ -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 = ({
<PageHeaderAside>
<div className="flex items-center space-x-2">
{isNewAPIDocsEnabled && (
<APIDocsButton
section={
functionSlug !== undefined
? ['edge-functions', functionSlug]
: ['edge-functions']
}
source="edge-functions"
/>
)}
<DocsButton href={`${DOCS_URL}/guides/functions`} />
<Popover_Shadcn_>
<PopoverTrigger_Shadcn_ asChild>
@@ -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')
})
@@ -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: <List size={ICON_SIZE} strokeWidth={ICON_STROKE_WIDTH} />,
link: ref && (unifiedLogsEnabled ? `/project/${ref}/logs` : `/project/${ref}/logs/explorer`),
},
...(apiDocsSidePanelEnabled
? [
{
key: 'api',
label: 'API Docs',
disabled: !isProjectActive,
icon: <FileText size={ICON_SIZE} strokeWidth={ICON_STROKE_WIDTH} />,
link:
ref &&
(isProjectBuilding ? buildingUrl : `/project/${ref}/integrations/data_api/docs`),
},
]
: []),
{
key: 'integrations',
label: 'Integrations',
@@ -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])
+8 -4
View File
@@ -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={<BookOpenText />}
className="w-7"
className={label ? undefined : 'w-7'}
tooltip={{
content: {
side: 'bottom',
text: 'API Docs',
text: tooltip ?? 'API Docs',
},
}}
/>
>
{label}
</ButtonTooltip>
)
}
@@ -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,