From 8a9cbef038cd2e1260c6d6e628984937524a8adb Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 15 Feb 2024 23:01:53 +0000 Subject: [PATCH] chore: update no-restricted-imports lint rule - prevent importing from the "monolith" lodash module. individual modules are better for tree shaking. - prevent importing `useTheme` and types from @mui/material/styles. prefer importing from @emotion/react. --- site/.eslintrc.yaml | 5 ++ .../src/components/FullPageLayout/Sidebar.tsx | 62 ++++++++++--------- site/src/components/FullPageLayout/Topbar.tsx | 2 +- site/src/components/Menu/Search.tsx | 11 +++- site/src/hooks/usePaginatedQuery.ts | 2 +- site/src/pages/HealthPage/Content.tsx | 2 +- site/src/pages/HealthPage/DERPPage.tsx | 27 ++++---- .../HealthPage/ProvisionerDaemonsPage.tsx | 9 ++- site/src/pages/HealthPage/WebsocketPage.tsx | 2 +- .../pages/HealthPage/WorkspaceProxyPage.tsx | 7 ++- site/src/pages/HealthPage/healthyColor.ts | 4 +- .../pages/WorkspacePage/ResourcesSidebar.tsx | 16 +++-- .../WorkspacePage/ResourcesSidebarContent.tsx | 2 +- site/src/pages/WorkspacePage/Workspace.tsx | 2 +- .../WorkspaceScheduleControls.tsx | 1 - site/src/theme/index.ts | 1 + 16 files changed, 88 insertions(+), 67 deletions(-) diff --git a/site/.eslintrc.yaml b/site/.eslintrc.yaml index 9fc59fce26123..78da4dd93fdb9 100644 --- a/site/.eslintrc.yaml +++ b/site/.eslintrc.yaml @@ -144,6 +144,11 @@ rules: "You should use the native HTML elements as span, p, h1, h2, h3..." - name: "@mui/material/Box" message: "You should use a
instead" + - name: "@mui/material/styles" + importNames: ["Interpolation", "Theme", "useTheme"] + message: "Import from @emotion/react instead." + - name: "lodash" + message: "Import from lodash/ instead." no-unused-vars: "off" "object-curly-spacing": "off" react-hooks/exhaustive-deps: warn diff --git a/site/src/components/FullPageLayout/Sidebar.tsx b/site/src/components/FullPageLayout/Sidebar.tsx index 46f867e4619a6..a1e9817250775 100644 --- a/site/src/components/FullPageLayout/Sidebar.tsx +++ b/site/src/components/FullPageLayout/Sidebar.tsx @@ -1,9 +1,9 @@ -import { Interpolation, Theme, useTheme } from "@mui/material/styles"; -import { ComponentProps, HTMLAttributes } from "react"; -import { Link, LinkProps } from "react-router-dom"; +import { type Interpolation, type Theme, useTheme } from "@emotion/react"; +import { type ComponentProps, type FC, type HTMLAttributes } from "react"; +import { Link, type LinkProps } from "react-router-dom"; import { TopbarIconButton } from "./Topbar"; -export const Sidebar = (props: HTMLAttributes) => { +export const Sidebar: FC> = (props) => { const theme = useTheme(); return (
) => { ); }; -export const SidebarLink = (props: LinkProps) => { +export const SidebarLink: FC = (props) => { return ; }; -export const SidebarItem = ( - props: HTMLAttributes & { isActive?: boolean }, -) => { - const { isActive, ...buttonProps } = props; +interface SidebarItemProps extends HTMLAttributes { + isActive?: boolean; +} + +export const SidebarItem: FC = ({ + isActive, + ...buttonProps +}) => { const theme = useTheme(); return ( @@ -49,7 +53,7 @@ export const SidebarItem = ( ); }; -export const SidebarCaption = (props: HTMLAttributes) => { +export const SidebarCaption: FC> = (props) => { return ( ) => { ); }; -export const SidebarIconButton = ( - props: { isActive: boolean } & ComponentProps, -) => { - const theme = useTheme(); +interface SidebarIconButton extends ComponentProps { + isActive: boolean; +} +export const SidebarIconButton: FC = (props) => { return ( @@ -112,4 +103,19 @@ const styles = { backgroundColor: theme.palette.action.hover, }, }), + + activeSidebarIconButton: (theme) => ({ + opacity: 1, + position: "relative", + "&::before": { + content: '""', + position: "absolute", + left: 0, + top: 0, + bottom: 0, + width: 2, + backgroundColor: theme.palette.primary.main, + height: "100%", + }, + }), } satisfies Record>; diff --git a/site/src/components/FullPageLayout/Topbar.tsx b/site/src/components/FullPageLayout/Topbar.tsx index 27457faa473e3..217cacdb4ae7c 100644 --- a/site/src/components/FullPageLayout/Topbar.tsx +++ b/site/src/components/FullPageLayout/Topbar.tsx @@ -1,7 +1,7 @@ import { css } from "@emotion/css"; import Button, { ButtonProps } from "@mui/material/Button"; import IconButton, { IconButtonProps } from "@mui/material/IconButton"; -import { useTheme } from "@mui/material/styles"; +import { useTheme } from "@emotion/react"; import { AvatarProps, ExternalAvatar } from "components/Avatar/Avatar"; import { type FC, diff --git a/site/src/components/Menu/Search.tsx b/site/src/components/Menu/Search.tsx index 833f247fb3229..bb5cede3b5db8 100644 --- a/site/src/components/Menu/Search.tsx +++ b/site/src/components/Menu/Search.tsx @@ -1,9 +1,14 @@ import SearchOutlined from "@mui/icons-material/SearchOutlined"; // eslint-disable-next-line no-restricted-imports -- use it to have the component prop -import Box, { BoxProps } from "@mui/material/Box"; -import { Interpolation, Theme, useTheme } from "@mui/material/styles"; +import Box, { type BoxProps } from "@mui/material/Box"; +import { type Interpolation, type Theme, useTheme } from "@emotion/react"; import visuallyHidden from "@mui/utils/visuallyHidden"; -import { FC, HTMLAttributes, InputHTMLAttributes, forwardRef } from "react"; +import { + type FC, + type HTMLAttributes, + type InputHTMLAttributes, + forwardRef, +} from "react"; export const Search = forwardRef( ({ children, ...boxProps }, ref) => { diff --git a/site/src/hooks/usePaginatedQuery.ts b/site/src/hooks/usePaginatedQuery.ts index 5be2b5e3b6261..bc1844e2e34f0 100644 --- a/site/src/hooks/usePaginatedQuery.ts +++ b/site/src/hooks/usePaginatedQuery.ts @@ -1,7 +1,7 @@ import { useEffect } from "react"; import { useEffectEvent } from "./hookPolyfills"; import { type SetURLSearchParams, useSearchParams } from "react-router-dom"; -import { clamp } from "lodash"; +import clamp from "lodash/clamp"; import { type QueryFunctionContext, diff --git a/site/src/pages/HealthPage/Content.tsx b/site/src/pages/HealthPage/Content.tsx index a304205c58fe6..a55a5f6b515ed 100644 --- a/site/src/pages/HealthPage/Content.tsx +++ b/site/src/pages/HealthPage/Content.tsx @@ -14,7 +14,7 @@ import { css } from "@emotion/css"; import DoNotDisturbOnOutlined from "@mui/icons-material/DoNotDisturbOnOutlined"; import { HealthMessage, HealthSeverity } from "api/typesGenerated"; import Link from "@mui/material/Link"; -import { useTheme } from "@mui/material/styles"; +import { useTheme } from "@emotion/react"; const CONTENT_PADDING = 36; diff --git a/site/src/pages/HealthPage/DERPPage.tsx b/site/src/pages/HealthPage/DERPPage.tsx index c3771ad280b77..fc6c4e14f84d5 100644 --- a/site/src/pages/HealthPage/DERPPage.tsx +++ b/site/src/pages/HealthPage/DERPPage.tsx @@ -1,4 +1,16 @@ import { Link, useOutletContext } from "react-router-dom"; +import type { + HealthMessage, + HealthSeverity, + HealthcheckReport, +} from "api/typesGenerated"; +import Button from "@mui/material/Button"; +import LocationOnOutlined from "@mui/icons-material/LocationOnOutlined"; +import { Alert } from "components/Alert/Alert"; +import { Helmet } from "react-helmet-async"; +import { pageTitle } from "utils/page"; +import { useTheme } from "@emotion/react"; +import { type FC } from "react"; import { Header, HeaderTitle, @@ -9,19 +21,8 @@ import { Logs, HealthyDot, } from "./Content"; -import { - HealthMessage, - HealthSeverity, - HealthcheckReport, -} from "api/typesGenerated"; -import Button from "@mui/material/Button"; -import LocationOnOutlined from "@mui/icons-material/LocationOnOutlined"; -import { healthyColor } from "./healthyColor"; -import { Alert } from "components/Alert/Alert"; -import { Helmet } from "react-helmet-async"; -import { pageTitle } from "utils/page"; -import { useTheme } from "@mui/material/styles"; import { DismissWarningButton } from "./DismissWarningButton"; +import { healthyColor } from "./healthyColor"; const flags = [ "UDP", @@ -38,7 +39,7 @@ const flags = [ "PCP", ]; -export const DERPPage = () => { +export const DERPPage: FC = () => { const { derp } = useOutletContext(); const { netcheck, regions, netcheck_logs: logs } = derp; const theme = useTheme(); diff --git a/site/src/pages/HealthPage/ProvisionerDaemonsPage.tsx b/site/src/pages/HealthPage/ProvisionerDaemonsPage.tsx index b7e2b0f04d843..4788703ebb77b 100644 --- a/site/src/pages/HealthPage/ProvisionerDaemonsPage.tsx +++ b/site/src/pages/HealthPage/ProvisionerDaemonsPage.tsx @@ -9,23 +9,22 @@ import { } from "./Content"; import { Helmet } from "react-helmet-async"; import { pageTitle } from "utils/page"; -import { useTheme } from "@mui/material/styles"; +import { useTheme } from "@emotion/react"; import { DismissWarningButton } from "./DismissWarningButton"; import { Alert } from "components/Alert/Alert"; -import { HealthcheckReport } from "api/typesGenerated"; +import type { HealthcheckReport } from "api/typesGenerated"; import { createDayString } from "utils/createDayString"; - +import { type FC } from "react"; import { useOutletContext } from "react-router-dom"; import Business from "@mui/icons-material/Business"; import Person from "@mui/icons-material/Person"; import SwapHoriz from "@mui/icons-material/SwapHoriz"; import Tooltip from "@mui/material/Tooltip"; import Sell from "@mui/icons-material/Sell"; -import { FC } from "react"; import CloseIcon from "@mui/icons-material/Close"; import IconButton from "@mui/material/IconButton"; -export const ProvisionerDaemonsPage = () => { +export const ProvisionerDaemonsPage: FC = () => { const healthStatus = useOutletContext(); const { provisioner_daemons: daemons } = healthStatus; const theme = useTheme(); diff --git a/site/src/pages/HealthPage/WebsocketPage.tsx b/site/src/pages/HealthPage/WebsocketPage.tsx index 150432c311646..45376b6c87549 100644 --- a/site/src/pages/HealthPage/WebsocketPage.tsx +++ b/site/src/pages/HealthPage/WebsocketPage.tsx @@ -10,7 +10,7 @@ import { import { HealthcheckReport } from "api/typesGenerated"; import CodeOutlined from "@mui/icons-material/CodeOutlined"; import Tooltip from "@mui/material/Tooltip"; -import { useTheme } from "@mui/material/styles"; +import { useTheme } from "@emotion/react"; import { MONOSPACE_FONT_FAMILY } from "theme/constants"; import { Alert } from "components/Alert/Alert"; import { pageTitle } from "utils/page"; diff --git a/site/src/pages/HealthPage/WorkspaceProxyPage.tsx b/site/src/pages/HealthPage/WorkspaceProxyPage.tsx index d3798052dc2e8..c2058cc364b7d 100644 --- a/site/src/pages/HealthPage/WorkspaceProxyPage.tsx +++ b/site/src/pages/HealthPage/WorkspaceProxyPage.tsx @@ -8,18 +8,19 @@ import { Main, Pill, } from "./Content"; -import { HealthcheckReport } from "api/typesGenerated"; -import { useTheme } from "@mui/material/styles"; +import type { HealthcheckReport } from "api/typesGenerated"; +import { useTheme } from "@emotion/react"; import { createDayString } from "utils/createDayString"; import PublicOutlined from "@mui/icons-material/PublicOutlined"; import Tooltip from "@mui/material/Tooltip"; import TagOutlined from "@mui/icons-material/TagOutlined"; import { Alert } from "components/Alert/Alert"; +import { type FC } from "react"; import { Helmet } from "react-helmet-async"; import { pageTitle } from "utils/page"; import { DismissWarningButton } from "./DismissWarningButton"; -export const WorkspaceProxyPage = () => { +export const WorkspaceProxyPage: FC = () => { const healthStatus = useOutletContext(); const { workspace_proxy } = healthStatus; const { regions } = workspace_proxy.workspace_proxies; diff --git a/site/src/pages/HealthPage/healthyColor.ts b/site/src/pages/HealthPage/healthyColor.ts index d14bc808c0dca..97d69b08d559b 100644 --- a/site/src/pages/HealthPage/healthyColor.ts +++ b/site/src/pages/HealthPage/healthyColor.ts @@ -1,5 +1,5 @@ -import { Theme } from "@mui/material/styles"; -import { HealthSeverity } from "api/typesGenerated"; +import type { Theme } from "@emotion/react"; +import type { HealthSeverity } from "api/typesGenerated"; export const healthyColor = (theme: Theme, severity: HealthSeverity) => { switch (severity) { diff --git a/site/src/pages/WorkspacePage/ResourcesSidebar.tsx b/site/src/pages/WorkspacePage/ResourcesSidebar.tsx index 4cf6d9c2ac971..c71d18f0d0374 100644 --- a/site/src/pages/WorkspacePage/ResourcesSidebar.tsx +++ b/site/src/pages/WorkspacePage/ResourcesSidebar.tsx @@ -1,7 +1,7 @@ -import { Interpolation, Theme } from "@emotion/react"; +import { type Interpolation, type Theme, useTheme } from "@emotion/react"; import Skeleton from "@mui/material/Skeleton"; -import { useTheme } from "@mui/material/styles"; -import { WorkspaceResource } from "api/typesGenerated"; +import { type FC } from "react"; +import type { WorkspaceResource } from "api/typesGenerated"; import { Sidebar, SidebarCaption, @@ -16,9 +16,13 @@ type ResourcesSidebarProps = { isSelected: (resource: WorkspaceResource) => boolean; }; -export const ResourcesSidebar = (props: ResourcesSidebarProps) => { +export const ResourcesSidebar: FC = ({ + failed, + onChange, + isSelected, + resources, +}) => { const theme = useTheme(); - const { failed, onChange, isSelected, resources } = props; return ( @@ -83,7 +87,7 @@ export const ResourcesSidebar = (props: ResourcesSidebarProps) => { ); }; -export const ResourceSidebarItemSkeleton = () => { +export const ResourceSidebarItemSkeleton: FC = () => { return (
diff --git a/site/src/pages/WorkspacePage/ResourcesSidebarContent.tsx b/site/src/pages/WorkspacePage/ResourcesSidebarContent.tsx index ebc43cf73dbaf..5db9494521b4f 100644 --- a/site/src/pages/WorkspacePage/ResourcesSidebarContent.tsx +++ b/site/src/pages/WorkspacePage/ResourcesSidebarContent.tsx @@ -1,4 +1,4 @@ -import { useTheme } from "@mui/material/styles"; +import { useTheme } from "@emotion/react"; import { Workspace } from "api/typesGenerated"; import { SidebarLink, SidebarCaption } from "components/FullPageLayout/Sidebar"; diff --git a/site/src/pages/WorkspacePage/Workspace.tsx b/site/src/pages/WorkspacePage/Workspace.tsx index 31efc004c2aa7..6b999fc093b8f 100644 --- a/site/src/pages/WorkspacePage/Workspace.tsx +++ b/site/src/pages/WorkspacePage/Workspace.tsx @@ -15,7 +15,7 @@ import { WorkspaceDeletedBanner } from "./WorkspaceDeletedBanner"; import { WorkspaceTopbar } from "./WorkspaceTopbar"; import { HistorySidebar } from "./HistorySidebar"; import HistoryOutlined from "@mui/icons-material/HistoryOutlined"; -import { useTheme } from "@mui/material/styles"; +import { useTheme } from "@emotion/react"; import { SidebarIconButton } from "components/FullPageLayout/Sidebar"; import HubOutlined from "@mui/icons-material/HubOutlined"; import { ResourcesSidebar } from "./ResourcesSidebar"; diff --git a/site/src/pages/WorkspacePage/WorkspaceScheduleControls.tsx b/site/src/pages/WorkspacePage/WorkspaceScheduleControls.tsx index 4613f6d489c84..1241ce769b417 100644 --- a/site/src/pages/WorkspacePage/WorkspaceScheduleControls.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceScheduleControls.tsx @@ -16,7 +16,6 @@ import IconButton from "@mui/material/IconButton"; import RemoveIcon from "@mui/icons-material/RemoveOutlined"; import AddIcon from "@mui/icons-material/AddOutlined"; import Tooltip from "@mui/material/Tooltip"; -import _ from "lodash"; import { getErrorMessage } from "api/errors"; import { updateDeadline, diff --git a/site/src/theme/index.ts b/site/src/theme/index.ts index aa8283d779f69..49bd61cef3dae 100644 --- a/site/src/theme/index.ts +++ b/site/src/theme/index.ts @@ -1,3 +1,4 @@ +// eslint-disable-next-line no-restricted-imports -- we still use `Theme` as a basis for our actual theme, for now. import type { Theme as MuiTheme } from "@mui/material/styles"; import type * as monaco from "monaco-editor"; import type { NewTheme } from "./experimental";