From 5fc0c86007b5b8493d90c52280177f32abcbc23e Mon Sep 17 00:00:00 2001 From: Miranda Limonczenko Date: Fri, 26 Jun 2026 12:11:19 -0700 Subject: [PATCH] feat(studio) Link observability pages to relevant docs (#47351) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes DOCS-488 Screenshot 2026-06-26 at 11 02
57 AM ## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## Problem We have helpful documentation that delves into each observability metric, but it is not easily findable in the moment it is needed while viewing the dashboards. ## Solution Solution includes: - Add a docs link in Studio in every relevant place with the `DocsButton` component - Add aria-hidden on the `DocsButton` icon - An added `constants.ts` to see all of the docs links in one place - A contextual aria-label for the docs so that screenreader users know where they're going | Page | Docs link | |------|-----------| | Overview | `/guides/telemetry/reports` | | Query Performance / Query Insights | `/guides/platform/performance#examining-query-performance` | | API Gateway | `/guides/telemetry/reports#api-gateway` | | Database | `/guides/telemetry/reports#database` | | Data API | `/guides/telemetry/reports#postgrest` | | Auth | `/guides/telemetry/reports#auth` | | Edge Functions | `/guides/telemetry/reports#edge-functions` | | Storage | `/guides/telemetry/reports#storage` | | Realtime | `/guides/realtime/reports` | | Custom reports | `/guides/telemetry/reports#using-reports` | Query Performance and Query Insights already had the button in their custom headers. They now use the shared constants. ## Tophatting 1. Go to a project `/observability`. 2. Click into each of the panels and see a **Docs** link in the top right. ## Summary by CodeRabbit * **New Features** * Added direct documentation links across observability report pages, making it easier to open relevant help content from each view. * Added clearer, page-specific labels for observability headers and docs links. * **Bug Fixes** * Improved accessibility for icon buttons so icons are hidden from assistive technologies while button labels remain clear. * Adjusted report navigation layouts to keep controls aligned with the new docs buttons. --- .../Observability/Observability.constants.ts | 15 +++++++ .../Observability/ObservabilityOverview.tsx | 7 +++- .../interfaces/Reports/ReportStickyNav.tsx | 2 +- .../components/interfaces/Reports/Reports.tsx | 23 ++++++---- apps/studio/components/ui/DocsButton.tsx | 10 ++++- .../[ref]/observability/api-overview.tsx | 11 +++-- .../project/[ref]/observability/auth.tsx | 11 +++-- .../project/[ref]/observability/database.tsx | 11 +++-- .../[ref]/observability/edge-functions.tsx | 11 +++-- .../project/[ref]/observability/postgrest.tsx | 11 +++-- .../[ref]/observability/query-insights.tsx | 10 ++--- .../[ref]/observability/query-performance.tsx | 10 ++--- .../project/[ref]/observability/realtime.tsx | 11 +++-- .../project/[ref]/observability/storage.tsx | 11 +++-- .../ui/src/components/Button/Button.test.tsx | 7 ++++ packages/ui/src/components/Button/Button.tsx | 42 ++++++++++--------- 16 files changed, 139 insertions(+), 64 deletions(-) create mode 100644 apps/studio/components/interfaces/Observability/Observability.constants.ts diff --git a/apps/studio/components/interfaces/Observability/Observability.constants.ts b/apps/studio/components/interfaces/Observability/Observability.constants.ts new file mode 100644 index 00000000000..2c47e519e38 --- /dev/null +++ b/apps/studio/components/interfaces/Observability/Observability.constants.ts @@ -0,0 +1,15 @@ +import { DOCS_URL } from '@/lib/constants' + +export const OBSERVABILITY_DOCS_HREFS = { + overview: `${DOCS_URL}/guides/telemetry/reports`, + queryPerformance: `${DOCS_URL}/guides/platform/performance#examining-query-performance`, + queryInsights: `${DOCS_URL}/guides/platform/performance#examining-query-performance`, + apiGateway: `${DOCS_URL}/guides/telemetry/reports#api-gateway`, + database: `${DOCS_URL}/guides/telemetry/reports#database`, + dataApi: `${DOCS_URL}/guides/telemetry/reports#postgrest`, + auth: `${DOCS_URL}/guides/telemetry/reports#auth`, + edgeFunctions: `${DOCS_URL}/guides/telemetry/reports#edge-functions`, + storage: `${DOCS_URL}/guides/telemetry/reports#storage`, + realtime: `${DOCS_URL}/guides/realtime/reports`, + customReport: `${DOCS_URL}/guides/telemetry/reports#using-reports`, +} as const diff --git a/apps/studio/components/interfaces/Observability/ObservabilityOverview.tsx b/apps/studio/components/interfaces/Observability/ObservabilityOverview.tsx index e18c746b70d..6eddc3a2299 100644 --- a/apps/studio/components/interfaces/Observability/ObservabilityOverview.tsx +++ b/apps/studio/components/interfaces/Observability/ObservabilityOverview.tsx @@ -8,12 +8,14 @@ import { Badge, Button, Tooltip, TooltipContent, TooltipTrigger } from 'ui' import { useUnifiedLogsPreview } from '../App/FeaturePreview/FeaturePreviewContext' import { DatabaseInfrastructureSection } from './DatabaseInfrastructureSection' +import { OBSERVABILITY_DOCS_HREFS } from './Observability.constants' import { useObservabilityOverviewData } from './ObservabilityOverview.utils' import { ObservabilityOverviewFooter } from './ObservabilityOverviewFooter' import { ServiceHealthTable } from './ServiceHealthTable' import { useSlowQueriesCount } from './useSlowQueriesCount' import ReportHeader from '@/components/interfaces/Reports/ReportHeader' import ReportPadding from '@/components/interfaces/Reports/ReportPadding' +import { DocsButton } from '@/components/ui/DocsButton' import { ChartIntervalDropdown } from '@/components/ui/Logs/ChartIntervalDropdown' import { CHART_INTERVALS } from '@/components/ui/Logs/logs.utils' import { ShortcutTooltip } from '@/components/ui/ShortcutTooltip' @@ -23,6 +25,8 @@ import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganizati import { SHORTCUT_IDS } from '@/state/shortcuts/registry' import { useShortcut } from '@/state/shortcuts/useShortcut' +const REPORT_TITLE = 'Overview' + type ChartIntervalKey = '1hr' | '1day' | '7day' export const ObservabilityOverview = () => { @@ -167,7 +171,7 @@ export const ObservabilityOverview = () => {
- + Beta @@ -178,6 +182,7 @@ export const ObservabilityOverview = () => {
+
-
+
{content}
diff --git a/apps/studio/components/interfaces/Reports/Reports.tsx b/apps/studio/components/interfaces/Reports/Reports.tsx index 9ee6bf22a91..5d69c83b2b4 100644 --- a/apps/studio/components/interfaces/Reports/Reports.tsx +++ b/apps/studio/components/interfaces/Reports/Reports.tsx @@ -12,10 +12,12 @@ import { ChartConfig } from '../SQLEditor/UtilityPanel/ChartConfig' import { GridResize } from './GridResize' import { MetricOptions } from './MetricOptions' import { LAYOUT_COLUMN_COUNT } from './Reports.constants' +import { OBSERVABILITY_DOCS_HREFS } from '@/components/interfaces/Observability/Observability.constants' import { DiscardChangesConfirmationDialog } from '@/components/ui-patterns/Dialogs/DiscardChangesConfirmationDialog' import { ButtonTooltip } from '@/components/ui/ButtonTooltip' import { DatabaseSelector } from '@/components/ui/DatabaseSelector' import { DateRangePicker } from '@/components/ui/DateRangePicker' +import { DocsButton } from '@/components/ui/DocsButton' import NoPermission from '@/components/ui/NoPermission' import { DEFAULT_CHART_CONFIG } from '@/components/ui/QueryBlock/QueryBlock' import { AnalyticsInterval } from '@/data/analytics/constants' @@ -366,12 +368,14 @@ const Reports = () => { return } + const reportTitle = currentReport?.name || 'Reports' + return ( <>
-

{currentReport?.name || 'Reports'}

+

{reportTitle}

{currentReport?.description}

{hasEdits && ( @@ -396,14 +400,6 @@ const Reports = () => {
- } - className="w-7" - disabled={isRefreshing} - tooltip={{ content: { side: 'bottom', text: 'Refresh report' } }} - onClick={onRefreshReport} - />
{
+ + } + className="w-7" + disabled={isRefreshing} + tooltip={{ content: { side: 'bottom', text: 'Refresh report' } }} + onClick={onRefreshReport} + /> {canUpdateReport ? ( diff --git a/apps/studio/components/ui/DocsButton.tsx b/apps/studio/components/ui/DocsButton.tsx index c4a0df06575..9a3de4e8e9e 100644 --- a/apps/studio/components/ui/DocsButton.tsx +++ b/apps/studio/components/ui/DocsButton.tsx @@ -5,9 +5,10 @@ interface DocsButtonProps { href: string abbrev?: boolean className?: string + topic?: string } -export const DocsButton = ({ href, abbrev = true, className }: DocsButtonProps) => { +export const DocsButton = ({ href, abbrev = true, className, topic }: DocsButtonProps) => { return ( diff --git a/apps/studio/pages/project/[ref]/observability/api-overview.tsx b/apps/studio/pages/project/[ref]/observability/api-overview.tsx index f50b4394f18..67d14e69527 100644 --- a/apps/studio/pages/project/[ref]/observability/api-overview.tsx +++ b/apps/studio/pages/project/[ref]/observability/api-overview.tsx @@ -1,5 +1,6 @@ import { useCallback } from 'react' +import { OBSERVABILITY_DOCS_HREFS } from '@/components/interfaces/Observability/Observability.constants' import { ErrorCountsChartRenderer, NetworkTrafficRenderer, @@ -18,11 +19,14 @@ import { DatePickerValue } from '@/components/interfaces/Settings/Logs/Logs.Date import UpgradePrompt from '@/components/interfaces/Settings/Logs/UpgradePrompt' import DefaultLayout from '@/components/layouts/DefaultLayout' import ObservabilityLayout from '@/components/layouts/ObservabilityLayout/ObservabilityLayout' +import { DocsButton } from '@/components/ui/DocsButton' import { ObservabilityLink } from '@/components/ui/ObservabilityLink' import { useApiReport } from '@/data/reports/api-report-query' import { useReportDateRange } from '@/hooks/misc/useReportDateRange' import type { NextPageWithLayout } from '@/types' +const REPORT_TITLE = 'API Gateway' + export const ApiReport: NextPageWithLayout = () => { const report = useApiReport() @@ -94,10 +98,10 @@ export const ApiReport: NextPageWithLayout = () => { return ( - + +
{ filters={filters} datepickerHelpers={datePickerHelpers} initialDatePickerValue={datePickerValue} - className="w-full" + className="flex-1 min-w-0" showDatabaseSelector={false} /> + ( export type UpdateDateRange = (from: string, to: string) => void export default AuthReport +const REPORT_TITLE = 'Auth' + const AuthUsage = () => { const { ref } = useParams() const chartSyncId = `auth-report` @@ -209,11 +213,12 @@ const AuthUsage = () => { return ( <> - + -
+
+
+ ( export type UpdateDateRange = (from: string, to: string) => void export default DatabaseReport +const REPORT_TITLE = 'Database' + const DatabaseUsage = () => { const { db, chart, ref } = useParams() const { data: project } = useSelectedProjectQuery() @@ -227,10 +231,11 @@ const DatabaseUsage = () => { return ( <> - + +
+ {
)}
- +
} > {selectedDateRange && diff --git a/apps/studio/pages/project/[ref]/observability/edge-functions.tsx b/apps/studio/pages/project/[ref]/observability/edge-functions.tsx index f322b664da3..953e1ddd4f4 100644 --- a/apps/studio/pages/project/[ref]/observability/edge-functions.tsx +++ b/apps/studio/pages/project/[ref]/observability/edge-functions.tsx @@ -6,6 +6,7 @@ import { parseAsJson, useQueryState } from 'nuqs' import { useMemo, useState } from 'react' import { Button } from 'ui' +import { OBSERVABILITY_DOCS_HREFS } from '@/components/interfaces/Observability/Observability.constants' import ReportHeader from '@/components/interfaces/Reports/ReportHeader' import ReportPadding from '@/components/interfaces/Reports/ReportPadding' import { @@ -28,6 +29,7 @@ import DefaultLayout from '@/components/layouts/DefaultLayout' import ObservabilityLayout from '@/components/layouts/ObservabilityLayout/ObservabilityLayout' import { ReportSettings } from '@/components/ui/Charts/ReportSettings' import { useChartHoverState } from '@/components/ui/Charts/useChartHoverState' +import { DocsButton } from '@/components/ui/DocsButton' import { ObservabilityLink } from '@/components/ui/ObservabilityLink' import { ShortcutTooltip } from '@/components/ui/ShortcutTooltip' import { useEdgeFunctionsQuery } from '@/data/edge-functions/edge-functions-query' @@ -54,6 +56,8 @@ EdgeFunctionsReportV2.getLayout = (page) => ( export default EdgeFunctionsReportV2 +const REPORT_TITLE = 'Edge Functions' + const EdgeFunctionsUsage = () => { const { ref } = useParams() const { data: functions } = useEdgeFunctionsQuery({ @@ -143,11 +147,12 @@ const EdgeFunctionsUsage = () => { return ( <> - + -
+
+
+ ( export type UpdateDateRange = (from: string, to: string) => void export default PostgRESTReport +const REPORT_TITLE = 'Data API' + const PostgrestReport = () => { const { db, chart } = useParams() const { @@ -115,11 +119,12 @@ const PostgrestReport = () => { return ( <> - + -
+
+
+ { const { selectedDateRange, datePickerValue, datePickerHelpers, handleDatePickerChange } = useReportDateRange(REPORT_DATERANGE_HELPER_LABELS.LAST_60_MINUTES) @@ -30,11 +32,9 @@ const QueryInsightsReport: NextPageWithLayout = () => { return (
-

Query Insights

+

{REPORT_TITLE}

- +