Skip to main content
Glama

Convex MCP server

Official
by get-convex
ChartForFunctionRate.tsx9.68 kB
import classNames from "classnames"; import { format } from "date-fns"; import { useState } from "react"; import { ResponsiveContainer, LineChart, XAxis, YAxis, Legend, Tooltip, Line, ReferenceLine, CartesianGrid, } from "recharts"; import { ChartTooltip } from "@common/elements/ChartTooltip"; import { useDeploymentAuditLogs } from "@common/lib/useDeploymentAuditLog"; import { timeLabelForMinute } from "@common/lib/format"; import { ChartData } from "@common/lib/charts/types"; import { DeploymentTimes } from "@common/features/health/components/DeploymentTimes"; import { Button } from "@ui/Button"; import { FunctionNameOption } from "@common/elements/FunctionNameOption"; import { LoadingTransition } from "@ui/Loading"; export function ChartForFunctionRate({ chartData, kind, }: { chartData: ChartData | undefined | null; kind: "cacheHitRate" | "failureRate" | "schedulerStatus"; }) { const [shown, setShown] = useState<string | null>(null); const [startDate] = useState(new Date(Date.now() - 3600 * 1000)); const auditLogs = useDeploymentAuditLogs(startDate.getTime(), { actions: ["push_config", "push_config_with_components"], }); const deploysByMinute = auditLogs?.map( (log) => { const creationDate = new Date(log._creationTime); return { hour: format(creationDate, "h:mm a"), timestamp: log._creationTime, }; }, {} as Record<string, { hour: string; timestamp: number }[]>, ); return ( <div className="h-full min-h-52 w-full"> <LoadingTransition loadingProps={{ fullHeight: false, className: "h-[9rem] w-full", }} > {chartData === null ? ( <div className="flex h-[11.25rem] w-full items-center justify-center px-12 text-center text-sm text-content-secondary"> Data will appear here as your{" "} {kind === "cacheHitRate" ? "queries" : "functions"} are called. </div> ) : chartData === undefined ? null : ( <ResponsiveContainer width="95%" height="95%"> <LineChart data={chartData.data} style={{ fontSize: 11, }} > {/* Show a reference line for each time bucket that had a deployment */} {deploysByMinute?.map(({ hour, timestamp }) => ( <ReferenceLine key={timestamp} x={hour} stroke="var(--brand-yellow)" strokeDasharray="3 3" /> ))} <XAxis axisLine={false} tickLine={false} dataKey="time" strokeWidth={1} domain={["auto", "auto"]} minTickGap={25} className="stroke-content-secondary" tick={{ fontSize: 11, fill: "currentColor" }} /> <YAxis axisLine={false} tickLine={false} width={40} tickFormatter={(value) => kind === "schedulerStatus" ? value : `${value.toFixed((value as number) % 1 === 0 ? 0 : 2)}%` } ticks={ kind !== "schedulerStatus" ? [0, 25, 50, 75, 100] : undefined } className="stroke-content-secondary" tick={{ fontSize: 11, fill: "currentColor" }} /> <Legend content={({ payload }) => ( <div className="flex max-h-12 max-w-full flex-wrap items-start gap-2 px-2 text-[11px]"> {payload?.map((entry, idx) => { const { dataKey, color } = entry; return ( <Button variant="unstyled" key={idx} className={classNames( "flex items-center gap-1 transition-opacity", shown === dataKey || shown === null ? "opacity-100" : "opacity-50", )} onClick={() => shown === dataKey ? setShown(null) : setShown(dataKey as string) } > <div className="h-0.5 w-2.5 shrink-0" style={{ backgroundColor: color }} /> {dataKey === "_rest" ? ( `All${payload.length > 1 ? " other" : ""} ${kind === "cacheHitRate" ? "queries" : "functions"}` ) : kind === "schedulerStatus" ? ( "Lag Time (minutes)" ) : ( <FunctionNameOption maxChars={24} label={dataKey as string} /> )} </Button> ); })} </div> )} /> <Tooltip animationDuration={100} content={({ active, payload, label }) => { const deploymentTimes = deploysByMinute ?.filter((deploy) => deploy.hour === label) .map((deploy) => format(new Date(deploy.timestamp), "pp")); return ( <ChartTooltip active={active} payload={payload ?.filter( ({ dataKey }) => shown === dataKey || shown === null, ) .map((dataPoint) => ({ ...dataPoint, formattedValue: ( <span className="flex min-w-48 items-center justify-between"> <div> {dataPoint.dataKey === "_rest" ? ( `All${payload.length > 1 ? " other" : ""} ${kind === "cacheHitRate" ? "queries" : "functions"}` ) : kind === "schedulerStatus" ? ( "Lag Time" ) : ( <FunctionNameOption maxChars={24} label={dataPoint.dataKey as string} /> )} </div> <div> {kind === "schedulerStatus" ? `${(dataPoint.value as number).toLocaleString()} minutes` : `${(dataPoint.value as number).toFixed( (dataPoint.value as number) % 1 === 0 ? 0 : 2, )}%`} </div> </span> ), }))} extraContent={ <DeploymentTimes deploymentTimes={deploymentTimes} /> } label={timeLabelForMinute(label)} showLegend /> ); }} /> <CartesianGrid className="stroke-content-tertiary/40" horizontal strokeWidth={1} vertical={false} verticalFill={[]} horizontalFill={[ "color-mix(in srgb, var(--background-tertiary) 33%, transparent)", ]} syncWithTicks horizontalValues={ kind !== "schedulerStatus" ? // For some reason (likely due to the size of the chart), ticks don't appear at 75 if the value is exactly 75. So, get as close to 75 as possible [0, 25, 50, 74.99, 100] : undefined } /> {chartData.lineKeys.map((line) => { const dataKey = line.key; const { name } = line; const { color } = line; return ( <Line isAnimationActive={false} strokeWidth={1.5} activeDot={{ r: 4, className: "stroke-none", display: shown === dataKey || shown === null ? "block" : "none", }} key={dataKey} dataKey={dataKey} name={name} min={0} display={ shown === dataKey || shown === null ? "block" : "none" } className="transition-opacity" stroke={color} fillOpacity={1} fill={`url(#${dataKey})`} dot={false} /> ); })} </LineChart> </ResponsiveContainer> )} </LoadingTransition> </div> ); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/get-convex/convex-backend'

If you have feedback or need assistance with the MCP directory API, please join our Discord server