chore: migrate workspace agent row styling to Tailwind (#22195)

This commit is contained in:
Jaayden Halko
2026-02-26 00:43:29 +07:00
committed by GitHub
parent 4e365e59b6
commit 4e1cedf8fd
2 changed files with 60 additions and 232 deletions
+59 -222
View File
@@ -1,4 +1,3 @@
import type { Interpolation, Theme } from "@emotion/react";
import Collapse from "@mui/material/Collapse";
import Divider from "@mui/material/Divider";
import Skeleton from "@mui/material/Skeleton";
@@ -25,6 +24,7 @@ import {
import { Link as RouterLink } from "react-router";
import AutoSizer from "react-virtualized-auto-sizer";
import type { FixedSizeList as List, ListOnScrollProps } from "react-window";
import { cn } from "utils/cn";
import { AgentApps, organizeAgentApps } from "./AgentApps/AgentApps";
import { AgentDevcontainerCard } from "./AgentDevcontainerCard";
import { AgentExternal } from "./AgentExternal";
@@ -52,6 +52,43 @@ interface AgentRowProps {
onUpdateAgent: () => void;
}
const statusBorderClassByStatus: Partial<
Record<WorkspaceAgent["status"], string>
> = {
connected: "border-border-success",
connecting: "border-border-pending",
timeout: "border-border-warning",
};
const statusBorderClassByLifecycle: Partial<
Record<WorkspaceAgent["lifecycle_state"], string>
> = {
starting: "border-border-pending",
shutting_down: "border-border-pending",
ready: "border-border-success",
start_timeout: "border-border-warning",
shutdown_timeout: "border-border-warning",
start_error: "border-border-destructive",
shutdown_error: "border-border-destructive",
off: "border-border",
};
const getAgentBorderClass = (
agent: WorkspaceAgent,
hasErrorState: boolean,
): string => {
if (hasErrorState) {
return "border-border";
}
// Lifecycle state is more specific than connection status, so it wins.
return (
statusBorderClassByLifecycle[agent.lifecycle_state] ??
statusBorderClassByStatus[agent.status] ??
"border-border"
);
};
export const AgentRow: FC<AgentRowProps> = ({
agent,
subAgents,
@@ -143,24 +180,26 @@ export const AgentRow: FC<AgentRowProps> = ({
const hasSubdomainApps = agent.apps?.some((app) => app.subdomain);
const shouldShowWildcardWarning =
hasSubdomainApps && !proxy.proxy?.wildcard_hostname;
const borderClass = getAgentBorderClass(
agent,
Boolean(hasDevcontainerErrors || shouldShowWildcardWarning),
);
return (
<div
key={agent.id}
className="flex flex-col max-w-full"
css={[
styles.agentRow,
styles[`agentRow-${agent.status}`],
styles[`agentRow-lifecycle-${agent.lifecycle_state}`],
(hasDevcontainerErrors || shouldShowWildcardWarning) &&
styles.agentRowWithErrors,
]}
className={cn(
"flex max-w-full flex-col rounded-lg border border-solid bg-surface-primary text-sm shadow-md",
borderClass,
)}
>
<header css={styles.header}>
<div css={styles.agentInfo}>
<div css={styles.agentNameAndStatus}>
<header className="flex flex-wrap items-center justify-between gap-4 px-4 pt-4 pl-8 leading-normal md:gap-6 [&:has(+_[role='alert'])]:pb-4">
<div className="flex min-w-0 items-center gap-6 text-sm text-content-secondary">
<div className="flex min-w-0 w-full items-center gap-4 md:w-auto">
<AgentStatus agent={agent} />
<span css={styles.agentName}>{agent.name}</span>
<span className="block max-w-[260px] overflow-hidden text-ellipsis whitespace-nowrap text-base font-semibold text-content-primary">
{agent.name}
</span>
</div>
{agent.status === "connected" && (
<>
@@ -207,7 +246,7 @@ export const AgentRow: FC<AgentRowProps> = ({
</div>
</header>
<div css={styles.content}>
<div className="flex flex-col gap-8 p-8">
{workspace.latest_app_status?.agent_id === agent.id && (
<section>
<h3 className="sr-only">App statuses</h3>
@@ -229,7 +268,7 @@ export const AgentRow: FC<AgentRowProps> = ({
{shouldShowWildcardWarning && <WildcardHostnameWarning />}
{shouldDisplayAppsSection && (
<section css={styles.apps}>
<section className="flex flex-wrap gap-4 [&:empty]:hidden">
{shouldDisplayAgentApps && (
<>
{showVSCode && (
@@ -263,18 +302,18 @@ export const AgentRow: FC<AgentRowProps> = ({
)}
{agent.status === "connecting" && !isExternalAgent && (
<section css={styles.apps}>
<section className="flex flex-wrap gap-4 [&:empty]:hidden">
<Skeleton
width={80}
height={32}
variant="rectangular"
css={styles.buttonSkeleton}
className="rounded"
/>
<Skeleton
width={110}
height={32}
variant="rectangular"
css={styles.buttonSkeleton}
className="rounded"
/>
</section>
)}
@@ -307,11 +346,7 @@ export const AgentRow: FC<AgentRowProps> = ({
</div>
{hasStartupFeatures && (
<section
css={(theme) => ({
borderTop: `1px solid ${theme.palette.divider}`,
})}
>
<section className="border-0 border-t border-solid border-border">
<Collapse in={showLogs}>
<AutoSizer disableHeight>
{({ width }) => (
@@ -320,7 +355,7 @@ export const AgentRow: FC<AgentRowProps> = ({
innerRef={logListDivRef}
height={256}
width={width}
css={styles.startupLogs}
className="max-h-[420px] border-0 border-b border-solid border-border"
onScroll={handleLogScroll}
overflowed={agent.logs_overflowed}
logs={agentLogs.map((l) => ({
@@ -353,201 +388,3 @@ export const AgentRow: FC<AgentRowProps> = ({
</div>
);
};
const styles = {
agentRow: (theme) => ({
fontSize: 14,
border: `1px solid ${theme.palette.text.secondary}`,
backgroundColor: theme.palette.background.default,
borderRadius: 8,
boxShadow: theme.shadows[3],
}),
"agentRow-connected": (theme) => ({
borderColor: theme.palette.success.light,
}),
"agentRow-disconnected": (theme) => ({
borderColor: theme.palette.divider,
}),
"agentRow-connecting": (theme) => ({
borderColor: theme.palette.info.light,
}),
"agentRow-timeout": (theme) => ({
borderColor: theme.palette.warning.light,
}),
"agentRow-lifecycle-created": {},
"agentRow-lifecycle-starting": (theme) => ({
borderColor: theme.palette.info.light,
}),
"agentRow-lifecycle-ready": (theme) => ({
borderColor: theme.palette.success.light,
}),
"agentRow-lifecycle-start_timeout": (theme) => ({
borderColor: theme.palette.warning.light,
}),
"agentRow-lifecycle-start_error": (theme) => ({
borderColor: theme.palette.error.light,
}),
"agentRow-lifecycle-shutting_down": (theme) => ({
borderColor: theme.palette.info.light,
}),
"agentRow-lifecycle-shutdown_timeout": (theme) => ({
borderColor: theme.palette.warning.light,
}),
"agentRow-lifecycle-shutdown_error": (theme) => ({
borderColor: theme.palette.error.light,
}),
"agentRow-lifecycle-off": (theme) => ({
borderColor: theme.palette.divider,
}),
header: (theme) => ({
padding: "16px 16px 0 32px",
display: "flex",
gap: 24,
alignItems: "center",
justifyContent: "space-between",
flexWrap: "wrap",
lineHeight: "1.5",
"&:has(+ [role='alert'])": {
paddingBottom: 16,
},
[theme.breakpoints.down("md")]: {
gap: 16,
},
}),
agentInfo: (theme) => ({
display: "flex",
alignItems: "center",
gap: 24,
color: theme.palette.text.secondary,
fontSize: 14,
}),
agentNameAndInfo: (theme) => ({
display: "flex",
alignItems: "center",
gap: 24,
flexWrap: "wrap",
[theme.breakpoints.down("md")]: {
gap: 12,
},
}),
content: {
padding: 32,
display: "flex",
flexDirection: "column",
gap: 32,
},
apps: (theme) => ({
display: "flex",
gap: 16,
flexWrap: "wrap",
"&:empty": {
display: "none",
},
[theme.breakpoints.down("md")]: {
marginLeft: 0,
justifyContent: "flex-start",
},
}),
agentDescription: (theme) => ({
fontSize: 14,
color: theme.palette.text.secondary,
}),
agentNameAndStatus: (theme) => ({
display: "flex",
alignItems: "center",
gap: 16,
[theme.breakpoints.down("md")]: {
width: "100%",
},
}),
agentName: (theme) => ({
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
maxWidth: 260,
fontWeight: 600,
flexShrink: 0,
width: "fit-content",
fontSize: 16,
color: theme.palette.text.primary,
[theme.breakpoints.down("md")]: {
overflow: "unset",
},
}),
agentDataGroup: {
display: "flex",
alignItems: "baseline",
gap: 48,
},
agentData: (theme) => ({
display: "flex",
flexDirection: "column",
fontSize: 12,
"& > *:first-of-type": {
fontWeight: 500,
color: theme.palette.text.secondary,
},
}),
buttonSkeleton: {
borderRadius: 4,
},
agentErrorMessage: (theme) => ({
fontSize: 12,
fontWeight: 400,
marginTop: 4,
color: theme.palette.warning.light,
}),
agentOS: {
textTransform: "capitalize",
},
startupLogs: (theme) => ({
maxHeight: 420,
borderBottom: `1px solid ${theme.palette.divider}`,
backgroundColor: theme.palette.background.paper,
paddingTop: 16,
// We need this to be able to apply the padding top from startupLogs
"& > div": {
position: "relative",
},
}),
agentRowWithErrors: (theme) => ({
borderColor: theme.palette.divider,
}),
} satisfies Record<string, Interpolation<Theme>>;
+1 -10
View File
@@ -159,16 +159,7 @@ export const Workspace: FC<WorkspaceProps> = ({
)}
</div>
<div
style={{
background: `radial-gradient(
circle at 1px 1px,
hsl(var(--surface-invert-secondary)) 0,
transparent 1px
) -2px -2px / 16px 16px`,
}}
className="p-8 overflow-y-auto relative w-full"
>
<div className="relative w-full overflow-y-auto bg-[radial-gradient(circle_at_1px_1px,hsl(var(--surface-invert-secondary))_0,transparent_1px)] bg-[-2px_-2px] bg-[length:16px_16px] p-8">
{selectedResource && (
<ResourceMetadata
resource={selectedResource}