refactor: replace MUI tooltip in WorkspaceTimings (#21107)

for #19974 

Continuing the train of thought from
https://github.com/coder/coder/pull/20849#issuecomment-3560666271: it's
probably better to do away with a custom tooltip component that's only
used in `ResourcesChart`/`ScriptsChart`/`StagesChart` and only slightly
differs from our base tooltip
This commit is contained in:
Andrew Aquino
2025-12-09 14:19:24 -08:00
committed by GitHub
parent 8f15caad22
commit fca93438ee
4 changed files with 92 additions and 175 deletions
@@ -1,81 +0,0 @@
import { css } from "@emotion/css";
import { type Interpolation, type Theme, useTheme } from "@emotion/react";
import MUITooltip, {
type TooltipProps as MUITooltipProps,
} from "@mui/material/Tooltip";
import { ExternalLinkIcon } from "lucide-react";
import type { FC, HTMLProps } from "react";
import { Link, type LinkProps } from "react-router";
export type TooltipProps = MUITooltipProps;
export const Tooltip: FC<TooltipProps> = (props) => {
const theme = useTheme();
return (
<MUITooltip
classes={{
tooltip: css(styles.tooltip(theme)),
...props.classes,
}}
{...props}
/>
);
};
export const TooltipTitle: FC<HTMLProps<HTMLSpanElement>> = (props) => {
return <span css={styles.title} {...props} />;
};
export const TooltipShortDescription: FC<HTMLProps<HTMLSpanElement>> = (
props,
) => {
return <span css={styles.shortDesc} {...props} />;
};
export const TooltipLink: FC<LinkProps> = (props) => {
return (
<Link {...props} css={styles.link}>
<ExternalLinkIcon className="size-icon-xs" />
{props.children}
</Link>
);
};
const styles = {
tooltip: (theme) => ({
backgroundColor: theme.palette.background.default,
border: `1px solid ${theme.palette.divider}`,
maxWidth: "max-content",
borderRadius: 8,
display: "flex",
flexDirection: "column",
fontWeight: 500,
fontSize: 12,
color: theme.palette.text.secondary,
gap: 4,
}),
title: (theme) => ({
color: theme.palette.text.primary,
display: "block",
}),
link: (theme) => ({
color: "inherit",
textDecoration: "none",
display: "flex",
alignItems: "center",
gap: 4,
"&:hover": {
color: theme.palette.text.primary,
},
"& svg": {
width: 12,
height: 12,
},
}),
shortDesc: {
maxWidth: 280,
},
} satisfies Record<string, Interpolation<Theme>>;
@@ -1,5 +1,12 @@
import { type Theme, useTheme } from "@emotion/react";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "components/Tooltip/Tooltip";
import { ExternalLinkIcon } from "lucide-react";
import { type FC, useState } from "react";
import { Link } from "react-router";
import { Bar } from "./Chart/Bar";
import {
Chart,
@@ -10,7 +17,6 @@ import {
ChartSearch,
ChartToolbar,
} from "./Chart/Chart";
import { Tooltip, TooltipLink, TooltipTitle } from "./Chart/Tooltip";
import {
calcDuration,
calcOffset,
@@ -116,23 +122,31 @@ export const ResourcesChart: FC<ResourcesChartProps> = ({
key={t.name}
yAxisLabelId={encodeURIComponent(t.name)}
>
<Tooltip
title={
<>
<TooltipTitle>{label}</TooltipTitle>
{/* Stage boundaries should not have these links */}
{!stageBoundary && (
<TooltipLink to="">view template</TooltipLink>
)}
</>
}
>
<Bar
value={duration}
offset={calcOffset(t.range, generalTiming)}
scale={scale}
colors={legend.colors}
/>
<Tooltip>
<TooltipTrigger asChild>
<Bar
value={duration}
offset={calcOffset(t.range, generalTiming)}
scale={scale}
colors={legend.colors}
/>
</TooltipTrigger>
<TooltipContent
side="bottom"
className="flex flex-col gap-1.5 border-surface-quaternary"
>
<p className="m-0 text-content-primary">{label}</p>
{/* Stage boundaries should not have these links */}
{!stageBoundary && (
<Link
to=""
className="flex items-center gap-1 no-underline text-xs text-inherit hover:text-content-primary"
>
<ExternalLinkIcon className="size-icon-xs" />
view template
</Link>
)}
</TooltipContent>
</Tooltip>
{formatTime(duration)}
</XAxisRow>
@@ -1,4 +1,9 @@
import { type Theme, useTheme } from "@emotion/react";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "components/Tooltip/Tooltip";
import { type FC, useState } from "react";
import { Bar } from "./Chart/Bar";
import {
@@ -10,7 +15,6 @@ import {
ChartSearch,
ChartToolbar,
} from "./Chart/Chart";
import { Tooltip, TooltipTitle } from "./Chart/Tooltip";
import {
calcDuration,
calcOffset,
@@ -103,19 +107,21 @@ export const ScriptsChart: FC<ScriptsChartProps> = ({
key={t.name}
yAxisLabelId={encodeURIComponent(t.name)}
>
<Tooltip
title={
<TooltipTitle>
Script exited with <strong>code {t.exitCode}</strong>
</TooltipTitle>
}
>
<Bar
value={duration}
offset={calcOffset(t.range, generalTiming)}
scale={scale}
colors={legendsByStatus[t.status].colors}
/>
<Tooltip>
<TooltipTrigger asChild>
<Bar
value={duration}
offset={calcOffset(t.range, generalTiming)}
scale={scale}
colors={legendsByStatus[t.status].colors}
/>
</TooltipTrigger>
<TooltipContent
side="bottom"
className="border-surface-quaternary text-content-primary"
>
Script exited with <strong>code {t.exitCode}</strong>
</TooltipContent>
</Tooltip>
{formatTime(duration)}
@@ -1,16 +1,15 @@
import type { Interpolation, Theme } from "@emotion/react";
import type { TimingStage } from "api/typesGenerated";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "components/Tooltip/Tooltip";
import { CircleAlertIcon, InfoIcon } from "lucide-react";
import type { FC } from "react";
import { Bar, ClickableBar } from "./Chart/Bar";
import { Blocks } from "./Chart/Blocks";
import { Chart, ChartContent } from "./Chart/Chart";
import {
Tooltip,
type TooltipProps,
TooltipShortDescription,
TooltipTitle,
} from "./Chart/Tooltip";
import {
calcDuration,
calcOffset,
@@ -45,7 +44,10 @@ export type Stage = {
/**
* The tooltip is used to provide additional information about the stage.
*/
tooltip: Omit<TooltipProps, "children">;
tooltip: {
heading: string;
description: string;
};
};
type StageTiming = {
@@ -105,11 +107,22 @@ export const StagesChart: FC<StagesChartProps> = ({
>
<span css={styles.stageLabel}>
{stage.label}
<Tooltip {...stage.tooltip}>
<InfoIcon
className="size-icon-xs"
css={styles.info}
/>
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon
className="size-icon-xs"
css={styles.info}
/>
</TooltipTrigger>
<TooltipContent
side="bottom"
className="flex flex-col gap-1.5 max-w-xs border-surface-quaternary"
>
<p className="m-0 text-content-primary">
{stage.tooltip.heading}
</p>
<p className="m-0">{stage.tooltip.description}</p>
</TooltipContent>
</Tooltip>
</span>
</YAxisLabel>
@@ -219,14 +232,8 @@ export const provisioningStages: Stage[] = [
label: "init",
section: "provisioning",
tooltip: {
title: (
<>
<TooltipTitle>Terraform initialization</TooltipTitle>
<TooltipShortDescription>
Download providers & modules.
</TooltipShortDescription>
</>
),
heading: "Terraform initialization",
description: "Download providers & modules.",
},
},
{
@@ -234,15 +241,9 @@ export const provisioningStages: Stage[] = [
label: "plan",
section: "provisioning",
tooltip: {
title: (
<>
<TooltipTitle>Terraform plan</TooltipTitle>
<TooltipShortDescription>
Compare state of desired vs actual resources and compute changes to
be made.
</TooltipShortDescription>
</>
),
heading: "Terraform plan",
description:
"Compare state of desired vs actual resources and compute changes to be made.",
},
},
{
@@ -250,14 +251,9 @@ export const provisioningStages: Stage[] = [
label: "graph",
section: "provisioning",
tooltip: {
title: (
<>
<TooltipTitle>Terraform graph</TooltipTitle>
<TooltipShortDescription>
List all resources in plan, used to update coderd database.
</TooltipShortDescription>
</>
),
heading: "Terraform graph",
description:
"List all resources in plan, used to update coderd database.",
},
},
{
@@ -265,15 +261,9 @@ export const provisioningStages: Stage[] = [
label: "apply",
section: "provisioning",
tooltip: {
title: (
<>
<TooltipTitle>Terraform apply</TooltipTitle>
<TooltipShortDescription>
Execute Terraform plan to create/modify/delete resources into
desired states.
</TooltipShortDescription>
</>
),
heading: "Terraform apply",
description:
"Execute Terraform plan to create/modify/delete resources into desired states.",
},
},
];
@@ -285,14 +275,8 @@ export const agentStages = (section: string): Stage[] => {
label: "connect",
section,
tooltip: {
title: (
<>
<TooltipTitle>Connect</TooltipTitle>
<TooltipShortDescription>
Establish an RPC connection with the control plane.
</TooltipShortDescription>
</>
),
heading: "Connect",
description: "Establish an RPC connection with the control plane.",
},
},
{
@@ -300,14 +284,8 @@ export const agentStages = (section: string): Stage[] => {
label: "run startup scripts",
section,
tooltip: {
title: (
<>
<TooltipTitle>Run startup scripts</TooltipTitle>
<TooltipShortDescription>
Execute each agent startup script.
</TooltipShortDescription>
</>
),
heading: "Run startup scripts",
description: "Execute each agent startup script.",
},
},
];