From 5b5fbbed33ca4a922c7986781ff88fb4db44e2b4 Mon Sep 17 00:00:00 2001 From: Brett Kolodny Date: Thu, 14 Aug 2025 09:26:20 -0400 Subject: [PATCH] fix: implement proper overflow behavior for workspace history (#19340) Before: https://github.com/user-attachments/assets/2f1ff75c-4916-4d0a-a657-004d46691ea0 After: https://github.com/user-attachments/assets/a8e575b5-84f9-4eea-b318-93d2a3d60aa5 Also converts a lot of emotion components to tailwind --- .../src/components/FullPageLayout/Sidebar.tsx | 99 ++---- .../src/modules/dashboard/DashboardLayout.tsx | 4 +- .../modules/dashboard/Navbar/NavbarView.tsx | 2 +- .../pages/WorkspacePage/HistorySidebar.tsx | 63 ++-- site/src/pages/WorkspacePage/Workspace.tsx | 310 +++++++----------- 5 files changed, 186 insertions(+), 292 deletions(-) diff --git a/site/src/components/FullPageLayout/Sidebar.tsx b/site/src/components/FullPageLayout/Sidebar.tsx index 8a5eaf9b4f..f58e97ac60 100644 --- a/site/src/components/FullPageLayout/Sidebar.tsx +++ b/site/src/components/FullPageLayout/Sidebar.tsx @@ -1,30 +1,28 @@ -import { type Interpolation, type Theme, useTheme } from "@emotion/react"; import type { ComponentProps, FC, HTMLAttributes } from "react"; import { Link, type LinkProps } from "react-router"; +import { cn } from "utils/cn"; import { TopbarIconButton } from "./Topbar"; export const Sidebar: FC> = (props) => { - const theme = useTheme(); return (
); }; -export const SidebarLink: FC = (props) => { - return ; +export const SidebarLink: FC = ({ className, ...props }) => { + return ( + + ); }; interface SidebarItemProps extends HTMLAttributes { @@ -33,21 +31,16 @@ interface SidebarItemProps extends HTMLAttributes { export const SidebarItem: FC = ({ isActive, + className, ...buttonProps }) => { - const theme = useTheme(); - return ( + +
+ {builds + ? builds.map((build) => ( + + + + )) + : Array.from({ length: 15 }, (_, i) => ( + + + + ))} + {buildsQuery.hasNextPage && ( +
+ +
+ )}
- )} +
); }; diff --git a/site/src/pages/WorkspacePage/Workspace.tsx b/site/src/pages/WorkspacePage/Workspace.tsx index 07c5ec26d0..b96ddcdf7b 100644 --- a/site/src/pages/WorkspacePage/Workspace.tsx +++ b/site/src/pages/WorkspacePage/Workspace.tsx @@ -1,5 +1,3 @@ -import type { Interpolation, Theme } from "@emotion/react"; -import { useTheme } from "@emotion/react"; import HistoryOutlined from "@mui/icons-material/HistoryOutlined"; import HubOutlined from "@mui/icons-material/HubOutlined"; import AlertTitle from "@mui/material/AlertTitle"; @@ -68,7 +66,6 @@ export const Workspace: FC = ({ handleDebug, }) => { const navigate = useNavigate(); - const theme = useTheme(); const transitionStats = template !== undefined ? ActiveTransition(template, workspace) : undefined; @@ -100,18 +97,7 @@ export const Workspace: FC = ({ workspacePending && !haveBuildLogs && !provisionersHealthy && !isRestarting; return ( -
+
= ({ handleToggleFavorite={handleToggleFavorite} /> -
- { - setSidebarOption("resources"); - }} - > - - - { - setSidebarOption("history"); - }} - > - - -
- - {sidebarOption.value === "resources" && ( - - )} - {sidebarOption.value === "history" && ( - - )} - -
- {selectedResource && ( - - )} -
- {workspace.latest_build.status === "deleted" && ( - navigate("/templates")} - /> - )} - - {shouldShowProvisionerAlert && ( - - )} - - {workspace.latest_build.job.error && ( - - Workspace build failed - {workspace.latest_build.job.error} - - )} - - {transitionStats !== undefined && ( - - )} - - {shouldShowBuildLogs && ( - - )} - - {selectedResource && ( -
+
+
+ { + setSidebarOption("resources"); }} > - {selectedResource.agents - // If an agent has a `parent_id`, that means it is - // child of another agent. We do not want these agents - // to be displayed at the top-level on this page. We - // want them to display _as children_ of their parents. - ?.filter((agent) => agent.parent_id === null) - .map((agent) => ( - a.parent_id === agent.id, - )} - workspace={workspace} - template={template} - onUpdateAgent={handleUpdate} // On updating the workspace the agent version is also updated - /> - ))} + + + { + setSidebarOption("history"); + }} + > + + +
- {(!selectedResource.agents || - selectedResource.agents?.length === 0) && ( -
-
-

- No agents are currently assigned to this resource. -

-
-
- )} -
+ {sidebarOption.value === "resources" && ( + )} + {sidebarOption.value === "history" && ( + + )} +
- +
+ {selectedResource && ( + + )} +
+ {workspace.latest_build.status === "deleted" && ( + navigate("/templates")} + /> + )} + + {shouldShowProvisionerAlert && ( + + )} + + {workspace.latest_build.job.error && ( + + Workspace build failed + {workspace.latest_build.job.error} + + )} + + {transitionStats !== undefined && ( + + )} + + {shouldShowBuildLogs && ( + + )} + + {selectedResource && ( +
+ {selectedResource.agents + // If an agent has a `parent_id`, that means it is + // child of another agent. We do not want these agents + // to be displayed at the top-level on this page. We + // want them to display _as children_ of their parents. + ?.filter((agent) => agent.parent_id === null) + .map((agent) => ( + a.parent_id === agent.id, + )} + workspace={workspace} + template={template} + onUpdateAgent={handleUpdate} // On updating the workspace the agent version is also updated + /> + ))} + + {(!selectedResource.agents || + selectedResource.agents?.length === 0) && ( +
+
+

+ No agents are currently assigned to this resource. +

+
+
+ )} +
+ )} + + +
@@ -286,33 +252,3 @@ export const Workspace: FC = ({ const countAgents = (resource: TypesGen.WorkspaceResource) => { return resource.agents ? resource.agents.length : 0; }; - -const styles = { - content: { - padding: 32, - gridArea: "content", - overflowY: "auto", - position: "relative", - }, - - dotsBackground: (theme) => ({ - "--d": "1px", - background: ` - radial-gradient( - circle at - var(--d) - var(--d), - - ${theme.palette.dots} calc(var(--d) - 1px), - ${theme.palette.background.default} var(--d) - ) - -2px -2px / 16px 16px - `, - }), - - actions: (theme) => ({ - [theme.breakpoints.down("md")]: { - flexDirection: "column", - }, - }), -} satisfies Record>;