refactor: replace Popover with Tooltip in HelpTooltip (#19635)

for #19397 

Currently there are 24 files that import bindings from the deprecated
`Popover` component. One of those is `HelpTooltip`, which is
instantiated in 24 other files. After this PR, the remaining files that
import the deprecated `Popover` should be able to be migrated in just
1-2 more PRs. 🤞🏽

I opted for `Tooltip` as a replacement because it's triggered on hover,
unlike our new `Popover` which is triggered on click.
This commit is contained in:
Andrew Aquino
2025-09-08 10:59:09 -07:00
committed by GitHub
parent d7d69d1ce9
commit ff18499cb0
26 changed files with 211 additions and 178 deletions
@@ -7,9 +7,9 @@ import {
import {
HelpTooltip,
HelpTooltipContent,
HelpTooltipIconTrigger,
HelpTooltipText,
HelpTooltipTitle,
HelpTooltipTrigger,
} from "components/HelpTooltip/HelpTooltip";
import type { FC } from "react";
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from "recharts";
@@ -116,7 +116,7 @@ export const ActiveUsersTitle: FC<ActiveUsersTitleProps> = ({ interval }) => {
<div className="flex items-center gap-2">
{interval === "day" ? "Daily" : "Weekly"} Active Users
<HelpTooltip>
<HelpTooltipTrigger size="small" />
<HelpTooltipIconTrigger size="small" />
<HelpTooltipContent>
<HelpTooltipTitle>How do we calculate active users?</HelpTooltipTitle>
<HelpTooltipText>
+35 -35
View File
@@ -3,18 +3,17 @@ import {
css,
type Interpolation,
type Theme,
useTheme,
} from "@emotion/react";
import Link from "@mui/material/Link";
import {
Popover,
PopoverContent,
type PopoverContentProps,
type PopoverProps,
PopoverTrigger,
usePopover,
} from "components/deprecated/Popover/Popover";
import { Stack } from "components/Stack/Stack";
import {
Tooltip,
TooltipContent,
type TooltipContentProps,
type TooltipProps,
TooltipProvider,
TooltipTrigger,
} from "components/Tooltip/Tooltip";
import { CircleHelpIcon, ExternalLinkIcon } from "lucide-react";
import {
type FC,
@@ -23,43 +22,50 @@ import {
type PropsWithChildren,
type ReactNode,
} from "react";
import { cn } from "utils/cn";
type Icon = typeof CircleHelpIcon;
type Size = "small" | "medium";
export const HelpTooltipTrigger = TooltipTrigger;
export const HelpTooltipIcon = CircleHelpIcon;
export const HelpTooltip: FC<PopoverProps> = (props) => {
return <Popover mode="hover" {...props} />;
export const HelpTooltip: FC<TooltipProps> = (props) => {
return (
<TooltipProvider>
<Tooltip delayDuration={0} {...props} />
</TooltipProvider>
);
};
export const HelpTooltipContent: FC<PopoverContentProps> = (props) => {
const theme = useTheme();
export const HelpTooltipContent: FC<TooltipContentProps> = ({
className,
...props
}) => {
return (
<PopoverContent
<TooltipContent
side="bottom"
align="start"
collisionPadding={16}
{...props}
css={{
"& .MuiPaper-root": {
fontSize: 14,
width: 304,
padding: 20,
color: theme.palette.text.secondary,
},
}}
className={cn(
"w-[320px] p-5 bg-surface-secondary border-surface-quaternary text-sm",
className,
)}
/>
);
};
type HelpTooltipTriggerProps = HTMLAttributes<HTMLButtonElement> & {
type HelpTooltipIconTriggerProps = HTMLAttributes<HTMLButtonElement> & {
size?: Size;
hoverEffect?: boolean;
};
export const HelpTooltipTrigger = forwardRef<
export const HelpTooltipIconTrigger = forwardRef<
HTMLButtonElement,
HelpTooltipTriggerProps
HelpTooltipIconTriggerProps
>((props, ref) => {
const {
size = "medium",
@@ -76,7 +82,7 @@ export const HelpTooltipTrigger = forwardRef<
});
return (
<PopoverTrigger>
<HelpTooltipTrigger asChild>
<button
{...buttonProps}
aria-label="More info"
@@ -102,7 +108,7 @@ export const HelpTooltipTrigger = forwardRef<
>
{children}
</button>
</PopoverTrigger>
</HelpTooltipTrigger>
);
});
@@ -155,18 +161,12 @@ export const HelpTooltipAction: FC<HelpTooltipActionProps> = ({
onClick,
ariaLabel,
}) => {
const popover = usePopover();
return (
<button
type="button"
aria-label={ariaLabel ?? ""}
css={styles.action}
onClick={(event) => {
event.stopPropagation();
onClick();
popover.setOpen(false);
}}
onClick={onClick}
>
<Icon css={styles.actionIcon} />
{children}
@@ -1,5 +1,5 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import { expect, userEvent, waitFor, within } from "storybook/test";
import { expect, screen, userEvent, waitFor } from "storybook/test";
import { InfoTooltip } from "./InfoTooltip";
const meta = {
@@ -16,13 +16,13 @@ export default meta;
type Story = StoryObj<typeof InfoTooltip>;
export const Example: Story = {
play: async ({ canvasElement, step }) => {
const screen = within(canvasElement);
play: async ({ step }) => {
await step("activate hover trigger", async () => {
await userEvent.hover(screen.getByRole("button"));
await waitFor(() =>
expect(screen.getByText(meta.args.message)).toBeInTheDocument(),
expect(screen.getByRole("tooltip")).toHaveTextContent(
meta.args.message,
),
);
});
},
@@ -33,13 +33,13 @@ export const Notice = {
type: "notice",
message: "Unfortunately, there's a radio connected to my brain",
},
play: async ({ canvasElement, step }) => {
const screen = within(canvasElement);
play: async ({ step }) => {
await step("activate hover trigger", async () => {
await userEvent.hover(screen.getByRole("button"));
await waitFor(() =>
expect(screen.getByText(Notice.args.message)).toBeInTheDocument(),
expect(screen.getByRole("tooltip")).toHaveTextContent(
Notice.args.message,
),
);
});
},
@@ -50,13 +50,13 @@ export const Warning = {
type: "warning",
message: "Unfortunately, there's a radio connected to my brain",
},
play: async ({ canvasElement, step }) => {
const screen = within(canvasElement);
play: async ({ step }) => {
await step("activate hover trigger", async () => {
await userEvent.hover(screen.getByRole("button"));
await waitFor(() =>
expect(screen.getByText(Warning.args.message)).toBeInTheDocument(),
expect(screen.getByRole("tooltip")).toHaveTextContent(
Warning.args.message,
),
);
});
},
@@ -3,9 +3,9 @@ import {
HelpTooltip,
HelpTooltipContent,
HelpTooltipIcon,
HelpTooltipIconTrigger,
HelpTooltipText,
HelpTooltipTitle,
HelpTooltipTrigger,
} from "components/HelpTooltip/HelpTooltip";
import type { FC, ReactNode } from "react";
import type { ThemeRole } from "theme/roles";
@@ -26,9 +26,9 @@ export const InfoTooltip: FC<InfoTooltipProps> = ({
return (
<HelpTooltip>
<HelpTooltipTrigger size="small" css={styles.button}>
<HelpTooltipIconTrigger size="small" css={styles.button}>
<HelpTooltipIcon css={{ color: iconColor }} />
</HelpTooltipTrigger>
</HelpTooltipIconTrigger>
<HelpTooltipContent>
<HelpTooltipTitle>{title}</HelpTooltipTitle>
<HelpTooltipText>{message}</HelpTooltipText>
@@ -39,10 +39,10 @@ export const InfoTooltip: FC<InfoTooltipProps> = ({
const styles = {
button: css`
opacity: 1;
opacity: 1;
&:hover {
opacity: 1;
}
`,
&:hover {
opacity: 1;
}
`,
} satisfies Record<string, Interpolation<Theme>>;
+9 -3
View File
@@ -8,15 +8,21 @@ import { cn } from "utils/cn";
export const TooltipProvider = TooltipPrimitive.Provider;
export type TooltipProps = TooltipPrimitive.TooltipProps;
export const Tooltip = TooltipPrimitive.Root;
export const TooltipTrigger = TooltipPrimitive.Trigger;
export type TooltipContentProps = React.ComponentPropsWithoutRef<
typeof TooltipPrimitive.Content
> & {
disablePortal?: boolean;
};
export const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> & {
disablePortal?: boolean;
}
TooltipContentProps
>(({ className, sideOffset = 4, disablePortal, ...props }, ref) => {
const content = (
<TooltipPrimitive.Content
@@ -60,7 +60,7 @@ type ControlledPopoverProps = BasePopoverProps & {
onOpenChange: (open: boolean) => void;
};
export type PopoverProps = UncontrolledPopoverProps | ControlledPopoverProps;
type PopoverProps = UncontrolledPopoverProps | ControlledPopoverProps;
/** @deprecated prefer `components.Popover` */
export const Popover: FC<PopoverProps> = (props) => {
@@ -155,7 +155,7 @@ export const PopoverTrigger: FC<PopoverTriggerProps> = (props) => {
type Horizontal = "left" | "right";
export type PopoverContentProps = Omit<
type PopoverContentProps = Omit<
MuiPopoverProps,
"open" | "onClose" | "anchorEl"
> & {
+22 -24
View File
@@ -1,11 +1,11 @@
import { type Theme, useTheme } from "@emotion/react";
import type { DERPRegion, WorkspaceAgent } from "api/typesGenerated";
import { PopoverTrigger } from "components/deprecated/Popover/Popover";
import {
HelpTooltip,
HelpTooltipContent,
HelpTooltipText,
HelpTooltipTitle,
HelpTooltipTrigger,
} from "components/HelpTooltip/HelpTooltip";
import { Stack } from "components/Stack/Stack";
import type { FC } from "react";
@@ -44,7 +44,7 @@ export const AgentLatency: FC<AgentLatencyProps> = ({ agent }) => {
return (
<HelpTooltip>
<PopoverTrigger>
<HelpTooltipTrigger asChild>
<span
role="presentation"
aria-label="latency"
@@ -52,35 +52,33 @@ export const AgentLatency: FC<AgentLatencyProps> = ({ agent }) => {
>
{Math.round(latency.latency_ms)}ms
</span>
</PopoverTrigger>
</HelpTooltipTrigger>
<HelpTooltipContent>
<HelpTooltipTitle>Latency</HelpTooltipTitle>
<HelpTooltipText>
This is the latency overhead on non peer to peer connections. The
first row is the preferred relay.
</HelpTooltipText>
<HelpTooltipText>
<Stack direction="column" spacing={1} css={{ marginTop: 16 }}>
{Object.entries(agent.latency)
.sort(([, a], [, b]) => a.latency_ms - b.latency_ms)
.map(([regionName, region]) => (
<Stack
direction="row"
key={regionName}
spacing={0.5}
justifyContent="space-between"
css={
region.preferred && {
color: theme.palette.text.primary,
}
<Stack direction="column" spacing={1} css={{ marginTop: 16 }}>
{Object.entries(agent.latency)
.sort(([, a], [, b]) => a.latency_ms - b.latency_ms)
.map(([regionName, region]) => (
<Stack
direction="row"
key={regionName}
spacing={0.5}
justifyContent="space-between"
css={
region.preferred && {
color: theme.palette.text.primary,
}
>
<strong>{regionName}</strong>
{Math.round(region.latency_ms)}ms
</Stack>
))}
</Stack>
</HelpTooltipText>
}
>
<strong>{regionName}</strong>
{Math.round(region.latency_ms)}ms
</Stack>
))}
</Stack>
</HelpTooltipContent>
</HelpTooltip>
);
@@ -1,5 +1,4 @@
import type { WorkspaceAgent } from "api/typesGenerated";
import { PopoverTrigger } from "components/deprecated/Popover/Popover";
import {
HelpTooltip,
HelpTooltipAction,
@@ -7,10 +6,11 @@ import {
HelpTooltipLinksGroup,
HelpTooltipText,
HelpTooltipTitle,
HelpTooltipTrigger,
} from "components/HelpTooltip/HelpTooltip";
import { Stack } from "components/Stack/Stack";
import { RotateCcwIcon } from "lucide-react";
import type { FC } from "react";
import { type FC, useState } from "react";
import { agentVersionStatus } from "../../utils/workspace";
type AgentOutdatedTooltipProps = {
@@ -26,6 +26,8 @@ export const AgentOutdatedTooltip: FC<AgentOutdatedTooltipProps> = ({
status,
onUpdate,
}) => {
const [isOpen, setIsOpen] = useState(false);
const title =
status === agentVersionStatus.Outdated
? "Agent Outdated"
@@ -37,12 +39,12 @@ export const AgentOutdatedTooltip: FC<AgentOutdatedTooltipProps> = ({
const text = `${opener} This can happen after you update Coder with running workspaces. To fix this, you can stop and start the workspace.`;
return (
<HelpTooltip>
<PopoverTrigger>
<HelpTooltip open={isOpen} onOpenChange={setIsOpen}>
<HelpTooltipTrigger asChild>
<span role="status" className="cursor-pointer">
{status === agentVersionStatus.Outdated ? "Outdated" : "Deprecated"}
</span>
</PopoverTrigger>
</HelpTooltipTrigger>
<HelpTooltipContent>
<Stack spacing={1}>
<div>
@@ -67,7 +69,10 @@ export const AgentOutdatedTooltip: FC<AgentOutdatedTooltipProps> = ({
<HelpTooltipLinksGroup>
<HelpTooltipAction
icon={RotateCcwIcon}
onClick={onUpdate}
onClick={() => {
onUpdate();
setIsOpen(false);
}}
ariaLabel="Update workspace"
>
Update workspace
+13 -13
View File
@@ -6,12 +6,12 @@ import type {
WorkspaceAgentDevcontainer,
} from "api/typesGenerated";
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne";
import { PopoverTrigger } from "components/deprecated/Popover/Popover";
import {
HelpTooltip,
HelpTooltipContent,
HelpTooltipText,
HelpTooltipTitle,
HelpTooltipTrigger,
} from "components/HelpTooltip/HelpTooltip";
import { TriangleAlertIcon } from "lucide-react";
import type { FC } from "react";
@@ -62,9 +62,9 @@ interface DevcontainerStatusProps {
const StartTimeoutLifecycle: FC<AgentStatusProps> = ({ agent }) => {
return (
<HelpTooltip>
<PopoverTrigger role="status" aria-label="Agent timeout">
<HelpTooltipTrigger asChild role="status" aria-label="Agent timeout">
<TriangleAlertIcon css={styles.timeoutWarning} />
</PopoverTrigger>
</HelpTooltipTrigger>
<HelpTooltipContent>
<HelpTooltipTitle>Agent is taking too long to start</HelpTooltipTitle>
@@ -87,9 +87,9 @@ const StartTimeoutLifecycle: FC<AgentStatusProps> = ({ agent }) => {
const StartErrorLifecycle: FC<AgentStatusProps> = ({ agent }) => {
return (
<HelpTooltip>
<PopoverTrigger role="status" aria-label="Start error">
<HelpTooltipTrigger asChild role="status" aria-label="Start error">
<TriangleAlertIcon css={styles.errorWarning} />
</PopoverTrigger>
</HelpTooltipTrigger>
<HelpTooltipContent>
<HelpTooltipTitle>Error starting the agent</HelpTooltipTitle>
<HelpTooltipText>
@@ -123,9 +123,9 @@ const ShuttingDownLifecycle: FC = () => {
const ShutdownTimeoutLifecycle: FC<AgentStatusProps> = ({ agent }) => {
return (
<HelpTooltip>
<PopoverTrigger role="status" aria-label="Stop timeout">
<HelpTooltipTrigger asChild role="status" aria-label="Stop timeout">
<TriangleAlertIcon css={styles.timeoutWarning} />
</PopoverTrigger>
</HelpTooltipTrigger>
<HelpTooltipContent>
<HelpTooltipTitle>Agent is taking too long to stop</HelpTooltipTitle>
<HelpTooltipText>
@@ -147,9 +147,9 @@ const ShutdownTimeoutLifecycle: FC<AgentStatusProps> = ({ agent }) => {
const ShutdownErrorLifecycle: FC<AgentStatusProps> = ({ agent }) => {
return (
<HelpTooltip>
<PopoverTrigger role="status" aria-label="Stop error">
<HelpTooltipTrigger asChild role="status" aria-label="Stop error">
<TriangleAlertIcon css={styles.errorWarning} />
</PopoverTrigger>
</HelpTooltipTrigger>
<HelpTooltipContent>
<HelpTooltipTitle>Error stopping the agent</HelpTooltipTitle>
<HelpTooltipText>
@@ -243,9 +243,9 @@ const ConnectingStatus: FC = () => {
const TimeoutStatus: FC<AgentStatusProps> = ({ agent }) => {
return (
<HelpTooltip>
<PopoverTrigger role="status" aria-label="Timeout">
<HelpTooltipTrigger asChild role="status" aria-label="Timeout">
<TriangleAlertIcon css={styles.timeoutWarning} />
</PopoverTrigger>
</HelpTooltipTrigger>
<HelpTooltipContent>
<HelpTooltipTitle>Agent is taking too long to connect</HelpTooltipTitle>
<HelpTooltipText>
@@ -308,9 +308,9 @@ const SubAgentStatus: FC<SubAgentStatusProps> = ({ agent }) => {
const DevcontainerStartError: FC<AgentStatusProps> = ({ agent }) => {
return (
<HelpTooltip>
<PopoverTrigger role="status" aria-label="Start error">
<HelpTooltipTrigger asChild role="status" aria-label="Start error">
<TriangleAlertIcon css={styles.errorWarning} />
</PopoverTrigger>
</HelpTooltipTrigger>
<HelpTooltipContent>
<HelpTooltipTitle>
Error starting the devcontainer agent
@@ -9,9 +9,9 @@ import {
HelpTooltipLinksGroup,
HelpTooltipText,
HelpTooltipTitle,
HelpTooltipTrigger,
} from "components/HelpTooltip/HelpTooltip";
import { Stack } from "components/Stack/Stack";
import { TooltipTrigger } from "components/Tooltip/Tooltip";
import { RotateCcwIcon } from "lucide-react";
import type { FC } from "react";
@@ -39,11 +39,11 @@ export const SubAgentOutdatedTooltip: FC<SubAgentOutdatedTooltipProps> = ({
return (
<HelpTooltip>
<HelpTooltipTrigger>
<TooltipTrigger className="px-0 py-1 bg-transparent text-inherit border-none opacity-50 hover:opacity-100">
<span role="status" className="cursor-pointer">
Outdated
</span>
</HelpTooltipTrigger>
</TooltipTrigger>
<HelpTooltipContent>
<Stack spacing={1}>
<div>
@@ -5,7 +5,7 @@ import {
} from "testHelpers/entities";
import { withDashboardProvider } from "testHelpers/storybook";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { expect, userEvent, waitFor, within } from "storybook/test";
import { expect, screen, userEvent, waitFor, within } from "storybook/test";
import { WorkspaceOutdatedTooltip } from "./WorkspaceOutdatedTooltip";
const meta: Meta<typeof WorkspaceOutdatedTooltip> = {
@@ -39,7 +39,9 @@ const Example: Story = {
await step("activate hover trigger", async () => {
await userEvent.hover(body.getByRole("button"));
await waitFor(() =>
expect(body.getByText(MockTemplateVersion.message)).toBeInTheDocument(),
expect(screen.getByRole("tooltip")).toHaveTextContent(
MockTemplateVersion.message,
),
);
});
},
@@ -4,49 +4,56 @@ import Skeleton from "@mui/material/Skeleton";
import { getErrorDetail, getErrorMessage } from "api/errors";
import { templateVersion } from "api/queries/templates";
import type { Workspace } from "api/typesGenerated";
import { usePopover } from "components/deprecated/Popover/Popover";
import { displayError } from "components/GlobalSnackbar/utils";
import {
HelpTooltip,
HelpTooltipAction,
HelpTooltipContent,
HelpTooltipIconTrigger,
HelpTooltipLinksGroup,
HelpTooltipText,
HelpTooltipTitle,
HelpTooltipTrigger,
} from "components/HelpTooltip/HelpTooltip";
import { InfoIcon, RotateCcwIcon } from "lucide-react";
import { linkToTemplate, useLinks } from "modules/navigation";
import type { FC } from "react";
import { type FC, useState } from "react";
import { useQuery } from "react-query";
import {
useWorkspaceUpdate,
WorkspaceUpdateDialogs,
} from "../WorkspaceUpdateDialogs";
interface TooltipProps {
interface WorkspaceOutdatedTooltipProps {
workspace: Workspace;
}
export const WorkspaceOutdatedTooltip: FC<TooltipProps> = (props) => {
export const WorkspaceOutdatedTooltip: FC<WorkspaceOutdatedTooltipProps> = (
props,
) => {
const [isOpen, setIsOpen] = useState(false);
return (
<HelpTooltip>
<HelpTooltipTrigger size="small" hoverEffect={false}>
<HelpTooltip open={isOpen} onOpenChange={setIsOpen}>
<HelpTooltipIconTrigger size="small" hoverEffect={false}>
<InfoIcon css={styles.icon} />
<span className="sr-only">Outdated info</span>
</HelpTooltipTrigger>
<WorkspaceOutdatedTooltipContent {...props} />
</HelpTooltipIconTrigger>
<WorkspaceOutdatedTooltipContent isOpen={isOpen} {...props} />
</HelpTooltip>
);
};
const WorkspaceOutdatedTooltipContent: FC<TooltipProps> = ({ workspace }) => {
type TooltipContentProps = WorkspaceOutdatedTooltipProps & { isOpen: boolean };
const WorkspaceOutdatedTooltipContent: FC<TooltipContentProps> = ({
workspace,
isOpen,
}) => {
const getLink = useLinks();
const theme = useTheme();
const popover = usePopover();
const { data: activeVersion } = useQuery({
...templateVersion(workspace.template_active_version_id),
enabled: popover.open,
enabled: isOpen,
});
const updateWorkspace = useWorkspaceUpdate({
workspace,
@@ -1,11 +1,11 @@
import {
HelpTooltip,
HelpTooltipContent,
HelpTooltipIconTrigger,
HelpTooltipLink,
HelpTooltipLinksGroup,
HelpTooltipText,
HelpTooltipTitle,
HelpTooltipTrigger,
} from "components/HelpTooltip/HelpTooltip";
import type { FC } from "react";
import { docs } from "utils/docs";
@@ -19,7 +19,7 @@ const Language = {
export const AuditHelpTooltip: FC = () => {
return (
<HelpTooltip>
<HelpTooltipTrigger />
<HelpTooltipIconTrigger />
<HelpTooltipContent>
<HelpTooltipTitle>{Language.title}</HelpTooltipTitle>
@@ -1,11 +1,11 @@
import {
HelpTooltip,
HelpTooltipContent,
HelpTooltipIconTrigger,
HelpTooltipLink,
HelpTooltipLinksGroup,
HelpTooltipText,
HelpTooltipTitle,
HelpTooltipTrigger,
} from "components/HelpTooltip/HelpTooltip";
import type { FC } from "react";
import { docs } from "utils/docs";
@@ -19,7 +19,7 @@ const Language = {
export const ConnectionLogHelpTooltip: FC = () => {
return (
<HelpTooltip>
<HelpTooltipTrigger />
<HelpTooltipIconTrigger />
<HelpTooltipContent>
<HelpTooltipTitle>{Language.title}</HelpTooltipTitle>
@@ -18,8 +18,8 @@ import { EmptyState } from "components/EmptyState/EmptyState";
import {
HelpTooltip,
HelpTooltipContent,
HelpTooltipIconTrigger,
HelpTooltipText,
HelpTooltipTrigger,
} from "components/HelpTooltip/HelpTooltip";
import { Input } from "components/Input/Input";
import { Label } from "components/Label/Label";
@@ -459,7 +459,7 @@ const OrganizationRow: FC<OrganizationRowProps> = ({
const AssignDefaultOrgHelpTooltip: FC = () => {
return (
<HelpTooltip>
<HelpTooltipTrigger />
<HelpTooltipIconTrigger />
<HelpTooltipContent>
<HelpTooltipText>
Disabling will remove all users from the default organization if a
@@ -8,9 +8,9 @@ import { Combobox } from "components/Combobox/Combobox";
import {
HelpTooltip,
HelpTooltipContent,
HelpTooltipIconTrigger,
HelpTooltipText,
HelpTooltipTitle,
HelpTooltipTrigger,
} from "components/HelpTooltip/HelpTooltip";
import { Input } from "components/Input/Input";
import { Label } from "components/Label/Label";
@@ -414,7 +414,7 @@ const GroupRow: FC<GroupRowProps> = ({
const AutoCreateMissingGroupsHelpTooltip: FC = () => {
return (
<HelpTooltip>
<HelpTooltipTrigger />
<HelpTooltipIconTrigger />
<HelpTooltipContent>
<HelpTooltipText>
Enabling auto create missing groups will automatically create groups
@@ -431,7 +431,7 @@ const LegacyGroupSyncHeader: FC = () => {
<div className="flex items-end gap-2">
<span>Legacy group sync settings</span>
<HelpTooltip>
<HelpTooltipTrigger />
<HelpTooltipIconTrigger />
<HelpTooltipContent>
<HelpTooltipTitle>Legacy group sync settings</HelpTooltipTitle>
<HelpTooltipText>
@@ -43,6 +43,17 @@ export const Loading: Story = {
},
};
export const CannotSetRoles: Story = {
args: {
userLoginType: "oidc",
oidcRoleSync: true,
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await userEvent.hover(canvas.getByLabelText("More info"));
},
};
export const AdvancedOpen: Story = {
args: {
selectedRoleNames: new Set([MockWorkspaceCreationBanRole.name]),
@@ -11,9 +11,9 @@ import {
import {
HelpTooltip,
HelpTooltipContent,
HelpTooltipIconTrigger,
HelpTooltipText,
HelpTooltipTitle,
HelpTooltipTrigger,
} from "components/HelpTooltip/HelpTooltip";
import { EditSquare } from "components/Icons/EditSquare";
import { UserIcon } from "lucide-react";
@@ -83,7 +83,7 @@ export const EditRolesButton: FC<EditRolesButtonProps> = (props) => {
if (!canSetRoles) {
return (
<HelpTooltip>
<HelpTooltipTrigger size="small" />
<HelpTooltipIconTrigger size="small" />
<HelpTooltipContent>
<HelpTooltipTitle>Externally controlled</HelpTooltipTitle>
<HelpTooltipText>
@@ -1,11 +1,11 @@
import {
HelpTooltip,
HelpTooltipContent,
HelpTooltipIconTrigger,
HelpTooltipLink,
HelpTooltipLinksGroup,
HelpTooltipText,
HelpTooltipTitle,
HelpTooltipTrigger,
} from "components/HelpTooltip/HelpTooltip";
import type { FC } from "react";
import { docs } from "utils/docs";
@@ -45,7 +45,7 @@ export const TableColumnHelpTooltip: FC<Props> = ({ variant }) => {
return (
<HelpTooltip>
<HelpTooltipTrigger size="small" />
<HelpTooltipIconTrigger size="small" />
<HelpTooltipContent>
<HelpTooltipTitle>{variantLang.title}</HelpTooltipTitle>
<HelpTooltipText>{variantLang.text}</HelpTooltipText>
@@ -29,9 +29,9 @@ import { Avatar } from "components/Avatar/Avatar";
import {
HelpTooltip,
HelpTooltipContent,
HelpTooltipIconTrigger,
HelpTooltipText,
HelpTooltipTitle,
HelpTooltipTrigger,
} from "components/HelpTooltip/HelpTooltip";
import { Loader } from "components/Loader/Loader";
import { Stack } from "components/Stack/Stack";
@@ -284,7 +284,7 @@ const UsersLatencyPanel: FC<UsersLatencyPanelProps> = ({
<PanelTitle css={{ display: "flex", alignItems: "center", gap: 8 }}>
Latency by user
<HelpTooltip>
<HelpTooltipTrigger size="small" />
<HelpTooltipIconTrigger size="small" />
<HelpTooltipContent>
<HelpTooltipTitle>How is latency calculated?</HelpTooltipTitle>
<HelpTooltipText>
@@ -352,7 +352,7 @@ const UsersActivityPanel: FC<UsersActivityPanelProps> = ({
<PanelTitle css={{ display: "flex", alignItems: "center", gap: 8 }}>
Activity by user
<HelpTooltip>
<HelpTooltipTrigger size="small" />
<HelpTooltipIconTrigger size="small" />
<HelpTooltipContent>
<HelpTooltipTitle>How is activity calculated?</HelpTooltipTitle>
<HelpTooltipText>
@@ -13,11 +13,11 @@ import * as Yup from "yup";
import {
HelpTooltip,
HelpTooltipContent,
HelpTooltipIconTrigger,
HelpTooltipLink,
HelpTooltipLinksGroup,
HelpTooltipText,
HelpTooltipTitle,
HelpTooltipTrigger,
} from "../../components/HelpTooltip/HelpTooltip";
import { docs } from "../../utils/docs";
@@ -121,9 +121,13 @@ export const PublishTemplateVersionDialog: FC<
/>
<HelpTooltip>
<HelpTooltipTrigger />
<HelpTooltipIconTrigger />
<HelpTooltipContent>
{/**
* 2025-09-03 - Without disablePortal, the tooltip will render under the dialog;
* this prop may not need to be set when we switch away from MuiDialog
*/}
<HelpTooltipContent disablePortal>
<HelpTooltipTitle>
{Language.activeVersionHelpTitle}
</HelpTooltipTitle>
@@ -157,6 +157,12 @@ export const WithError = {
},
};
export const PublishDialog = {
args: {
isAskingPublishParameters: true,
},
};
export const Published = {
args: {
publishedVersion: MockTemplateVersion,
@@ -12,11 +12,11 @@ import { Button } from "components/Button/Button";
import {
HelpTooltip,
HelpTooltipContent,
HelpTooltipIconTrigger,
HelpTooltipLink,
HelpTooltipLinksGroup,
HelpTooltipText,
HelpTooltipTitle,
HelpTooltipTrigger,
} from "components/HelpTooltip/HelpTooltip";
import { Margins } from "components/Margins/Margins";
import {
@@ -72,7 +72,7 @@ const Language = {
const TemplateHelpTooltip: FC = () => {
return (
<HelpTooltip>
<HelpTooltipTrigger />
<HelpTooltipIconTrigger />
<HelpTooltipContent>
<HelpTooltipTitle>{Language.templateTooltipTitle}</HelpTooltipTitle>
<HelpTooltipText>{Language.templateTooltipText}</HelpTooltipText>
@@ -320,9 +320,9 @@ export const TemplateInfoPopover: Story = {
await step("activate hover trigger", async () => {
await userEvent.hover(canvas.getByText(baseWorkspace.name));
await waitFor(() =>
expect(
canvas.getByRole("presentation", { hidden: true }),
).toHaveTextContent(MockTemplate.display_name),
expect(screen.getByRole("tooltip")).toHaveTextContent(
MockTemplate.display_name,
),
);
});
},
@@ -346,9 +346,9 @@ export const TemplateInfoPopoverWithoutDisplayName: Story = {
await step("activate hover trigger", async () => {
await userEvent.hover(canvas.getByText(baseWorkspace.name));
await waitFor(() =>
expect(
canvas.getByRole("presentation", { hidden: true }),
).toHaveTextContent(MockTemplate.name),
expect(screen.getByRole("tooltip")).toHaveTextContent(
MockTemplate.name,
),
);
});
},
@@ -6,7 +6,6 @@ import type * as TypesGen from "api/typesGenerated";
import { Avatar } from "components/Avatar/Avatar";
import { AvatarData } from "components/Avatar/AvatarData";
import { CopyButton } from "components/CopyButton/CopyButton";
import { Popover, PopoverTrigger } from "components/deprecated/Popover/Popover";
import {
Topbar,
TopbarAvatar,
@@ -15,7 +14,11 @@ import {
TopbarIcon,
TopbarIconButton,
} from "components/FullPageLayout/Topbar";
import { HelpTooltipContent } from "components/HelpTooltip/HelpTooltip";
import {
HelpTooltip,
HelpTooltipContent,
HelpTooltipTrigger,
} from "components/HelpTooltip/HelpTooltip";
import { ChevronLeftIcon, CircleDollarSign, TrashIcon } from "lucide-react";
import { useDashboard } from "modules/dashboard/useDashboard";
import { linkToTemplate, useLinks } from "modules/navigation";
@@ -253,21 +256,18 @@ const OwnerBreadcrumb: FC<OwnerBreadcrumbProps> = ({
ownerAvatarUrl,
}) => {
return (
<Popover mode="hover">
<PopoverTrigger>
<HelpTooltip>
<HelpTooltipTrigger asChild>
<span css={styles.breadcrumbSegment}>
<Avatar size="sm" fallback={ownerName} src={ownerAvatarUrl} />
<span css={styles.breadcrumbText}>{ownerName}</span>
</span>
</PopoverTrigger>
</HelpTooltipTrigger>
<HelpTooltipContent
anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
transformOrigin={{ vertical: "top", horizontal: "center" }}
>
<HelpTooltipContent align="center">
<AvatarData title={ownerName} subtitle="Owner" src={ownerAvatarUrl} />
</HelpTooltipContent>
</Popover>
</HelpTooltip>
);
};
@@ -283,8 +283,8 @@ const OrganizationBreadcrumb: FC<OrganizationBreadcrumbProps> = ({
orgIconUrl,
}) => {
return (
<Popover mode="hover">
<PopoverTrigger>
<HelpTooltip>
<HelpTooltipTrigger asChild>
<span css={styles.breadcrumbSegment}>
<Avatar
size="sm"
@@ -294,12 +294,9 @@ const OrganizationBreadcrumb: FC<OrganizationBreadcrumbProps> = ({
/>
<span css={styles.breadcrumbText}>{orgName}</span>
</span>
</PopoverTrigger>
</HelpTooltipTrigger>
<HelpTooltipContent
anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
transformOrigin={{ vertical: "top", horizontal: "center" }}
>
<HelpTooltipContent align="center">
<AvatarData
title={
orgPageUrl ? (
@@ -323,7 +320,7 @@ const OrganizationBreadcrumb: FC<OrganizationBreadcrumbProps> = ({
imgFallbackText={orgName}
/>
</HelpTooltipContent>
</Popover>
</HelpTooltip>
);
};
@@ -346,8 +343,8 @@ const WorkspaceBreadcrumb: FC<WorkspaceBreadcrumbProps> = ({
}) => {
return (
<div className="flex items-center">
<Popover mode="hover">
<PopoverTrigger>
<HelpTooltip>
<HelpTooltipTrigger asChild>
<span css={styles.breadcrumbSegment}>
<TopbarAvatar
src={templateIconUrl}
@@ -358,12 +355,9 @@ const WorkspaceBreadcrumb: FC<WorkspaceBreadcrumbProps> = ({
{workspaceName}
</span>
</span>
</PopoverTrigger>
</HelpTooltipTrigger>
<HelpTooltipContent
anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
transformOrigin={{ vertical: "top", horizontal: "center" }}
>
<HelpTooltipContent align="center">
<AvatarData
title={
<Link
@@ -393,7 +387,7 @@ const WorkspaceBreadcrumb: FC<WorkspaceBreadcrumbProps> = ({
imgFallbackText={templateDisplayName}
/>
</HelpTooltipContent>
</Popover>
</HelpTooltip>
<CopyButton text={workspaceName} label="Copy workspace name" />
</div>
);
@@ -1,11 +1,11 @@
import {
HelpTooltip,
HelpTooltipContent,
HelpTooltipIconTrigger,
HelpTooltipLink,
HelpTooltipLinksGroup,
HelpTooltipText,
HelpTooltipTitle,
HelpTooltipTrigger,
} from "components/HelpTooltip/HelpTooltip";
import type { FC } from "react";
import { docs } from "utils/docs";
@@ -22,7 +22,7 @@ const Language = {
export const WorkspaceHelpTooltip: FC = () => {
return (
<HelpTooltip>
<HelpTooltipTrigger />
<HelpTooltipIconTrigger />
<HelpTooltipContent>
<HelpTooltipTitle>{Language.workspaceTooltipTitle}</HelpTooltipTitle>
<HelpTooltipText>{Language.workspaceTooltipText}</HelpTooltipText>