From 13fbbcd279462d186ecc53ef765b27660b49a261 Mon Sep 17 00:00:00 2001 From: Andrew Aquino Date: Mon, 15 Dec 2025 08:12:27 -0800 Subject: [PATCH] refactor: replace remaining MUI tooltips (#20938) closes #19974 This PR replaces all remaining MUI tooltips with our shadcn tooltip component, and uncomments the linter restriction on importing the MUI tooltip --- biome.jsonc | 2 +- .../RichParameterInput/RichParameterInput.tsx | 59 +++++++---- .../modules/resources/AgentLogs/AgentLogs.tsx | 28 +++--- .../src/modules/resources/AppLink/AppLink.tsx | 2 +- .../WorkspaceDormantBadge.tsx | 56 ++++++----- .../AuditPage/AuditLogRow/AuditLogRow.tsx | 25 +++-- .../ConnectionLogRow/ConnectionLogRow.tsx | 25 +++-- .../OrganizationMembersPageView.stories.tsx | 8 +- .../UserTable/EditRolesButton.tsx | 33 ++++--- .../UserTable/UserRoleCell.tsx | 18 ++-- .../WorkspaceScheduleControls.tsx | 98 +++++++++++-------- 11 files changed, 210 insertions(+), 144 deletions(-) diff --git a/biome.jsonc b/biome.jsonc index d45b5cabb2..b6fa53af58 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -99,7 +99,7 @@ // "@mui/material/TextField": "Use shadcn/ui Input component instead.", // "@mui/material/ToggleButton": "Use shadcn/ui Toggle or custom component instead.", // "@mui/material/ToggleButtonGroup": "Use shadcn/ui Toggle or custom component instead.", - // "@mui/material/Tooltip": "Use shadcn/ui Tooltip component instead.", + "@mui/material/Tooltip": "Use components/Tooltip/Tooltip instead.", "@mui/material/Typography": "Use native HTML elements instead. Eg: ,

,

, etc.", // "@mui/material/useMediaQuery": "Use Tailwind responsive classes or custom hook instead.", // "@mui/system": "Use Tailwind CSS instead.", diff --git a/site/src/components/RichParameterInput/RichParameterInput.tsx b/site/src/components/RichParameterInput/RichParameterInput.tsx index 1852d50af9..b3d7589187 100644 --- a/site/src/components/RichParameterInput/RichParameterInput.tsx +++ b/site/src/components/RichParameterInput/RichParameterInput.tsx @@ -5,13 +5,17 @@ import type { InputBaseComponentProps } from "@mui/material/InputBase"; import Radio from "@mui/material/Radio"; import RadioGroup from "@mui/material/RadioGroup"; import TextField, { type TextFieldProps } from "@mui/material/TextField"; -import Tooltip from "@mui/material/Tooltip"; import type { TemplateVersionParameter } from "api/typesGenerated"; import { Button } from "components/Button/Button"; import { ExternalImage } from "components/ExternalImage/ExternalImage"; import { MemoizedMarkdown } from "components/Markdown/Markdown"; import { Pill } from "components/Pill/Pill"; import { Stack } from "components/Stack/Stack"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { CircleAlertIcon, SettingsIcon } from "lucide-react"; import { type FC, type ReactNode, useState } from "react"; import type { @@ -136,25 +140,41 @@ const ParameterLabel: FC = ({ parameter, isPreset }) => { {displayName} {!parameter.required && ( - - (optional) + + + (optional) + + + If no value is specified, the system will default to the value set + by the administrator. + )} {!parameter.mutable && ( - - } - > - Immutable - + + + } + > + Immutable + + + + This value cannot be modified after the workspace has been created. + )} {isPreset && ( - - }> - Preset - + + + }> + Preset + + + + This value was set by a preset + )} @@ -328,14 +348,15 @@ const RichParameterField: FC = ({ css={{ padding: small ? undefined : "4px 0" }} > {small ? ( - + +
{option.name}
+
+ {option.description} - } - > -
{option.name}
+
) : ( <> diff --git a/site/src/modules/resources/AgentLogs/AgentLogs.tsx b/site/src/modules/resources/AgentLogs/AgentLogs.tsx index e715769132..744d8c1b96 100644 --- a/site/src/modules/resources/AgentLogs/AgentLogs.tsx +++ b/site/src/modules/resources/AgentLogs/AgentLogs.tsx @@ -1,4 +1,3 @@ -import MuiTooltip from "@mui/material/Tooltip"; import type { WorkspaceAgentLogSource } from "api/typesGenerated"; import { Badge } from "components/Badge/Badge"; import type { Line } from "components/Logs/LogLine"; @@ -125,21 +124,18 @@ export const AgentLogs = forwardRef( maxLineNumber={logs.length} style={style} sourceIcon={ - - {logSource.display_name} - {assignedIcon && ( - -
- No icon specified! -
- )} - - } - > - {icon} -
+ + {icon} + + {logSource.display_name} + {assignedIcon && ( + +
+ No icon specified! +
+ )} +
+
} /> ); diff --git a/site/src/modules/resources/AppLink/AppLink.tsx b/site/src/modules/resources/AppLink/AppLink.tsx index 9294f94912..1c26704027 100644 --- a/site/src/modules/resources/AppLink/AppLink.tsx +++ b/site/src/modules/resources/AppLink/AppLink.tsx @@ -155,7 +155,7 @@ export const AppLink: FC = ({ return ( {button} - + {primaryTooltip ? ( primaryTooltip ) : app.tooltip ? ( diff --git a/site/src/modules/workspaces/WorkspaceDormantBadge/WorkspaceDormantBadge.tsx b/site/src/modules/workspaces/WorkspaceDormantBadge/WorkspaceDormantBadge.tsx index 1712d67e77..0bb4ba53ee 100644 --- a/site/src/modules/workspaces/WorkspaceDormantBadge/WorkspaceDormantBadge.tsx +++ b/site/src/modules/workspaces/WorkspaceDormantBadge/WorkspaceDormantBadge.tsx @@ -1,6 +1,10 @@ -import Tooltip from "@mui/material/Tooltip"; import type { Workspace } from "api/typesGenerated"; import { Badge } from "components/Badge/Badge"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import type { FC } from "react"; import { DATE_FORMAT, @@ -16,34 +20,32 @@ export const WorkspaceDormantBadge: FC = ({ workspace, }) => { return workspace.deleting_at ? ( - - This workspace has not been used for{" "} - {relativeTimeWithoutSuffix(workspace.last_used_at)} and has been - marked dormant. It is scheduled to be deleted on{" "} - {formatDateTime(workspace.deleting_at, DATE_FORMAT.FULL_DATETIME)}. - - } - > - - Deletion Pending - + + + + Deletion Pending + + + + This workspace has not been used for{" "} + {relativeTimeWithoutSuffix(workspace.last_used_at)} and has been marked + dormant. It is scheduled to be deleted on{" "} + {formatDateTime(workspace.deleting_at, DATE_FORMAT.FULL_DATETIME)}. + ) : ( - - This workspace has not been used for{" "} - {relativeTimeWithoutSuffix(workspace.last_used_at)} and has been - marked dormant. It is not scheduled for auto-deletion but will become - a candidate if auto-deletion is enabled on this template. - - } - > - - Dormant - + + + + Dormant + + + + This workspace has not been used for{" "} + {relativeTimeWithoutSuffix(workspace.last_used_at)} and has been marked + dormant. It is not scheduled for auto-deletion but will become a + candidate if auto-deletion is enabled on this template. + ); }; diff --git a/site/src/pages/AuditPage/AuditLogRow/AuditLogRow.tsx b/site/src/pages/AuditPage/AuditLogRow/AuditLogRow.tsx index a1422e95de..7611407e56 100644 --- a/site/src/pages/AuditPage/AuditLogRow/AuditLogRow.tsx +++ b/site/src/pages/AuditPage/AuditLogRow/AuditLogRow.tsx @@ -1,7 +1,6 @@ import type { CSSObject, Interpolation, Theme } from "@emotion/react"; import Collapse from "@mui/material/Collapse"; import Link from "@mui/material/Link"; -import Tooltip from "@mui/material/Tooltip"; import type { AuditLog, BuildReason } from "api/typesGenerated"; import { Avatar } from "components/Avatar/Avatar"; import { DropdownArrow } from "components/DropdownArrow/DropdownArrow"; @@ -9,6 +8,11 @@ import { Stack } from "components/Stack/Stack"; import { StatusPill } from "components/StatusPill/StatusPill"; import { TableCell } from "components/Table/Table"; import { TimelineEntry } from "components/Timeline/TimelineEntry"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { InfoIcon, NetworkIcon } from "lucide-react"; import { type FC, useState } from "react"; import { Link as RouterLink } from "react-router"; @@ -128,8 +132,15 @@ export const AuditLogRow: FC = ({ {/* With multi-org, there is not enough space so show everything in a tooltip. */} {showOrgDetails ? ( - + + ({ + color: theme.palette.info.light, + })} + /> + +
{auditLog.ip && (
@@ -181,13 +192,7 @@ export const AuditLogRow: FC = ({
)}
- } - > - ({ - color: theme.palette.info.light, - })} - /> +
) : ( diff --git a/site/src/pages/ConnectionLogPage/ConnectionLogRow/ConnectionLogRow.tsx b/site/src/pages/ConnectionLogPage/ConnectionLogRow/ConnectionLogRow.tsx index f9d14432d4..3ad86c1917 100644 --- a/site/src/pages/ConnectionLogPage/ConnectionLogRow/ConnectionLogRow.tsx +++ b/site/src/pages/ConnectionLogPage/ConnectionLogRow/ConnectionLogRow.tsx @@ -1,12 +1,16 @@ import type { CSSObject, Interpolation, Theme } from "@emotion/react"; import Link from "@mui/material/Link"; -import Tooltip from "@mui/material/Tooltip"; import type { ConnectionLog } from "api/typesGenerated"; import { Avatar } from "components/Avatar/Avatar"; import { Stack } from "components/Stack/Stack"; import { StatusPill } from "components/StatusPill/StatusPill"; import { TableCell } from "components/Table/Table"; import { TimelineEntry } from "components/Timeline/TimelineEntry"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { InfoIcon, NetworkIcon } from "lucide-react"; import type { FC } from "react"; import { Link as RouterLink } from "react-router"; @@ -87,8 +91,15 @@ export const ConnectionLogRow: FC = ({ label={isWeb ? "HTTP Status Code" : "SSH Exit Code"} /> )} - + + ({ + color: theme.palette.info.light, + })} + /> + +
{connectionLog.ip && (
@@ -133,13 +144,7 @@ export const ConnectionLogRow: FC = ({
)}
- } - > - ({ - color: theme.palette.info.light, - })} - /> +
diff --git a/site/src/pages/OrganizationSettingsPage/OrganizationMembersPageView.stories.tsx b/site/src/pages/OrganizationSettingsPage/OrganizationMembersPageView.stories.tsx index 9cf02a22f1..d999e3a211 100644 --- a/site/src/pages/OrganizationSettingsPage/OrganizationMembersPageView.stories.tsx +++ b/site/src/pages/OrganizationSettingsPage/OrganizationMembersPageView.stories.tsx @@ -1,6 +1,8 @@ import { MockOrganizationMember, MockOrganizationMember2, + MockOwnerRole, + MockUserAdminRole, MockUserOwner, } from "testHelpers/entities"; import type { Meta, StoryObj } from "@storybook/react-vite"; @@ -19,7 +21,11 @@ const meta: Meta = { canViewMembers: true, me: MockUserOwner, members: [ - { ...MockOrganizationMember, groups: [] }, + { + ...MockOrganizationMember, + global_roles: [MockOwnerRole, MockUserAdminRole], + groups: [], + }, { ...MockOrganizationMember2, groups: [] }, ], membersQuery: { diff --git a/site/src/pages/OrganizationSettingsPage/UserTable/EditRolesButton.tsx b/site/src/pages/OrganizationSettingsPage/UserTable/EditRolesButton.tsx index 5d0f232193..87be0b6c6a 100644 --- a/site/src/pages/OrganizationSettingsPage/UserTable/EditRolesButton.tsx +++ b/site/src/pages/OrganizationSettingsPage/UserTable/EditRolesButton.tsx @@ -1,5 +1,4 @@ import Checkbox from "@mui/material/Checkbox"; -import Tooltip from "@mui/material/Tooltip"; import type { SlimRole } from "api/typesGenerated"; import { Button } from "components/Button/Button"; import { CollapsibleSummary } from "components/CollapsibleSummary/CollapsibleSummary"; @@ -16,6 +15,11 @@ import { PopoverContent, PopoverTrigger, } from "components/Popover/Popover"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { UserIcon } from "lucide-react"; import { type FC, useEffect, useState } from "react"; @@ -130,18 +134,21 @@ const EnabledEditRolesButton: FC = ({ return ( - - - - - + + + + + + + Edit user roles + = ({ } > {mainDisplayRole.global ? ( - - {displayName}* - + + + {displayName}* + + + This user has this role for all organizations. + + ) : ( displayName )} @@ -130,9 +134,9 @@ const OverflowRolePill: FC = ({ roles }) => { css={role.global ? styles.globalRoleBadge : styles.roleBadge} > {role.global ? ( - - {role.display_name || role.name}* - + + {role.display_name || role.name}* + ) : ( role.display_name || role.name )} diff --git a/site/src/pages/WorkspacePage/WorkspaceScheduleControls.tsx b/site/src/pages/WorkspacePage/WorkspaceScheduleControls.tsx index 1968f48a2f..f815d116a1 100644 --- a/site/src/pages/WorkspacePage/WorkspaceScheduleControls.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceScheduleControls.tsx @@ -1,7 +1,6 @@ import type { Interpolation, Theme } from "@emotion/react"; import IconButton from "@mui/material/IconButton"; import Link, { type LinkProps } from "@mui/material/Link"; -import Tooltip from "@mui/material/Tooltip"; import { visuallyHidden } from "@mui/utils"; import { getErrorMessage } from "api/errors"; import { @@ -11,6 +10,11 @@ import { import type { Template, Workspace } from "api/typesGenerated"; import { TopbarData, TopbarIcon } from "components/FullPageLayout/Topbar"; import { displayError, displaySuccess } from "components/GlobalSnackbar/utils"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import dayjs, { type Dayjs } from "dayjs"; import { useTime } from "hooks/useTime"; import { ClockIcon, MinusIcon, PlusIcon } from "lucide-react"; @@ -45,19 +49,22 @@ const WorkspaceScheduleContainer: FC = ({ return ( - - {onClickIcon ? ( - - ) : ( - icon - )} + + + {onClickIcon ? ( + + ) : ( + icon + )} + + Schedule {children} @@ -200,31 +207,39 @@ const AutostopDisplay: FC = ({ const controls = canUpdateSchedule && canEditDeadline(workspace) && (
- - { - handleDeadlineChange(deadline.subtract(1, "h")); - }} - > - - Subtract 1 hour - + + + { + handleDeadlineChange(deadline.subtract(1, "h")); + }} + > + + Subtract 1 hour from deadline + + + + Subtract 1 hour from deadline + - - { - handleDeadlineChange(deadline.add(1, "h")); - }} - > - - Add 1 hour - + + + { + handleDeadlineChange(deadline.add(1, "h")); + }} + > + + Add 1 hour to deadline + + + Add 1 hour to deadline
); @@ -232,7 +247,12 @@ const AutostopDisplay: FC = ({ if (tooltip) { return ( - {display} + + {display} + + {tooltip} + + {controls} );