Files
supabase/apps/studio/pages/project/[ref]/observability/api-overview.tsx
T
Alaister YoungandAlaister Young b0e31be89a chore(studio): remove dead code found by knip (#49719)
Removes Studio code that nothing imports, as reported by knip. First PR
in a stack of three: this one is pure deletions, #49720 removes the
unused dependencies, #49721 upgrades knip and adds the CI gate so this
doesn't accumulate again.

Every file was verified with a repo-wide grep for its basename, exported
symbols, and string/dynamic imports before deletion — none are reachable
via `next/dynamic`, a barrel file, or a config.

**Removed:**
-
`Billing/Usage/UsageWarningAlerts/{CPU,RAM,DiskIOBandwidth}Warnings.tsx`
(whole directory)
- `DataWarehouse/FormFooterChangeBadge.tsx` (whole directory)
- `Database/Replication/ReplicationDiagram/EmptyReplicationDiagram.tsx`
- `Integrations/Vercel/OrganizationPicker.tsx`
- `QueryInsights/QueryInsightsTable/QueryInsightsTableRow.tsx`
- `hooks/misc/useTrackExperimentExposure.ts`
- `data/ai/{parse-client-code,sql-policy}-mutation.ts`,
`data/misc/parse-query-mutation.ts`,
`data/database/table-check-rls-mutation.ts`
-
`data/notifications/notifications-v2-{archive-all-mutation,summary-query}.ts`
+ their two now-unused keys in `notifications/keys.ts` (`listV2` kept)
-
`data/platform-apps/platform-app-{update,signing-key-delete}-mutation.ts`
- `DateTimeFormats.DATE_ONLY` and the unused
`Notebooks.{MarkdownCell,LogCell,ChartConfig}` types

**Changed:**
- `ReportPadding` no longer has a duplicate default export; its 9
default importers (observability pages) now use the named export

Not removed: `CONSTRAINT_TYPE`'s unused members mirror the closed set of
`pg_constraint.contype` values, so they're documentation rather than
dead code — suppressed narrowly in #49721's knip config instead.

## To test

- `pnpm --filter studio run typecheck` and `lint:ratchet` pass
- Observability pages (`/project/[ref]/observability/*`) still render
with padding — they're the only code touched, via the `ReportPadding`
import change
- Notifications popover still loads and marks-as-read (the removed keys
weren't used for invalidation)


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

## Summary by CodeRabbit

- **Removed Features**
  - Removed CPU, memory, and disk usage warning alerts.
- Removed the Vercel organization picker and empty replication diagram.
  - Removed query insights row actions and several SQL assistance tools.
  - Removed notification summary and archive-all capabilities.
  - Removed platform app update and signing-key deletion actions.
- Removed the form change-count badge and experiment exposure tracking.

- **Refactor**
- Updated observability reports to use the revised report layout export.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-08-31 10:55:23 +08:00

201 lines
7.0 KiB
TypeScript

import { useCallback } from 'react'
import { OBSERVABILITY_DOCS_HREFS } from '@/components/interfaces/Observability/Observability.constants'
import {
ErrorCountsChartRenderer,
NetworkTrafficRenderer,
RequestsByCountryMapRenderer,
ResponseSpeedChartRenderer,
TopApiRoutesRenderer,
TotalRequestsChartRenderer,
} from '@/components/interfaces/Reports/renderers/ApiRenderers'
import ReportFilterBar from '@/components/interfaces/Reports/ReportFilterBar'
import ReportHeader from '@/components/interfaces/Reports/ReportHeader'
import { ReportPadding } from '@/components/interfaces/Reports/ReportPadding'
import { REPORT_DATERANGE_HELPER_LABELS } from '@/components/interfaces/Reports/Reports.constants'
import ReportStickyNav from '@/components/interfaces/Reports/ReportStickyNav'
import ReportWidget from '@/components/interfaces/Reports/ReportWidget'
import { DatePickerValue } from '@/components/interfaces/Settings/Logs/Logs.DatePickers'
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()
const {
data,
error,
filters,
isLoading,
params,
mergeParams,
removeFilters,
addFilter,
refresh,
} = report
const {
datePickerHelpers,
datePickerValue,
handleDatePickerChange: handleDatePickerChangeFromHook,
showUpgradePrompt,
setShowUpgradePrompt,
} = useReportDateRange(REPORT_DATERANGE_HELPER_LABELS.LAST_60_MINUTES)
const handleDatepickerChange = useCallback(
(vals: DatePickerValue) => {
const promptShown = handleDatePickerChangeFromHook(vals)
if (!promptShown) {
mergeParams({
iso_timestamp_start: vals.from ?? '',
iso_timestamp_end: vals.to ?? '',
})
}
},
[handleDatePickerChangeFromHook, mergeParams]
)
const handleDatepickerChangeForRefresh = useCallback(
(vals: DatePickerValue) => {
handleDatePickerChangeFromHook(vals)
mergeParams({
iso_timestamp_start: vals.from ?? '',
iso_timestamp_end: vals.to ?? '',
})
handleDatepickerChange(vals)
},
[handleDatePickerChangeFromHook, mergeParams, handleDatepickerChange]
)
const refreshWithParams = useCallback(async () => {
await new Promise((resolve) => setTimeout(resolve, 0))
refresh()
}, [refresh])
const onRefreshReport = useCallback(async () => {
if (datePickerValue.isHelper && datePickerValue.text) {
const selectedHelper = datePickerHelpers.find((h) => h.text === datePickerValue.text)
if (selectedHelper) {
handleDatepickerChangeForRefresh({
from: selectedHelper.calcFrom(),
to: selectedHelper.calcTo(),
isHelper: true,
text: selectedHelper.text,
})
}
}
await refreshWithParams()
}, [datePickerValue, datePickerHelpers, handleDatepickerChangeForRefresh, refreshWithParams])
return (
<ReportPadding>
<ReportHeader title={REPORT_TITLE} showDatabaseSelector={false} />
<ReportStickyNav
content={
<div className="flex w-full items-center gap-3">
<ReportFilterBar
onRemoveFilters={removeFilters}
onDatepickerChange={handleDatepickerChange}
datepickerFrom={params.totalRequests.iso_timestamp_start}
datepickerTo={params.totalRequests.iso_timestamp_end}
onAddFilter={addFilter}
onRefresh={onRefreshReport}
isLoading={isLoading}
filters={filters}
datepickerHelpers={datePickerHelpers}
initialDatePickerValue={datePickerValue}
className="flex-1 min-w-0"
showDatabaseSelector={false}
/>
<DocsButton href={OBSERVABILITY_DOCS_HREFS.apiGateway} topic={REPORT_TITLE} />
<UpgradePrompt
show={showUpgradePrompt}
setShowUpgradePrompt={setShowUpgradePrompt}
title="Report date range"
description="Report data can be stored for a maximum of 3 months depending on the plan that your project is on."
source="apiReportDateRange"
/>
</div>
}
>
<ReportWidget
isLoading={isLoading}
params={params.requestsByCountry}
error={error.requestsByCountry}
title="Requests by Geography"
tooltip="Number of API Gateway requests per geography"
data={data.requestsByCountry || []}
renderer={RequestsByCountryMapRenderer}
contentClassName="p-0 overflow-hidden"
headerClassName="px-4 pt-4"
/>
<ReportWidget
isLoading={isLoading}
params={params.totalRequests}
title="Total Requests"
data={data.totalRequests || []}
error={error.totalRequest}
renderer={TotalRequestsChartRenderer}
append={TopApiRoutesRenderer}
appendProps={{ data: data.topRoutes || [], params: params.topRoutes }}
/>
<ReportWidget
isLoading={isLoading}
params={params.errorCounts}
title="Response Errors"
tooltip="Error responses with 4XX or 5XX status codes"
data={data.errorCounts || []}
error={error.errorCounts}
renderer={ErrorCountsChartRenderer}
appendProps={{
data: data.topErrorRoutes || [],
params: params.topErrorRoutes,
}}
append={TopApiRoutesRenderer}
/>
<ReportWidget
isLoading={isLoading}
params={params.responseSpeed}
title="Response Speed"
tooltip="Average response speed of a request (in ms)"
data={data.responseSpeed || []}
error={error.responseSpeed}
renderer={ResponseSpeedChartRenderer}
appendProps={{ data: data.topSlowRoutes || [], params: params.topSlowRoutes }}
append={TopApiRoutesRenderer}
/>
<ReportWidget
isLoading={isLoading}
params={params.networkTraffic}
error={error.networkTraffic}
title="Network Traffic"
tooltip="Ingress and egress of requests and responses respectively"
data={data.networkTraffic || []}
renderer={NetworkTrafficRenderer}
/>
</ReportStickyNav>
<div className="py-8">
<ObservabilityLink />
</div>
</ReportPadding>
)
}
ApiReport.getLayout = (page) => (
<DefaultLayout>
<ObservabilityLayout title="API Gateway">{page}</ObservabilityLayout>
</DefaultLayout>
)
export default ApiReport