refactor(site): remove Stack component (#24503)

## Summary

Remove the deprecated `Stack` component and replace all usages with
Tailwind flex utility classes.

- Replaced `<Stack>` → `<div className="flex flex-col gap-4">` (and
variants per props)
- Updated `StackLabel` and `FormFields` to no longer depend on `Stack`
- Deleted `Stack.tsx` and `Stack.stories.tsx`

74 files changed, -226 lines net.

> 🤖 Generated by Coder Agents

---------

Co-authored-by: Jake Howell <jacob@coder.com>
This commit is contained in:
Kayla はな
2026-04-28 12:02:13 -06:00
committed by GitHub
co-authored by Jake Howell
parent 55ed6cfa06
commit 5afb297042
74 changed files with 265 additions and 519 deletions
@@ -5,7 +5,6 @@ import {
Sidebar as BaseSidebar,
SettingsSidebarNavItem as SidebarNavItem,
} from "#/components/Sidebar/Sidebar";
import { Stack } from "#/components/Stack/Stack";
import type { Permissions } from "#/modules/permissions";
import { getPrereleaseFlag } from "#/utils/buildInfo";
@@ -86,9 +85,9 @@ export const DeploymentSidebarView: FC<DeploymentSidebarViewProps> = ({
)}
{permissions.viewAnyGroup && (
<SidebarNavItem href="/deployment/groups">
<Stack direction="row" alignItems="center" spacing={0.5}>
<div className="flex flex-row items-center gap-1">
Groups {showOrganizations && <ArrowUpRightIcon size={16} />}
</Stack>
</div>
</SidebarNavItem>
)}
{permissions.viewOrganizationIDPSyncSettings && (
@@ -108,9 +107,9 @@ export const DeploymentSidebarView: FC<DeploymentSidebarViewProps> = ({
)}
{permissions.editDeploymentConfig && (
<SidebarNavItem href="/agents/settings/agents">
<Stack direction="row" alignItems="center" spacing={0.5}>
<div className="flex flex-row items-center gap-1">
Manage Coder Agents <ArrowUpRightIcon size={16} />
</Stack>
</div>
</SidebarNavItem>
)}
</div>
+2 -3
View File
@@ -15,7 +15,6 @@ import type {
WorkspaceAgentMetadata,
} from "#/api/typesGenerated";
import { Skeleton } from "#/components/Skeleton/Skeleton";
import { Stack } from "#/components/Stack/Stack";
import {
Tooltip,
TooltipContent,
@@ -139,7 +138,7 @@ export const AgentMetadata: FC<AgentMetadataProps> = ({
const AgentMetadataSkeleton: FC = () => {
return (
<Stack alignItems="baseline" direction="row" spacing={6}>
<div className="flex flex-row items-baseline gap-12">
<div className="leading-relaxed flex flex-col overflow-visible flex-shrink-0">
<Skeleton width={40} height={6} variant="text" />
<Skeleton width={65} height={8} variant="text" />
@@ -154,7 +153,7 @@ const AgentMetadataSkeleton: FC = () => {
<Skeleton width={40} height={6} variant="text" />
<Skeleton width={65} height={8} variant="text" />
</div>
</Stack>
</div>
);
};
@@ -10,7 +10,6 @@ import {
HelpPopoverTitle,
HelpPopoverTrigger,
} from "#/components/HelpPopover/HelpPopover";
import { Stack } from "#/components/Stack/Stack";
import { agentVersionStatus } from "../../utils/workspace";
type AgentOutdatedTooltipProps = {
@@ -46,25 +45,25 @@ export const AgentOutdatedTooltip: FC<AgentOutdatedTooltipProps> = ({
</span>
</HelpPopoverTrigger>
<HelpPopoverContent>
<Stack spacing={1}>
<div className="flex flex-col gap-2">
<div>
<HelpPopoverTitle>{title}</HelpPopoverTitle>
<HelpPopoverText>{text}</HelpPopoverText>
</div>
<Stack spacing={0.5}>
<div className="flex flex-col gap-1">
<span className="font-semibold text-content-primary">
Agent version
</span>
<span>{agent.version}</span>
</Stack>
</div>
<Stack spacing={0.5}>
<div className="flex flex-col gap-1">
<span className="font-semibold text-content-primary">
Server version
</span>
<span>{serverVersion}</span>
</Stack>
</div>
<HelpPopoverLinksGroup>
<HelpPopoverAction
@@ -78,7 +77,7 @@ export const AgentOutdatedTooltip: FC<AgentOutdatedTooltipProps> = ({
Update workspace
</HelpPopoverAction>
</HelpPopoverLinksGroup>
</Stack>
</div>
</HelpPopoverContent>
</HelpPopover>
);
+19 -35
View File
@@ -3,7 +3,6 @@ import type { FC } from "react";
import type { WorkspaceAgent } from "#/api/typesGenerated";
import { TerminalIcon } from "#/components/Icons/TerminalIcon";
import { VSCodeIcon } from "#/components/Icons/VSCodeIcon";
import { Stack } from "#/components/Stack/Stack";
import { DisplayAppNameMap } from "./AppLink/AppLink";
import { AppPreview } from "./AppLink/AppPreview";
import { BaseIcon } from "./AppLink/BaseIcon";
@@ -22,27 +21,21 @@ export const AgentRowPreview: FC<AgentRowPreviewProps> = ({
alignValues,
}) => {
return (
<Stack
<div
key={agent.id}
direction="row"
alignItems="center"
justifyContent="space-between"
className="flex flex-row items-center justify-between gap-4"
css={styles.agentRow}
>
<Stack direction="row" alignItems="baseline">
<div className="flex flex-row items-baseline gap-4">
<div css={styles.agentStatusWrapper}>
<div css={styles.agentStatusPreview} />
</div>
<Stack
alignItems="baseline"
direction="row"
spacing={4}
<div
className="flex flex-row items-baseline gap-8"
css={styles.agentData}
>
<Stack
direction="row"
alignItems="baseline"
spacing={1}
<div
className="flex flex-row items-baseline gap-2"
css={[
styles.noShrink,
styles.agentDataItem,
@@ -55,12 +48,10 @@ export const AgentRowPreview: FC<AgentRowPreviewProps> = ({
>
<span>Agent:</span>
<span css={styles.agentDataValue}>{agent.name}</span>
</Stack>
</div>
<Stack
direction="row"
alignItems="baseline"
spacing={1}
<div
className="flex flex-row items-baseline gap-2"
css={[
styles.noShrink,
styles.agentDataItem,
@@ -75,21 +66,14 @@ export const AgentRowPreview: FC<AgentRowPreviewProps> = ({
<span css={[styles.agentDataValue, styles.agentOS]}>
{agent.operating_system}
</span>
</Stack>
</div>
<Stack
direction="row"
alignItems="center"
spacing={1}
<div
className="flex flex-row items-center gap-2"
css={styles.agentDataItem}
>
<span>Apps:</span>
<Stack
direction="row"
alignItems="center"
spacing={0.5}
wrap="wrap"
>
<div className="flex flex-row items-center gap-1 flex-wrap">
{/* We display all modules returned in agent.apps */}
{agent.apps.map((app) => (
<AppPreview key={app.slug}>
@@ -130,11 +114,11 @@ export const AgentRowPreview: FC<AgentRowPreviewProps> = ({
{agent.apps.length === 0 && agent.display_apps.length === 0 && (
<span css={styles.agentDataValue}>None</span>
)}
</Stack>
</Stack>
</Stack>
</Stack>
</Stack>
</div>
</div>
</div>
</div>
</div>
);
};
@@ -1,14 +1,8 @@
import type { FC, PropsWithChildren } from "react";
import { Stack } from "#/components/Stack/Stack";
export const AppPreview: FC<PropsWithChildren> = ({ children }) => {
return (
<Stack
className="flex items-center h-8 px-3 rounded-full border border-solid border-surface-quaternary text-content-primary bg-surface-secondary flex-shrink-0 w-fit text-xs [&>svg]:w-[13px] [&>img]:w-[13px]"
alignItems="center"
direction="row"
spacing={1}
>
<div className="flex flex-row items-center gap-2 h-8 px-3 rounded-full border border-solid border-surface-quaternary text-content-primary bg-surface-secondary flex-shrink-0 w-fit text-xs [&>svg]:w-[13px] [&>img]:w-[13px]">
{children}
</Stack>
</div>
);
};
+5 -8
View File
@@ -5,7 +5,6 @@ import { ChevronDownIcon } from "#/components/AnimatedIcons/ChevronDown";
import { Button } from "#/components/Button/Button";
import { CopyableValue } from "#/components/CopyableValue/CopyableValue";
import { MemoizedInlineMarkdown } from "#/components/Markdown/InlineMarkdown";
import { Stack } from "#/components/Stack/Stack";
import {
Tooltip,
TooltipContent,
@@ -97,13 +96,11 @@ export const ResourceCard: FC<ResourceCardProps> = ({ resource, agentRow }) => {
return (
<div key={resource.id} css={styles.resourceCard} className="resource-card">
<Stack
direction="row"
alignItems="flex-start"
<div
className="flex flex-row items-start gap-20"
css={styles.resourceCardHeader}
spacing={10}
>
<Stack direction="row" spacing={1} css={styles.resourceCardProfile}>
<div className="flex flex-row gap-2" css={styles.resourceCardProfile}>
<div>
<ResourceAvatar resource={resource} />
</div>
@@ -111,7 +108,7 @@ export const ResourceCard: FC<ResourceCardProps> = ({ resource, agentRow }) => {
<div css={styles.metadataLabel}>{resource.type}</div>
<div css={styles.metadataValue}>{resource.name}</div>
</div>
</Stack>
</div>
<div
className="grow-[2] grid gap-x-10 gap-y-6"
@@ -180,7 +177,7 @@ export const ResourceCard: FC<ResourceCardProps> = ({ resource, agentRow }) => {
</TooltipContent>
</Tooltip>
)}
</Stack>
</div>
{resource.agents && resource.agents.length > 0 && (
<div>{resource.agents.map(agentRow)}</div>
+2 -3
View File
@@ -2,7 +2,6 @@ import { type FC, type JSX, useState } from "react";
import type { WorkspaceAgent, WorkspaceResource } from "#/api/typesGenerated";
import { ChevronDownIcon } from "#/components/AnimatedIcons/ChevronDown";
import { Button } from "#/components/Button/Button";
import { Stack } from "#/components/Stack/Stack";
import { ResourceCard } from "./ResourceCard";
const countAgents = (resource: WorkspaceResource) => {
@@ -26,7 +25,7 @@ export const Resources: FC<ResourcesProps> = ({ resources, agentRow }) => {
const hasHideResources = resources.some((r) => r.hide);
return (
<Stack direction="column" spacing={0} className="bg-surface-primary">
<div className="flex flex-col bg-surface-primary">
{displayResources.map((resource) => (
<ResourceCard
key={resource.id}
@@ -50,6 +49,6 @@ export const Resources: FC<ResourcesProps> = ({ resources, agentRow }) => {
</Button>
</div>
)}
</Stack>
</div>
);
};
@@ -14,7 +14,6 @@ import {
PopoverContent,
PopoverTrigger,
} from "#/components/Popover/Popover";
import { Stack } from "#/components/Stack/Stack";
import { docs } from "#/utils/docs";
interface AgentSSHButtonProps {
@@ -49,7 +48,7 @@ export const AgentSSHButton: FC<AgentSSHButtonProps> = ({
</HelpPopoverText>
<ol style={{ margin: 0, padding: 0 }}>
<Stack spacing={0.5} className="mt-3">
<div className="flex flex-col gap-1 mt-3">
<SSHStep
helpText="Configure SSH hosts on machine:"
codeExample="coder config-ssh"
@@ -58,7 +57,7 @@ export const AgentSSHButton: FC<AgentSSHButtonProps> = ({
helpText="Connect to the agent:"
codeExample={`ssh ${agentName}.${workspaceName}.${workspaceOwnerUsername}.${sshSuffix}`}
/>
</Stack>
</div>
</ol>
<HelpPopoverLinksGroup>
@@ -36,7 +36,6 @@ import {
SelectValue,
} from "#/components/Select/Select";
import { Slider } from "#/components/Slider/Slider";
import { Stack } from "#/components/Stack/Stack";
import { Switch } from "#/components/Switch/Switch";
import { TagInput } from "#/components/TagInput/TagInput";
import { Textarea } from "#/components/Textarea/Textarea";
@@ -505,7 +504,7 @@ const MaskableInput: FC<MaskableInputProps> = ({
const [showMaskedInput, setShowMaskedInput] = useState(false);
return (
<Stack direction="row" spacing={0} alignItems="center">
<div className="flex flex-row items-center">
<Input
id={id}
type={masked && showMaskedInput ? "text" : type}
@@ -535,7 +534,7 @@ const MaskableInput: FC<MaskableInputProps> = ({
)}
</Button>
)}
</Stack>
</div>
);
};
@@ -552,7 +551,7 @@ const MaskableTextArea: FC<MaskableInputProps> = ({
const [showMaskedInput, setShowMaskedInput] = useState(false);
return (
<Stack direction="row" spacing={0} alignItems="center">
<div className="flex flex-row items-center">
<Textarea
ref={textareaRef}
id={id}
@@ -589,7 +588,7 @@ const MaskableTextArea: FC<MaskableInputProps> = ({
)}
</Button>
)}
</Stack>
</div>
);
};
@@ -15,7 +15,6 @@ import type { DialogProps } from "#/components/Dialogs/Dialog";
import { FormFields } from "#/components/Form/Form";
import { Loader } from "#/components/Loader/Loader";
import { Pill } from "#/components/Pill/Pill";
import { Stack } from "#/components/Stack/Stack";
import { TemplateUpdateMessage } from "#/modules/templates/TemplateUpdateMessage";
import { createDayString } from "#/utils/createDayString";
@@ -55,7 +54,7 @@ export const ChangeWorkspaceVersionDialog: FC<
confirmText="Change"
title="Change version"
description={
<Stack>
<div className="flex flex-col gap-4">
<p>You are about to change the version of this workspace.</p>
{validVersions ? (
<>
@@ -90,16 +89,8 @@ export const ChangeWorkspaceVersionDialog: FC<
/>
}
title={
<Stack
direction="row"
justifyContent="space-between"
style={{ width: "100%" }}
>
<Stack
direction="row"
alignItems="center"
spacing={1}
>
<div className="flex flex-row justify-between gap-4 w-full">
<div className="flex flex-row items-center gap-2">
{option.name}
{option.message && (
<InfoIcon
@@ -107,10 +98,10 @@ export const ChangeWorkspaceVersionDialog: FC<
className="size-icon-xs"
/>
)}
</Stack>
</div>
{workspace.template_active_version_id ===
option.id && <Pill type="success">Active</Pill>}
</Stack>
</div>
}
subtitle={createDayString(option.created_at)}
/>
@@ -155,7 +146,7 @@ export const ChangeWorkspaceVersionDialog: FC<
) : (
<Loader />
)}
</Stack>
</div>
}
/>
);
@@ -12,7 +12,6 @@ import {
type ConfirmDialogProps,
} from "#/components/Dialogs/ConfirmDialog/ConfirmDialog";
import { Skeleton } from "#/components/Skeleton/Skeleton";
import { Stack } from "#/components/Stack/Stack";
import { cn } from "#/utils/cn";
type DownloadLogsDialogProps = Pick<
@@ -140,7 +139,7 @@ export const DownloadLogsDialog: FC<DownloadLogsDialogProps> = ({
}
}}
description={
<Stack className="pb-4">
<div className="flex flex-col gap-4 pb-4">
<p>
Downloading logs will create a zip file containing all logs from all
jobs in this workspace. This may take a while.
@@ -162,7 +161,7 @@ export const DownloadLogsDialog: FC<DownloadLogsDialogProps> = ({
/>
))}
</ul>
</Stack>
</div>
}
/>
);