Files
supabase/apps/studio/components/ui/Logs/ChartIntervalDropdown.tsx
Jordi Enric 168c084f4e feat(o11y): overview page (#42098)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Observability Dashboard: unified overview for service health and
database infrastructure with interactive charts and metric cards (CPU,
memory, disk I/O, connections, error rate, slow queries).
* Service Health Monitoring: per-service health cards and a
multi-service table with error/warning counts and drill-down links to
reports/logs.
* Interval Selector: new chart-interval dropdown with plan-aware
retention messaging.
* Menu & Reports: updated Observability menu with Overview entry and
Custom Reports management.
* **Documentation**
  * Added a footer link to troubleshooting guides.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-01-30 14:00:01 +00:00

99 lines
3.3 KiB
TypeScript

import { InlineLink } from 'components/ui/InlineLink'
import { ChevronDown } from 'lucide-react'
import {
Button,
DropdownMenu,
DropdownMenuContent,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuTrigger,
Tooltip,
TooltipContent,
TooltipTrigger,
} from 'ui'
import { CHART_INTERVALS, LOG_RETENTION } from './logs.utils'
type PlanId = keyof typeof LOG_RETENTION
interface ChartIntervalDropdownProps {
value: string
onChange: (value: string) => void
planId?: string
planName?: string
organizationSlug?: string
dropdownAlign?: 'start' | 'center' | 'end'
tooltipSide?: 'left' | 'right' | 'top' | 'bottom'
}
export const ChartIntervalDropdown = ({
value,
onChange,
planId = 'free',
planName,
organizationSlug,
dropdownAlign = 'start',
tooltipSide = 'right',
}: ChartIntervalDropdownProps) => {
const selectedInterval = CHART_INTERVALS.find((i) => i.key === value) || CHART_INTERVALS[1]
const normalizedPlanId = (planId && planId in LOG_RETENTION ? planId : 'free') as PlanId
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button type="default" iconRight={<ChevronDown size={14} />}>
<span>{selectedInterval.label}</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent side="bottom" align={dropdownAlign} className="w-40">
<DropdownMenuRadioGroup value={value} onValueChange={onChange}>
{CHART_INTERVALS.map((i) => {
const disabled = !i.availableIn?.includes(normalizedPlanId)
if (disabled) {
const retentionDuration = LOG_RETENTION[normalizedPlanId]
return (
<Tooltip key={i.key}>
<TooltipTrigger asChild>
<DropdownMenuRadioItem disabled value={i.key} className="!pointer-events-auto">
{i.label}
</DropdownMenuRadioItem>
</TooltipTrigger>
<TooltipContent side={tooltipSide}>
<p>
{planName} plan only includes up to {retentionDuration} day
{retentionDuration > 1 ? 's' : ''} of log retention
</p>
<p className="text-foreground-light">
{organizationSlug ? (
<>
<InlineLink
className="text-foreground-light hover:text-foreground"
href={`/org/${organizationSlug}/billing?panel=subscriptionPlan`}
>
Upgrade your plan
</InlineLink>{' '}
to increase log retention and view statistics for the{' '}
{i.label.toLowerCase()}
</>
) : (
`Upgrade your plan to increase log retention and view statistics for the ${i.label.toLowerCase()}`
)}
</p>
</TooltipContent>
</Tooltip>
)
} else {
return (
<DropdownMenuRadioItem key={i.key} value={i.key}>
{i.label}
</DropdownMenuRadioItem>
)
}
})}
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
)
}