Files
supabase/apps/studio/components/layouts/ObservabilityLayout/ObservabilityLayout.tsx
Joshen Lim 073cada53a Fix observability custom reports menu item (#47759)
## Context

More action button should be flushed to the right here
<img width="294" height="156" alt="image"
src="https://github.com/user-attachments/assets/65017960-3edb-4268-bb0e-1e2c26937d4b"
/>

## Changes involved
- Adjust `Menu.Item` in `packages/ui` to use a `div` instead of a `span`
- Was otherwise causing HTML validation issues as we were trying to nest
a `div` within a `span`
- Having a `div` is a bit more flexible as well since `Menu.Item`
expects `children` to be of any type (e.g a react node)

<img width="279" height="149" alt="image"
src="https://github.com/user-attachments/assets/12730cef-b077-4ef4-93c9-c21def939888"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Standardized the Observability menu component to use named exports,
ensuring consistent usage across the app.
* Updated the mobile observability menu registration to reference the
correct exported component.
* **Style**
* Refined Observability menu item layout, spacing, truncation, and
dropdown sizing for a cleaner presentation.
* Enhanced menu item rendering to allow custom `className` styling and
full-width content layout.
* **Accessibility**
* Added an aria-label to the “more actions” button for improved screen
reader support.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-09 17:08:11 +08:00

113 lines
3.4 KiB
TypeScript

import { IS_PLATFORM, LOCAL_STORAGE_KEYS, useParams } from 'common'
import { usePathname } from 'next/navigation'
import { PropsWithChildren, useEffect, useRef } from 'react'
import { ProjectLayout } from '../ProjectLayout'
import { ObservabilityMenu } from './ObservabilityMenu'
import { useIndexAdvisorStatus } from '@/components/interfaces/QueryPerformance/hooks/useIsIndexAdvisorStatus'
import { BannerIndexAdvisor } from '@/components/ui/BannerStack/Banners/BannerIndexAdvisor'
import { BannerMetricsAPI } from '@/components/ui/BannerStack/Banners/BannerMetricsAPI'
import { useBannerStack } from '@/components/ui/BannerStack/BannerStackProvider'
import { UnknownInterface } from '@/components/ui/UnknownInterface'
import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage'
import { withAuth } from '@/hooks/misc/withAuth'
interface ObservabilityLayoutProps {
title: string
}
const ObservabilityLayoutContent = ({
title,
children,
}: PropsWithChildren<ObservabilityLayoutProps>) => {
const { ref } = useParams()
const pathname = usePathname()
const { addBanner, dismissBanner } = useBannerStack()
const { isIndexAdvisorAvailable, isIndexAdvisorEnabled } = useIndexAdvisorStatus()
const [isMetricsBannerDismissed] = useLocalStorageQuery(
LOCAL_STORAGE_KEYS.OBSERVABILITY_BANNER_DISMISSED(ref ?? ''),
false
)
const [isIndexAdvisorBannerDismissed] = useLocalStorageQuery(
LOCAL_STORAGE_KEYS.INDEX_ADVISOR_NOTICE_DISMISSED(ref ?? ''),
false
)
useEffect(() => {
if (!isMetricsBannerDismissed && IS_PLATFORM) {
addBanner({
id: 'metrics-api-banner',
isDismissed: false,
content: <BannerMetricsAPI />,
priority: 1,
})
} else {
dismissBanner('metrics-api-banner')
}
}, [isMetricsBannerDismissed, addBanner, dismissBanner])
const prevPathnameRef = useRef(pathname)
useEffect(() => {
const isQueryPerformancePage = pathname?.includes('/query-performance')
if (
isQueryPerformancePage &&
isIndexAdvisorAvailable &&
!isIndexAdvisorEnabled &&
!isIndexAdvisorBannerDismissed
) {
addBanner({
id: 'index-advisor-banner',
isDismissed: false,
content: <BannerIndexAdvisor />,
priority: 3,
})
} else if (isIndexAdvisorBannerDismissed || !isQueryPerformancePage || isIndexAdvisorEnabled) {
dismissBanner('index-advisor-banner')
}
prevPathnameRef.current = pathname
}, [
pathname,
isIndexAdvisorAvailable,
isIndexAdvisorEnabled,
isIndexAdvisorBannerDismissed,
addBanner,
dismissBanner,
])
const { reportsAll } = useIsFeatureEnabled(['reports:all'])
if (reportsAll) {
return (
<ProjectLayout
product="Observability"
browserTitle={{ section: title }}
productMenu={<ObservabilityMenu />}
isBlocking={false}
>
{children}
</ProjectLayout>
)
} else {
return <UnknownInterface urlBack={`/project/${ref}`} />
}
}
const ObservabilityLayout = (props: PropsWithChildren<ObservabilityLayoutProps>) => {
const { ref } = useParams()
const { reportsAll } = useIsFeatureEnabled(['reports:all'])
if (reportsAll) {
return <ObservabilityLayoutContent {...props} />
} else {
return <UnknownInterface urlBack={`/project/${ref}`} />
}
}
export default withAuth(ObservabilityLayout)