From 4863812d8c43c4c6fe08b6683c3ea3a9b6de9fb8 Mon Sep 17 00:00:00 2001 From: Andrew Aquino Date: Tue, 25 Nov 2025 13:40:26 -0800 Subject: [PATCH] refactor: replace MUI Tooltip component with Tooltip (simple usage) (#20849) for #19974 Redo of #20027, this time splitting it into multiple PRs + using our existing `Tooltip` component instead of creating a new component (see below). This PR covers the most basic usage of the MUI Tooltip, i.e., the tooltip content is a string literal. ~~Adds a global `TooltipProvider` to `AppProviders` and our Storybook decorators, so that we don't have to render a `TooltipProvider` for every tooltip instance. Removing redundant `TooltipProvider`s will be another separate PR~~ <- this was done by #20869 --- site/src/components/Badges/Badges.tsx | 24 ++++-- site/src/components/Latency/Latency.tsx | 43 +++++++--- .../components/SearchField/SearchField.tsx | 30 ++++--- site/src/components/Tooltip/Tooltip.tsx | 2 + .../modules/dashboard/Navbar/ProxyMenu.tsx | 1 + .../UserDropdown/UserDropdownContent.tsx | 40 +++++---- site/src/modules/provisioners/Provisioner.tsx | 29 ++++--- site/src/modules/resources/AgentMetadata.tsx | 19 +++-- .../modules/resources/AgentRow.stories.tsx | 7 ++ site/src/modules/resources/AgentStatus.tsx | 81 ++++++++++++------- .../modules/resources/ResourceCard.test.tsx | 12 +-- site/src/modules/resources/ResourceCard.tsx | 36 +++++---- site/src/modules/resources/SensitiveValue.tsx | 46 +++++------ .../WorkspaceBuildData/WorkspaceBuildData.tsx | 25 ++++-- .../LicensesSettingsPageView.tsx | 34 +++++--- .../NotificationsPage/NotificationEvents.tsx | 41 ++++++---- .../ExternalAuthPage/ExternalAuthPageView.tsx | 33 +++++--- site/src/pages/HealthPage/DERPRegionPage.tsx | 47 +++++++---- site/src/pages/HealthPage/HealthLayout.tsx | 41 ++++++---- site/src/pages/HealthPage/WebsocketPage.tsx | 17 ++-- .../pages/HealthPage/WorkspaceProxyPage.tsx | 30 ++++--- site/src/pages/IconsPage/IconsPage.tsx | 49 ++++++----- .../TemplateInsightsPage.tsx | 57 +++++++------ .../TemplateVersionEditor.tsx | 42 ++++++---- .../ExternalAuthPage/ExternalAuthPageView.tsx | 18 +++-- .../NotificationsPage/NotificationsPage.tsx | 15 +++- .../WorkspaceActions/Buttons.tsx | 56 ++++++++----- .../pages/WorkspacePage/WorkspaceTopbar.tsx | 17 ++-- site/src/testHelpers/entities.ts | 2 +- 29 files changed, 563 insertions(+), 331 deletions(-) diff --git a/site/src/components/Badges/Badges.tsx b/site/src/components/Badges/Badges.tsx index f0db2fb0e9..cef5288091 100644 --- a/site/src/components/Badges/Badges.tsx +++ b/site/src/components/Badges/Badges.tsx @@ -1,6 +1,10 @@ import type { Interpolation, Theme } from "@emotion/react"; -import Tooltip from "@mui/material/Tooltip"; import { Stack } from "components/Stack/Stack"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { type FC, forwardRef, @@ -69,16 +73,26 @@ export const NotHealthyBadge: FC = () => { export const NotRegisteredBadge: FC = () => { return ( - - Never seen + + + Never seen + + + Workspace Proxy has never come online and needs to be started. + ); }; export const NotReachableBadge: FC = () => { return ( - - Not reachable + + + Not reachable + + + Workspace Proxy not responding to http(s) requests. + ); }; diff --git a/site/src/components/Latency/Latency.tsx b/site/src/components/Latency/Latency.tsx index 84292616bc..9341d57507 100644 --- a/site/src/components/Latency/Latency.tsx +++ b/site/src/components/Latency/Latency.tsx @@ -1,7 +1,11 @@ import { useTheme } from "@emotion/react"; import CircularProgress from "@mui/material/CircularProgress"; -import Tooltip from "@mui/material/Tooltip"; import { Abbr } from "components/Abbr/Abbr"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { CircleHelpIcon } from "lucide-react"; import type { FC } from "react"; import { cn } from "utils/cn"; @@ -11,14 +15,12 @@ interface LatencyProps { latency?: number; isLoading?: boolean; className?: string; - iconClassName?: string; } export const Latency: FC = ({ latency, isLoading, className, - iconClassName, }) => { const theme = useTheme(); // Always use the no latency color for loading. @@ -26,22 +28,37 @@ export const Latency: FC = ({ if (isLoading) { return ( - - + + + {/** + * Spinning progress icon must be placed inside a fixed-size container, + * to ensure tooltip remains stationary when opened + */} +
+ +
+
+ Loading latency...
); } if (!latency) { return ( - - + + + + + Latency not available ); } diff --git a/site/src/components/SearchField/SearchField.tsx b/site/src/components/SearchField/SearchField.tsx index 4ee9fda2c2..8942cabb73 100644 --- a/site/src/components/SearchField/SearchField.tsx +++ b/site/src/components/SearchField/SearchField.tsx @@ -1,10 +1,15 @@ import IconButton from "@mui/material/IconButton"; import InputAdornment from "@mui/material/InputAdornment"; import TextField, { type TextFieldProps } from "@mui/material/TextField"; -import Tooltip from "@mui/material/Tooltip"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { useEffectEvent } from "hooks/hookPolyfills"; import { SearchIcon, XIcon } from "lucide-react"; import { type FC, useLayoutEffect, useRef } from "react"; + export type SearchFieldProps = Omit & { onChange: (query: string) => void; autoFocus?: boolean; @@ -47,16 +52,19 @@ export const SearchField: FC = ({ ), endAdornment: value !== "" && ( - - { - onChange(""); - }} - > - - Clear search - + + + { + onChange(""); + }} + > + + Clear search + + + Clear search ), diff --git a/site/src/components/Tooltip/Tooltip.tsx b/site/src/components/Tooltip/Tooltip.tsx index 262dc415c9..1d34f197f8 100644 --- a/site/src/components/Tooltip/Tooltip.tsx +++ b/site/src/components/Tooltip/Tooltip.tsx @@ -14,6 +14,8 @@ export const Tooltip = TooltipPrimitive.Root; export const TooltipTrigger = TooltipPrimitive.Trigger; +export const TooltipArrow = TooltipPrimitive.Arrow; + export type TooltipContentProps = React.ComponentPropsWithoutRef< typeof TooltipPrimitive.Content > & { diff --git a/site/src/modules/dashboard/Navbar/ProxyMenu.tsx b/site/src/modules/dashboard/Navbar/ProxyMenu.tsx index 2ed60982ab..cb20f2bae1 100644 --- a/site/src/modules/dashboard/Navbar/ProxyMenu.tsx +++ b/site/src/modules/dashboard/Navbar/ProxyMenu.tsx @@ -112,6 +112,7 @@ export const ProxyMenu: FC = ({ proxyContextValue }) => { // to turn this off because otherwise, screen readers will skip over all // the descriptive text and will only have access to the latency options autoFocus={false} + className="z-0" > {proxyContextValue.proxies && proxyContextValue.proxies.length > 1 && [ diff --git a/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownContent.tsx b/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownContent.tsx index b56c1c67de..4fea4acf19 100644 --- a/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownContent.tsx +++ b/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownContent.tsx @@ -6,11 +6,15 @@ import { } from "@emotion/react"; import Divider from "@mui/material/Divider"; import MenuItem from "@mui/material/MenuItem"; -import Tooltip from "@mui/material/Tooltip"; import { PopoverClose } from "@radix-ui/react-popover"; import type * as TypesGen from "api/typesGenerated"; import { CopyButton } from "components/CopyButton/CopyButton"; import { Stack } from "components/Stack/Stack"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { CircleUserIcon, LogOutIcon, @@ -102,23 +106,31 @@ export const UserDropdownContent: FC = ({ - - - {buildInfo?.version} - + + + + {buildInfo?.version} + + + Browse the source code {buildInfo?.deployment_id && (
- - - {buildInfo.deployment_id} - + + + + {buildInfo.deployment_id} + + + + Deployment Identifier + = ({ justifyContent: "right", }} > - - - - {daemonScope} - - + + + + + {daemonScope} + + + + Scope {extraTags.map(([key, value]) => ( diff --git a/site/src/modules/resources/AgentMetadata.tsx b/site/src/modules/resources/AgentMetadata.tsx index 2517ae9115..dcdcf3fb32 100644 --- a/site/src/modules/resources/AgentMetadata.tsx +++ b/site/src/modules/resources/AgentMetadata.tsx @@ -1,5 +1,4 @@ import Skeleton from "@mui/material/Skeleton"; -import Tooltip from "@mui/material/Tooltip"; import { watchAgentMetadata } from "api/api"; import type { ServerSentEvent, @@ -8,6 +7,11 @@ import type { } from "api/typesGenerated"; import { displayError } from "components/GlobalSnackbar/utils"; import { Stack } from "components/Stack/Stack"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import dayjs from "dayjs"; import { type FC, @@ -183,10 +187,15 @@ const MetadataItem: FC = ({ item }) => { status === "loading" ? ( ) : status === "stale" ? ( - - - {item.result.value} - + + + + {item.result.value} + + + + This data is stale and no longer up to date + ) : ( { const StartingLifecycle: FC = () => { return ( - -
+ + +
+ + Starting... ); }; @@ -110,12 +117,15 @@ const StartErrorLifecycle: FC = ({ agent }) => { const ShuttingDownLifecycle: FC = () => { return ( - -
+ + +
+ + Stopping... ); }; @@ -170,12 +180,15 @@ const ShutdownErrorLifecycle: FC = ({ agent }) => { const OffLifecycle: FC = () => { return ( - -
+ + +
+ + Stopped ); }; @@ -218,24 +231,30 @@ const ConnectedStatus: FC = ({ agent }) => { const DisconnectedStatus: FC = () => { return ( - -
+ + +
+ + Disconnected ); }; const ConnectingStatus: FC = () => { return ( - -
+ + +
+ + Connecting... ); }; diff --git a/site/src/modules/resources/ResourceCard.test.tsx b/site/src/modules/resources/ResourceCard.test.tsx index 460caf51fb..f9fd887d8e 100644 --- a/site/src/modules/resources/ResourceCard.test.tsx +++ b/site/src/modules/resources/ResourceCard.test.tsx @@ -1,12 +1,12 @@ import { MockWorkspaceResource } from "testHelpers/entities"; -import { renderComponent } from "testHelpers/renderHelpers"; +import { render } from "testHelpers/renderHelpers"; import { screen } from "@testing-library/react"; import type { WorkspaceResourceMetadata } from "api/typesGenerated"; import { ResourceCard } from "./ResourceCard"; describe("Resource Card", () => { it("renders daily cost and metadata tiles", async () => { - renderComponent( + render( <>} />, ); expect( @@ -45,9 +45,7 @@ describe("Resource Card", () => { ], }; - renderComponent( - <>} />, - ); + render( <>} />); expect(screen.getByText(mockResource.daily_cost)).toBeInTheDocument(); expect( screen.getByText(mockResource.metadata?.[0].value), @@ -92,9 +90,7 @@ describe("Resource Card", () => { ], }; - renderComponent( - <>} />, - ); + render( <>} />); expect(screen.queryByText(mockResource.daily_cost)).not.toBeInTheDocument(); expect( screen.getByText(mockResource.metadata?.[0].value), diff --git a/site/src/modules/resources/ResourceCard.tsx b/site/src/modules/resources/ResourceCard.tsx index d40ea5563a..794462bcde 100644 --- a/site/src/modules/resources/ResourceCard.tsx +++ b/site/src/modules/resources/ResourceCard.tsx @@ -1,11 +1,15 @@ import type { Interpolation, Theme } from "@emotion/react"; import IconButton from "@mui/material/IconButton"; -import Tooltip from "@mui/material/Tooltip"; import type { WorkspaceAgent, WorkspaceResource } from "api/typesGenerated"; import { CopyableValue } from "components/CopyableValue/CopyableValue"; import { DropdownArrow } from "components/DropdownArrow/DropdownArrow"; import { MemoizedInlineMarkdown } from "components/Markdown/Markdown"; import { Stack } from "components/Stack/Stack"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { Children, type FC, type JSX, useState } from "react"; import { ResourceAvatar } from "./ResourceAvatar"; import { SensitiveValue } from "./SensitiveValue"; @@ -162,19 +166,23 @@ export const ResourceCard: FC = ({ resource, agentRow }) => { })}
{mLength > 4 && ( - - { - setShouldDisplayAllMetadata((value) => !value); - }} - size="large" - > - - + + + { + setShouldDisplayAllMetadata((value) => !value); + }} + size="large" + > + + + + + {shouldDisplayAllMetadata ? "Hide metadata" : "Show all metadata"} + )} diff --git a/site/src/modules/resources/SensitiveValue.tsx b/site/src/modules/resources/SensitiveValue.tsx index 3a0cf65bed..da63ef70d1 100644 --- a/site/src/modules/resources/SensitiveValue.tsx +++ b/site/src/modules/resources/SensitiveValue.tsx @@ -1,7 +1,10 @@ -import { css, type Interpolation, type Theme } from "@emotion/react"; import IconButton from "@mui/material/IconButton"; -import Tooltip from "@mui/material/Tooltip"; import { CopyableValue } from "components/CopyableValue/CopyableValue"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { EyeIcon, EyeOffIcon } from "lucide-react"; import { type FC, useState } from "react"; @@ -25,37 +28,28 @@ export const SensitiveValue: FC = ({ value }) => { ); return ( -
+
{displayValue} - - { - setShouldDisplay((value) => !value); - }} - size="small" - aria-label={buttonLabel} - > - {icon} - + + + { + setShouldDisplay((value) => !value); + }} + size="small" + aria-label={buttonLabel} + > + {icon} + + + {buttonLabel}
); }; - -const styles = { - button: css` - color: inherit; - `, -} satisfies Record>; diff --git a/site/src/modules/workspaces/WorkspaceBuildData/WorkspaceBuildData.tsx b/site/src/modules/workspaces/WorkspaceBuildData/WorkspaceBuildData.tsx index b849b59caa..9cd258caf8 100644 --- a/site/src/modules/workspaces/WorkspaceBuildData/WorkspaceBuildData.tsx +++ b/site/src/modules/workspaces/WorkspaceBuildData/WorkspaceBuildData.tsx @@ -1,8 +1,12 @@ import { type Interpolation, type Theme, useTheme } from "@emotion/react"; import Skeleton from "@mui/material/Skeleton"; -import Tooltip from "@mui/material/Tooltip"; import type { WorkspaceBuild } from "api/typesGenerated"; import { BuildIcon } from "components/BuildIcon/BuildIcon"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { InfoIcon } from "lucide-react"; import { createDayString } from "utils/createDayString"; import { @@ -45,13 +49,18 @@ export const WorkspaceBuildData = ({ build }: { build: WorkspaceBuild }) => { {!systemBuildReasons.includes(build.reason) && build.transition === "start" && ( - - ({ - color: theme.palette.info.light, - })} - className="size-icon-xs -mt-px" - /> + + + ({ + color: theme.palette.info.light, + })} + className="size-icon-xs -mt-px" + /> + + + {buildReasonLabels[build.reason]} + )}
diff --git a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicensesSettingsPageView.tsx b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicensesSettingsPageView.tsx index cc2e35df6b..9b56ae5a12 100644 --- a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicensesSettingsPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicensesSettingsPageView.tsx @@ -1,7 +1,6 @@ import { type Interpolation, type Theme, useTheme } from "@emotion/react"; import MuiLink from "@mui/material/Link"; import Skeleton from "@mui/material/Skeleton"; -import Tooltip from "@mui/material/Tooltip"; import type { GetLicensesResponse } from "api/api"; import type { Feature, UserStatusChangeCount } from "api/typesGenerated"; import { Button } from "components/Button/Button"; @@ -12,6 +11,11 @@ import { } from "components/SettingsHeader/SettingsHeader"; import { Spinner } from "components/Spinner/Spinner"; import { Stack } from "components/Stack/Stack"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { useWindowSize } from "hooks/useWindowSize"; import { PlusIcon, RotateCwIcon } from "lucide-react"; import type { FC } from "react"; @@ -80,17 +84,23 @@ const LicensesSettingsPageView: FC = ({ Add a license - - + + + + + + Refresh license entitlements. This is done automatically every 10 + minutes. + diff --git a/site/src/pages/DeploymentSettingsPage/NotificationsPage/NotificationEvents.tsx b/site/src/pages/DeploymentSettingsPage/NotificationsPage/NotificationEvents.tsx index dc220c1252..d116718be1 100644 --- a/site/src/pages/DeploymentSettingsPage/NotificationsPage/NotificationEvents.tsx +++ b/site/src/pages/DeploymentSettingsPage/NotificationsPage/NotificationEvents.tsx @@ -6,7 +6,6 @@ import ListItem from "@mui/material/ListItem"; import ListItemText, { listItemTextClasses } from "@mui/material/ListItemText"; import ToggleButton from "@mui/material/ToggleButton"; import ToggleButtonGroup from "@mui/material/ToggleButtonGroup"; -import Tooltip from "@mui/material/Tooltip"; import { getErrorMessage } from "api/errors"; import { type selectTemplatesByGroup, @@ -17,6 +16,11 @@ import { Alert } from "components/Alert/Alert"; import { Button } from "components/Button/Button"; import { displayError, displaySuccess } from "components/GlobalSnackbar/utils"; import { Stack } from "components/Stack/Stack"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { castNotificationMethod, methodIcons, @@ -186,22 +190,25 @@ const MethodToggleGroup: FC = ({ const Icon = methodIcons[method]; const label = methodLabels[method]; return ( - - { - // Retain the value if the user clicks the same button, ensuring - // at least one value remains selected. - if (method === value) { - e.preventDefault(); - e.stopPropagation(); - return; - } - }} - > - - + + + { + // Retain the value if the user clicks the same button, ensuring + // at least one value remains selected. + if (method === value) { + e.preventDefault(); + e.stopPropagation(); + return; + } + }} + > + + + + {label} ); })} diff --git a/site/src/pages/ExternalAuthPage/ExternalAuthPageView.tsx b/site/src/pages/ExternalAuthPage/ExternalAuthPageView.tsx index f99328ad72..a231dd0a6b 100644 --- a/site/src/pages/ExternalAuthPage/ExternalAuthPageView.tsx +++ b/site/src/pages/ExternalAuthPage/ExternalAuthPageView.tsx @@ -1,12 +1,16 @@ import type { Interpolation, Theme } from "@emotion/react"; import Link from "@mui/material/Link"; -import Tooltip from "@mui/material/Tooltip"; import type { ApiErrorResponse } from "api/errors"; import type { ExternalAuth, ExternalAuthDevice } from "api/typesGenerated"; import { Alert } from "components/Alert/Alert"; import { Avatar } from "components/Avatar/Avatar"; import { GitDeviceAuth } from "components/GitDeviceAuth/GitDeviceAuth"; import { SignInLayout } from "components/SignInLayout/SignInLayout"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { Welcome } from "components/Welcome/Welcome"; import { ExternalLinkIcon, RotateCwIcon } from "lucide-react"; import type { FC, ReactNode } from "react"; @@ -82,17 +86,22 @@ const ExternalAuthPageView: FC = ({ return; } return ( - - - - + + + + + + + + {install.account.login} + ); })} diff --git a/site/src/pages/HealthPage/DERPRegionPage.tsx b/site/src/pages/HealthPage/DERPRegionPage.tsx index 202493373b..bc0830fbf5 100644 --- a/site/src/pages/HealthPage/DERPRegionPage.tsx +++ b/site/src/pages/HealthPage/DERPRegionPage.tsx @@ -1,5 +1,4 @@ import { type Interpolation, type Theme, useTheme } from "@emotion/react"; -import Tooltip from "@mui/material/Tooltip"; import type { DERPNodeReport, DERPRegionReport, @@ -7,6 +6,11 @@ import type { HealthSeverity, } from "api/typesGenerated"; import { Alert } from "components/Alert/Alert"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { ChevronLeftIcon, CodeIcon, HashIcon } from "lucide-react"; import type { FC } from "react"; import { Link, useOutletContext, useParams } from "react-router"; @@ -85,15 +89,21 @@ const DERPRegionPage: FC = () => {
- - }> - {region!.RegionID} - + + + }> + {region!.RegionID} + + + Region ID - - }> - {region!.RegionCode} - + + + }> + {region!.RegionCode} + + + Region Code Embedded Relay @@ -127,13 +137,18 @@ const DERPRegionPage: FC = () => {
- - } - > - {report.round_trip_ping_ms}ms - + + + } + > + {report.round_trip_ping_ms}ms + + + + Round trip ping + Exchange Messages diff --git a/site/src/pages/HealthPage/HealthLayout.tsx b/site/src/pages/HealthPage/HealthLayout.tsx index 5c9c44dad0..ad127b0690 100644 --- a/site/src/pages/HealthPage/HealthLayout.tsx +++ b/site/src/pages/HealthPage/HealthLayout.tsx @@ -1,10 +1,14 @@ import CircularProgress from "@mui/material/CircularProgress"; import IconButton from "@mui/material/IconButton"; -import Tooltip from "@mui/material/Tooltip"; import { health, refreshHealth } from "api/queries/debug"; import type { HealthSeverity } from "api/typesGenerated"; import { ErrorAlert } from "components/Alert/ErrorAlert"; import { Loader } from "components/Loader/Loader"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import kebabCase from "lodash/fp/kebabCase"; import { BellOffIcon, RotateCcwIcon } from "lucide-react"; import { DashboardFullPage } from "modules/dashboard/DashboardLayout"; @@ -76,21 +80,26 @@ export const HealthLayout: FC = () => {
- - { - forceRefresh(); - }} - > - {isRefreshing ? ( - - ) : ( - - )} - + + + { + forceRefresh(); + }} + > + {isRefreshing ? ( + + ) : ( + + )} + + + + Refresh health checks +
diff --git a/site/src/pages/HealthPage/WebsocketPage.tsx b/site/src/pages/HealthPage/WebsocketPage.tsx index ef11b5049d..d91e1cfca6 100644 --- a/site/src/pages/HealthPage/WebsocketPage.tsx +++ b/site/src/pages/HealthPage/WebsocketPage.tsx @@ -1,7 +1,11 @@ import { useTheme } from "@emotion/react"; -import Tooltip from "@mui/material/Tooltip"; import type { HealthcheckReport } from "api/typesGenerated"; import { Alert } from "components/Alert/Alert"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { CodeIcon } from "lucide-react"; import { useOutletContext } from "react-router"; import { MONOSPACE_FONT_FAMILY } from "theme/constants"; @@ -45,10 +49,13 @@ const WebsocketPage = () => { })}
- - }> - {websocket.code} - + + + }> + {websocket.code} + + + Code
diff --git a/site/src/pages/HealthPage/WorkspaceProxyPage.tsx b/site/src/pages/HealthPage/WorkspaceProxyPage.tsx index 2276c24cbc..e80786e1df 100644 --- a/site/src/pages/HealthPage/WorkspaceProxyPage.tsx +++ b/site/src/pages/HealthPage/WorkspaceProxyPage.tsx @@ -1,7 +1,11 @@ import { useTheme } from "@emotion/react"; -import Tooltip from "@mui/material/Tooltip"; import type { HealthcheckReport } from "api/typesGenerated"; import { Alert } from "components/Alert/Alert"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { GlobeIcon, HashIcon } from "lucide-react"; import type { FC } from "react"; import { useOutletContext } from "react-router"; @@ -106,17 +110,25 @@ const WorkspaceProxyPage: FC = () => {
{region.wildcard_hostname && ( - - }> - {region.wildcard_hostname} - + + + }> + {region.wildcard_hostname} + + + + Wildcard Hostname + )} {region.version && ( - - }> - {region.version} - + + + }> + {region.version} + + + Version )} {region.derp_enabled && ( diff --git a/site/src/pages/IconsPage/IconsPage.tsx b/site/src/pages/IconsPage/IconsPage.tsx index a7574fced5..801601f7ad 100644 --- a/site/src/pages/IconsPage/IconsPage.tsx +++ b/site/src/pages/IconsPage/IconsPage.tsx @@ -3,7 +3,6 @@ import IconButton from "@mui/material/IconButton"; import InputAdornment from "@mui/material/InputAdornment"; import Link from "@mui/material/Link"; import TextField from "@mui/material/TextField"; -import Tooltip from "@mui/material/Tooltip"; import { CopyableValue } from "components/CopyableValue/CopyableValue"; import { EmptyState } from "components/EmptyState/EmptyState"; import { Margins } from "components/Margins/Margins"; @@ -12,6 +11,11 @@ import { PageHeaderSubtitle, PageHeaderTitle, } from "components/PageHeader/PageHeader"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { SearchIcon, XIcon } from "lucide-react"; import { type FC, type ReactNode, useMemo, useState } from "react"; import { @@ -75,20 +79,18 @@ const IconsPage: FC = () => { - You can suggest a new icon by submitting a Pull Request to our - public GitHub repository. Just keep in mind that it should be - relevant to many Coder users, and redistributable under a - permissive license. -

- } - > - - Suggest an icon - + + + + Suggest an icon + + + + You can suggest a new icon by submitting a Pull Request to our + public GitHub repository. Just keep in mind that it should be + relevant to many Coder users, and redistributable under a + permissive license. + } > @@ -122,13 +124,16 @@ const IconsPage: FC = () => { ), endAdornment: searchInputText && ( - - setSearchInputText("")} - > - - + + + setSearchInputText("")} + > + + + + Clear filter ), diff --git a/site/src/pages/TemplatePage/TemplateInsightsPage/TemplateInsightsPage.tsx b/site/src/pages/TemplatePage/TemplateInsightsPage/TemplateInsightsPage.tsx index db2659abf6..47e8f951eb 100644 --- a/site/src/pages/TemplatePage/TemplateInsightsPage/TemplateInsightsPage.tsx +++ b/site/src/pages/TemplatePage/TemplateInsightsPage/TemplateInsightsPage.tsx @@ -1,7 +1,6 @@ import { useTheme } from "@emotion/react"; import LinearProgress from "@mui/material/LinearProgress"; import Link from "@mui/material/Link"; -import Tooltip from "@mui/material/Tooltip"; import { entitlements } from "api/queries/entitlements"; import { insightsTemplate, @@ -33,6 +32,12 @@ import { } from "components/HelpTooltip/HelpTooltip"; import { Loader } from "components/Loader/Loader"; import { Stack } from "components/Stack/Stack"; +import { + Tooltip, + TooltipArrow, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata"; import { CircleCheck as CircleCheckIcon, @@ -495,24 +500,26 @@ const TemplateUsagePanel: FC = ({ {usage.display_name}
- - + + + + + + {Math.floor(percentage)}% + + = ({ }} >
Value
- -
Count
+ + +
Count
+
+ + The number of workspaces using this value +
{[...parameter.values] diff --git a/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.tsx b/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.tsx index cba63cdf65..93ed021989 100644 --- a/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.tsx +++ b/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.tsx @@ -1,6 +1,5 @@ import { type Interpolation, type Theme, useTheme } from "@emotion/react"; import IconButton from "@mui/material/IconButton"; -import Tooltip from "@mui/material/Tooltip"; import { getErrorDetail, getErrorMessage } from "api/errors"; import type { ProvisionerJobLog, @@ -23,6 +22,11 @@ import { } from "components/FullPageLayout/Topbar"; import { displayError, displaySuccess } from "components/GlobalSnackbar/utils"; import { Loader } from "components/Loader/Loader"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { ChevronLeftIcon, ExternalLinkIcon, @@ -217,10 +221,15 @@ export const TemplateVersionEditor: FC = ({ data-testid="topbar" >
- - - - + + + + + + + + Back to the template +
@@ -367,16 +376,19 @@ export const TemplateVersionEditor: FC = ({ }, }} > - - { - setCreateFileOpen(true); - event.currentTarget.blur(); - }} - > - - + + + { + setCreateFileOpen(true); + event.currentTarget.blur(); + }} + > + + + + Create File
= ({ * attempt to authenticate when the token expires. */} {link?.has_refresh_token && authenticated && ( - - + + + + + + Authentication token will automatically refresh when expired. + )} diff --git a/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.tsx b/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.tsx index 39bac4df71..730a3e8b04 100644 --- a/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.tsx +++ b/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.tsx @@ -6,7 +6,6 @@ import ListItem from "@mui/material/ListItem"; import ListItemIcon from "@mui/material/ListItemIcon"; import ListItemText, { listItemTextClasses } from "@mui/material/ListItemText"; import Switch from "@mui/material/Switch"; -import Tooltip from "@mui/material/Tooltip"; import { customNotificationTemplates, disableNotification, @@ -23,6 +22,11 @@ import type { import { displayError, displaySuccess } from "components/GlobalSnackbar/utils"; import { Loader } from "components/Loader/Loader"; import { Stack } from "components/Stack/Stack"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { useAuthenticated } from "hooks"; import { castNotificationMethod, @@ -199,8 +203,13 @@ const NotificationsPage: FC = () => { css={styles.listItemEndIcon} aria-label="Delivery method" > - - + + + + + + Delivery via {label} + diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx index 37dcd5ae4c..cfff697f57 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx @@ -1,6 +1,10 @@ -import Tooltip from "@mui/material/Tooltip"; import type { Workspace, WorkspaceBuildParameter } from "api/typesGenerated"; import { TopbarButton } from "components/FullPageLayout/Topbar"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { BanIcon, CircleStopIcon, @@ -30,29 +34,30 @@ export const UpdateButton: FC = ({ requireActiveVersion, }) => { return ( - + + handleAction()} + > + {requireActiveVersion ? : } + {loading ? ( + <>Updating… + ) : isRunning ? ( + <>Update and restart… + ) : ( + <>Update and start… + )} + + + + {requireActiveVersion ? "This template requires automatic updates on workspace startup. Contact your administrator if you want to preserve the template version." : isRunning ? "Stop workspace and restart it with the latest template version." - : "Start workspace with the latest template version." - } - > - handleAction()} - > - {requireActiveVersion ? : } - {loading ? ( - <>Updating… - ) : isRunning ? ( - <>Update and restart… - ) : ( - <>Update and start… - )} - + : "Start workspace with the latest template version."} + ); }; @@ -88,7 +93,14 @@ export const StartButton: FC = ({ ); if (tooltipText) { - mainButton = {mainButton}; + mainButton = ( + + {mainButton} + + {tooltipText} + + + ); } return ( diff --git a/site/src/pages/WorkspacePage/WorkspaceTopbar.tsx b/site/src/pages/WorkspacePage/WorkspaceTopbar.tsx index 2c346432de..59b7b9472e 100644 --- a/site/src/pages/WorkspacePage/WorkspaceTopbar.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceTopbar.tsx @@ -1,6 +1,5 @@ import { type Interpolation, type Theme, useTheme } from "@emotion/react"; import Link from "@mui/material/Link"; -import Tooltip from "@mui/material/Tooltip"; import { workspaceQuota } from "api/queries/workspaceQuota"; import type * as TypesGen from "api/typesGenerated"; import { Avatar } from "components/Avatar/Avatar"; @@ -19,6 +18,11 @@ import { HelpTooltipContent, HelpTooltipTrigger, } from "components/HelpTooltip/HelpTooltip"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { ChevronLeftIcon, CircleDollarSign, TrashIcon } from "lucide-react"; import { useDashboard } from "modules/dashboard/useDashboard"; import { linkToTemplate, useLinks } from "modules/navigation"; @@ -108,10 +112,13 @@ export const WorkspaceTopbar: FC = ({ return ( - - - - + + + + + + + Back to workspaces
diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index f8213847f9..59a18ecd25 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -1043,7 +1043,7 @@ export const MockWorkspaceAppStatus: TypesGen.WorkspaceAppStatus = { icon: "", }; -const MockWorkspaceAgentDisconnected: TypesGen.WorkspaceAgent = { +export const MockWorkspaceAgentDisconnected: TypesGen.WorkspaceAgent = { ...MockWorkspaceAgent, id: "test-workspace-agent-2", name: "another-workspace-agent",