chore: migrate some emotion styles to tailwind (#23817)

This commit is contained in:
Kayla はな
2026-03-31 10:07:33 -06:00
committed by GitHub
parent c9e335c453
commit 755e8be5ad
94 changed files with 199 additions and 569 deletions
+1 -1
View File
@@ -37,7 +37,7 @@ export const AvatarCard: FC<AvatarCardProps> = ({
*
* @see {@link https://css-tricks.com/flexbox-truncated-text/}
*/}
<div css={{ marginRight: "auto", minWidth: 0 }}>
<div className="mr-auto min-w-0">
<h3
// Lets users hover over truncated text to see whole thing
title={header}
+1 -6
View File
@@ -75,12 +75,7 @@ export const DeprecatedBadge: React.FC = () => {
export const Badges: React.FC<React.PropsWithChildren> = ({ children }) => {
return (
<Stack
css={{ margin: "0 0 16px" }}
direction="row"
alignItems="center"
spacing={1}
>
<Stack className="mb-4" direction="row" alignItems="center" spacing={1}>
{children}
</Stack>
);
@@ -1,19 +1,18 @@
import type { Interpolation, Theme } from "@emotion/react";
import type { FC } from "react";
import { CoderIcon } from "#/components/Icons/CoderIcon";
import { getApplicationName, getLogoURL } from "#/utils/appearance";
import { cn } from "#/utils/cn";
/**
* Enterprise customers can set a custom logo for their Coder application. Use
* the custom logo wherever the Coder logo is used, if a custom one is provided.
*/
export const CustomLogo: FC<{ css?: Interpolation<Theme> }> = (props) => {
export const CustomLogo: FC<{ className?: string }> = ({ className }) => {
const applicationName = getApplicationName();
const logoURL = getLogoURL();
return logoURL ? (
<img
{...props}
alt={applicationName}
src={logoURL}
// This prevent browser to display the ugly error icon if the
@@ -24,10 +23,9 @@ export const CustomLogo: FC<{ css?: Interpolation<Theme> }> = (props) => {
onLoad={(e) => {
e.currentTarget.style.display = "inline";
}}
css={{ maxWidth: 200 }}
className="application-logo"
className={cn("max-w-[200px] application-logo", className)}
/>
) : (
<CoderIcon {...props} className="w-12 h-12" />
<CoderIcon className={cn("w-12 h-12", className)} />
);
};
@@ -78,7 +78,7 @@ export const DeleteDialog: FC<DeleteDialogProps> = ({
<TextField
fullWidth
autoFocus
css={{ marginTop: 24 }}
className="mt-6"
name="confirmation"
autoComplete="off"
id={`${hookId}-confirm`}
@@ -77,12 +77,7 @@ export const DurationField: FC<DurationFieldProps> = (props) => {
return (
<div>
<div
css={{
display: "flex",
gap: 8,
}}
>
<div className="flex gap-2">
<TextField
{...textFieldProps}
fullWidth
+1 -1
View File
@@ -146,7 +146,7 @@ const BaseSkeleton: FC<SkeletonProps> = ({ children, ...skeletonProps }) => {
};
export const MenuSkeleton: FC = () => {
return <BaseSkeleton css={{ minWidth: 200, flexShrink: 0 }} />;
return <BaseSkeleton className="min-w-[200px] shrink-0" />;
};
type FilterProps = {
+1 -12
View File
@@ -43,18 +43,7 @@ export const IconField: FC<IconFieldProps> = ({
endAdornment: hasIcon ? (
<InputAdornment
position="end"
css={{
width: 24,
height: 24,
display: "flex",
alignItems: "center",
justifyContent: "center",
"& img": {
maxWidth: "100%",
objectFit: "contain",
},
}}
className="w-6 h-6 flex items-center justify-center [&_img]:max-w-full [&_img]:object-contain"
>
<ExternalImage
alt=""
+1 -1
View File
@@ -24,7 +24,7 @@ export const JetBrainsIcon = (props: SvgIconProps): JSX.Element => (
25.59l85.73-58.84a7.35 7.35 0 0 0 3.17-6.05z"
fill="#fff"
/>
<path d="m60 60h60v60h-60z" css={{ fill: "#000 !important" }} />
<path d="m60 60h60v60h-60z" className="![fill:#000]" />
<g fill="#fff">
<path d="m66.53 108.75h22.5v3.75h-22.5z" />
<path
+1 -1
View File
@@ -18,7 +18,7 @@ export const Logs: FC<LogsProps> = ({
}) => {
return (
<div css={styles.root} className={`${className} logs-container`}>
<div css={{ minWidth: "fit-content" }}>
<div className="min-w-fit">
{lines.map((line) => (
<LogLine key={line.id} level={line.level}>
{!hideTimestamps && (
+4 -4
View File
@@ -4,6 +4,7 @@ import {
containerWidthMedium,
sidePadding,
} from "#/theme/constants";
import { cn } from "#/utils/cn";
type Size = "regular" | "medium" | "small";
@@ -20,20 +21,19 @@ type MarginsProps = JSX.IntrinsicElements["div"] & {
export const Margins: FC<MarginsProps> = ({
size = "regular",
children,
className,
...divProps
}) => {
const maxWidth = widthBySize[size];
return (
<div
{...divProps}
css={{
marginLeft: "auto",
marginRight: "auto",
style={{
maxWidth: maxWidth,
paddingLeft: sidePadding,
paddingRight: sidePadding,
width: "100%",
}}
className={cn("mx-auto w-full", className)}
>
{children}
</div>
@@ -14,13 +14,8 @@ const meta: Meta<typeof OverflowY> = {
children: numbers.map((num, i) => (
<p
key={num}
css={{
height: "50px",
padding: 0,
margin: 0,
color: "black",
backgroundColor: i % 2 === 0 ? "white" : "gray",
}}
className="h-[50px] p-0 m-0 text-black"
style={{ backgroundColor: i % 2 === 0 ? "white" : "gray" }}
>
Element {num}
</p>
+2 -4
View File
@@ -27,12 +27,10 @@ export const OverflowY: FC<OverflowYProps> = ({
return (
<div
css={{
width: "100%",
className="w-full overflow-y-auto shrink"
style={{
height: computedHeight,
maxHeight: computedMaxHeight,
overflowY: "auto",
flexShrink: 1,
}}
{...attrs}
>
@@ -63,18 +63,7 @@ const _PageHeaderActions: FC<PropsWithChildren> = ({ children }) => {
};
export const PageHeaderTitle: FC<PropsWithChildren> = ({ children }) => {
return (
<h1
css={{
fontSize: 18,
fontWeight: 500,
margin: 0,
lineHeight: "24px",
}}
>
{children}
</h1>
);
return <h1 className="text-lg font-medium m-0 leading-6">{children}</h1>;
};
export const PageHeaderSubtitle: FC<PropsWithChildren> = ({ children }) => {
@@ -242,7 +242,7 @@ export const RichParameterInput: FC<RichParameterInputProps> = ({
data-testid={`parameter-field-${parameter.name}`}
>
<ParameterLabel parameter={parameter} isPreset={isPreset} />
<div css={{ display: "flex", flexDirection: "column" }}>
<div className="flex flex-col">
<RichParameterField
{...fieldProps}
onChange={onChange}
@@ -271,7 +271,7 @@ export const RichParameterInput: FC<RichParameterInputProps> = ({
</FormHelperText>
)}
{autofillSource && autofillDescription[autofillSource] && (
<div css={{ marginTop: 4, fontSize: 12 }}>
<div className="mt-1 text-xs">
🪄 Autofilled {autofillDescription[autofillSource]}
</div>
)}
@@ -345,7 +345,7 @@ const RichParameterField: FC<RichParameterInputProps> = ({
spacing={small ? 1 : 0}
alignItems={small ? "center" : undefined}
direction={small ? "row" : "column"}
css={{ padding: small ? undefined : "4px 0" }}
className={small ? undefined : "py-1"}
>
{small ? (
<Tooltip>
+1 -7
View File
@@ -33,13 +33,7 @@ export const SidebarHeader: FC<SidebarHeaderProps> = ({
return (
<Stack direction="row" spacing={1} className="mb-4">
{avatar}
<div
css={{
overflow: "hidden",
display: "flex",
flexDirection: "column",
}}
>
<div className="overflow-hidden flex flex-col">
{linkTo ? (
<Link className={cn(titleStyles.normal, "no-underline")} to={linkTo}>
{title}
+2 -3
View File
@@ -36,11 +36,10 @@ export const AppStatusStateIcon: FC<AppStatusStateIconProps> = ({
// remove the stroke so it is not overly thick.
return (
<PauseIcon
css={{ strokeWidth: 0 }}
className={cn([
"text-content-secondary",
className,
"text-content-secondary stroke-0",
disabled ? "fill-content-disabled" : "fill-content-secondary",
className,
])}
/>
);
+2 -11
View File
@@ -79,7 +79,7 @@ export const DashboardLayout: FC = () => {
}),
}}
message={
<div css={{ display: "flex", gap: 16 }}>
<div className="flex gap-4">
<InfoIcon
className="size-icon-xs"
css={(theme) => ({
@@ -114,16 +114,7 @@ export const DashboardFullPage: FC<HTMLAttributes<HTMLDivElement>> = ({
...attrs
}) => {
return (
<div
{...attrs}
css={{
flex: 1,
display: "flex",
flexDirection: "column",
flexBasis: 0,
minHeight: "100%",
}}
>
<div {...attrs} className="flex-1 flex flex-col basis-0 min-h-full">
{children}
</div>
);
@@ -64,7 +64,7 @@ export const ProxyMenu: FC<ProxyMenuProps> = ({ proxyContextValue }) => {
<Skeleton
width="110px"
height={40}
css={{ borderRadius: 6, transform: "none" }}
className="rounded-[6px] transform-none"
/>
);
}
@@ -54,7 +54,7 @@ const DeploymentSettingsLayout: FC = () => {
<section className="px-10 max-w-screen-2xl mx-auto">
<div className="flex flex-row gap-28 py-10">
<DeploymentSidebar />
<div css={{ flexGrow: 1 }}>
<div className="grow">
<Suspense fallback={<Loader />}>
<Outlet />
</Suspense>
+7 -34
View File
@@ -45,47 +45,20 @@ export const Provisioner: FC<ProvisionerProps> = ({
isWarning && { borderColor: theme.palette.warning.light },
]}
>
<header
css={{
padding: 24,
display: "flex",
alignItems: "center",
justifyContent: "space-between",
gap: 24,
}}
>
<div
css={{
display: "flex",
alignItems: "center",
gap: 24,
objectFit: "fill",
}}
>
<div css={{ lineHeight: "160%" }}>
<h4 css={{ fontWeight: 500, margin: 0 }}>{provisioner.name}</h4>
<header className="p-6 flex items-center justify-between gap-6">
<div className="flex items-center gap-6 object-fill">
<div className="leading-[160%]">
<h4 className="font-medium m-0">{provisioner.name}</h4>
<span css={{ color: theme.palette.text.secondary }}>
<code>{provisioner.version}</code>
</span>
</div>
</div>
<div
css={{
marginLeft: "auto",
display: "flex",
flexWrap: "wrap",
gap: 12,
justifyContent: "right",
}}
>
<div className="ml-auto flex flex-wrap gap-3 justify-end">
<Tooltip>
<TooltipTrigger asChild>
<Pill size="lg" icon={iconScope}>
<span
css={{
":first-letter": { textTransform: "uppercase" },
}}
>
<span className="[&::first-letter]:uppercase">
{daemonScope}
</span>
</Pill>
@@ -110,7 +83,7 @@ export const Provisioner: FC<ProvisionerProps> = ({
}}
>
{warnings && warnings.length > 0 ? (
<div css={{ display: "flex", flexDirection: "column" }}>
<div className="flex flex-col">
{warnings.map((warning) => (
<span key={warning.code}>{warning.message}</span>
))}
@@ -35,7 +35,7 @@ export const ProvisionerTag: FC<ProvisionerTagProps> = ({
const { valid, value: boolValue } = parseBool(tagValue);
const kv = (
<>
<span css={{ fontWeight: 600 }}>{tagName}</span> <span>{tagValue}</span>
<span className="font-semibold">{tagName}</span> <span>{tagValue}</span>
</>
);
const content = onDelete ? (
@@ -27,7 +27,7 @@ export const AgentLogLine: FC<AgentLogLineProps> = ({
}, [line.output]);
return (
<LogLine css={{ paddingLeft: 16 }} level={line.level} style={style}>
<LogLine className="pl-4" level={line.level} style={style}>
{sourceIcon}
<LogLinePrefix
css={styles.number}
@@ -251,18 +251,8 @@ export const PortForwardPopoverView: FC<PortForwardPopoverViewProps> = ({
return (
<>
<div
css={{
maxHeight: 320,
overflowY: "auto",
}}
>
<Stack
direction="column"
css={{
padding: 20,
}}
>
<div className="max-h-80 overflow-y-auto">
<Stack direction="column" className="p-5">
<Stack
direction="row"
justifyContent="space-between"
@@ -280,13 +270,7 @@ export const PortForwardPopoverView: FC<PortForwardPopoverViewProps> = ({
The listening ports are exclusively accessible to you. Selecting
HTTP/S will change the protocol for all listening ports.
</HelpTooltipText>
<Stack
direction="row"
gap={2}
css={{
paddingBottom: 8,
}}
>
<Stack direction="row" gap={2} className="pb-2">
<FormControl size="small" css={styles.protocolFormControl}>
<Select
css={styles.listeningPortProtocol}
+2 -5
View File
@@ -114,12 +114,9 @@ export const ResourceCard: FC<ResourceCardProps> = ({ resource, agentRow }) => {
</Stack>
<div
css={{
flexGrow: 2,
display: "grid",
className="grow-[2] grid gap-x-10 gap-y-6"
style={{
gridTemplateColumns: `repeat(${gridWidth}, minmax(0, 1fr))`,
gap: 40,
rowGap: 24,
}}
>
{resource.daily_cost > 0 && (
@@ -78,21 +78,21 @@ export const VSCodeDesktopButton: FC<VSCodeDesktopButtonProps> = (props) => {
}}
>
<MenuItem
css={{ fontSize: 14 }}
className="text-sm"
onClick={() => {
selectVariant("vscode");
}}
>
<VSCodeIcon css={{ width: 12, height: 12 }} />
<VSCodeIcon className="w-3 h-3" />
{DisplayAppNameMap.vscode}
</MenuItem>
<MenuItem
css={{ fontSize: 14 }}
className="text-sm"
onClick={() => {
selectVariant("vscode-insiders");
}}
>
<VSCodeInsidersIcon css={{ width: 12, height: 12 }} />
<VSCodeInsidersIcon className="w-3 h-3" />
{DisplayAppNameMap.vscode_insiders}
</MenuItem>
</Menu>
@@ -82,21 +82,21 @@ export const VSCodeDevContainerButton: FC<VSCodeDevContainerButtonProps> = (
}}
>
<MenuItem
css={{ fontSize: 14 }}
className="text-sm"
onClick={() => {
selectVariant("vscode");
}}
>
<VSCodeIcon css={{ width: 12, height: 12 }} />
<VSCodeIcon className="w-3 h-3" />
{DisplayAppNameMap.vscode}
</MenuItem>
<MenuItem
css={{ fontSize: 14 }}
className="text-sm"
onClick={() => {
selectVariant("vscode-insiders");
}}
>
<VSCodeInsidersIcon css={{ width: 12, height: 12 }} />
<VSCodeInsidersIcon className="w-3 h-3" />
{DisplayAppNameMap.vscode_insiders}
</MenuItem>
</Menu>
@@ -23,7 +23,7 @@ export const TemplateExampleCard: FC<TemplateExampleCardProps> = ({
<div css={styles.icon}>
<ExternalImage
src={example.icon}
css={{ width: "100%", height: "100%", objectFit: "contain" }}
className="w-full h-full object-contain"
/>
</div>
@@ -39,15 +39,13 @@ export const TemplateExampleCard: FC<TemplateExampleCardProps> = ({
</div>
<div>
<h4 css={{ fontSize: 14, fontWeight: 600, margin: 0, marginBottom: 4 }}>
{example.name}
</h4>
<h4 className="text-sm font-semibold m-0 mb-1">{example.name}</h4>
<span css={styles.description}>
{example.description}{" "}
<Link
component={RouterLink}
to={`/starter-templates/${example.id}`}
css={{ display: "inline-block", fontSize: 13, marginTop: 4 }}
className="inline-block text-[13px] mt-1"
>
Read more
</Link>
@@ -30,7 +30,7 @@ export const WorkspaceBuildData = ({ build }: { build: WorkspaceBuild }) => {
color: theme.roles[statusType].fill.solid,
}}
/>
<div css={{ overflow: "hidden" }}>
<div className="overflow-hidden">
<div
css={{
color: theme.palette.text.primary,
@@ -42,9 +42,8 @@ export const WorkspaceBuildData = ({ build }: { build: WorkspaceBuild }) => {
gap: 4,
}}
>
<span css={{ textTransform: "capitalize" }}>{build.transition}</span>{" "}
by{" "}
<span css={{ fontWeight: 500 }}>
<span className="capitalize">{build.transition}</span> by{" "}
<span className="font-medium">
{getDisplayWorkspaceBuildInitiatedBy(build)}
</span>
{!systemBuildReasons.includes(build.reason) &&
@@ -83,12 +82,7 @@ export const WorkspaceBuildDataSkeleton = () => {
<Skeleton variant="circular" width={16} height={16} />
<div>
<Skeleton variant="text" width={94} height={16} />
<Skeleton
variant="text"
width={60}
height={14}
css={{ marginTop: 2 }}
/>
<Skeleton variant="text" width={60} height={14} className="mt-0.5" />
</div>
</div>
);
@@ -142,7 +142,7 @@ export const DownloadLogsDialog: FC<DownloadLogsDialogProps> = ({
}
}}
description={
<Stack css={{ paddingBottom: 16 }}>
<Stack className="pb-4">
<p>
Downloading logs will create a zip file containing all logs from all
jobs in this workspace. This may take a while.
@@ -61,7 +61,7 @@ export const UpdateBuildParametersDialog: FC<
Workspace parameters
</DialogTitle>
<DialogContent css={styles.content}>
<DialogContentText css={{ margin: 0 }}>
<DialogContentText className="m-0">
This template has new parameters that must be configured to complete
the update
</DialogContentText>
@@ -74,7 +74,7 @@ export const WorkspaceDeleteDialog: FC<WorkspaceDeleteDialogProps> = ({
<p className="name">{workspace.name}</p>
<p className="label">workspace</p>
</div>
<div css={{ textAlign: "right" }}>
<div className="text-right">
<p className="info">{dayjs(workspace.created_at).fromNow()}</p>
<p className="label">created</p>
</div>
@@ -90,7 +90,7 @@ export const WorkspaceDeleteDialog: FC<WorkspaceDeleteDialogProps> = ({
<TextField
fullWidth
autoFocus
css={{ marginTop: 32 }}
className="mt-8"
name="confirmation"
autoComplete="off"
id={`${hookId}-confirm`}
@@ -113,9 +113,9 @@ export const WorkspaceDeleteDialog: FC<WorkspaceDeleteDialogProps> = ({
/>
{hasTask && (
<div css={styles.warnContainer}>
<div css={{ flexDirection: "column" }}>
<div className="flex-col">
<p className="info">This workspace is related to a task</p>
<span css={{ fontSize: 12, marginTop: 4, display: "block" }}>
<span className="text-xs mt-1 block">
Deleting this workspace will also delete{" "}
<Link
href={`/tasks/${workspace.owner_name}/${workspace.task_id}`}
@@ -129,7 +129,7 @@ export const WorkspaceDeleteDialog: FC<WorkspaceDeleteDialogProps> = ({
)}
{canOrphan && (
<div css={styles.warnContainer}>
<div css={{ flexDirection: "column" }}>
<div className="flex-col">
<Checkbox
id="orphan_resources"
size="small"
@@ -143,9 +143,9 @@ export const WorkspaceDeleteDialog: FC<WorkspaceDeleteDialogProps> = ({
data-testid="orphan-checkbox"
/>
</div>
<div css={{ flexDirection: "column" }}>
<div className="flex-col">
<p className="info">Orphan Resources</p>
<span css={{ fontSize: 12, marginTop: 4, display: "block" }}>
<span className="text-xs mt-1 block">
As a Template Admin, you may skip resource cleanup to delete
a failed workspace. Resources such as volumes and virtual
machines will not be destroyed.&nbsp;
@@ -93,7 +93,7 @@ const WorkspaceOutdatedTooltipContent: FC<TooltipContentProps> = ({
</HelpTooltipText>
<div css={styles.container}>
<div css={{ lineHeight: "1.6" }}>
<div className="leading-[1.6]">
<div css={styles.bold}>New version</div>
<div>
{activeVersion ? (
@@ -110,7 +110,7 @@ const WorkspaceOutdatedTooltipContent: FC<TooltipContentProps> = ({
</div>
</div>
<div css={{ lineHeight: "1.6" }}>
<div className="leading-[1.6]">
<div css={styles.bold}>Message</div>
<div>
{activeVersion ? (
@@ -177,13 +177,7 @@ export const StagesChart: FC<StagesChartProps> = ({
}}
>
{t.error && (
<CircleAlertIcon
className="size-icon-sm"
css={{
color: "#F87171",
marginRight: 4,
}}
/>
<CircleAlertIcon className="size-icon-sm text-[#F87171] mr-1" />
)}
<Blocks count={t.visibleResources} />
</ClickableBar>
@@ -285,7 +285,7 @@ export const InvalidTimeRange: Story = {
export const MultipleAgents: Story = {
decorators: [
(Story) => (
<div css={{ "--collapse-body-height": "600px" }}>
<div style={{ "--collapse-body-height": "600px" } as React.CSSProperties}>
<Story />
</div>
),
@@ -15,16 +15,16 @@ export const CliInstallPageView: FC<CliInstallPageViewProps> = ({ origin }) => {
<p css={styles.instructions}>
Copy the command below and{" "}
<strong css={{ display: "block" }}>paste it in your terminal.</strong>
<strong className="block">paste it in your terminal.</strong>
</p>
<CodeExample
css={{ maxWidth: "100%" }}
className="max-w-full"
code={`curl -fsSL ${origin}/install.sh | sh`}
secret={false}
/>
<div css={{ paddingTop: 16 }}>
<div className="pt-4">
<RouterLink to="/workspaces" css={styles.backLink}>
Go to workspaces
</RouterLink>
@@ -47,38 +47,24 @@ export const CreateTemplateGalleryPageView: FC<
</PageHeader>
<Stack spacing={8}>
<Stack direction="row" spacing={4}>
<div css={{ width: 202 }}>
<div className="w-[202px]">
<h2 css={styles.sectionTitle}>
Choose a starting point for your new template
</h2>
</div>
<div
css={{
display: "flex",
flexWrap: "wrap",
gap: 32,
height: "max-content",
}}
>
<Card variant="outlined" css={{ width: 320, borderRadius: 6 }}>
<div className="flex flex-wrap gap-8 h-max">
<Card variant="outlined" className="w-[320px] rounded-[6px]">
<CardActionArea
component={RouterLink}
to="/templates/new"
sx={{ height: 115, padding: 1 }}
>
<CardContent>
<Stack
direction="row"
spacing={3}
css={{ alignItems: "center" }}
>
<Stack direction="row" spacing={3} className="items-center">
<div css={styles.icon}>
<ExternalImage
src="/emojis/1f4e1.png"
css={{
width: "100%",
height: "100%",
}}
className="w-full h-full"
/>
</div>
<div>
@@ -66,7 +66,7 @@ export const StarterTemplates: FC<StarterTemplatesProps> = ({
return (
<Stack direction="row" spacing={4} alignItems="flex-start">
{starterTemplatesByTag && tags && (
<Stack css={{ width: 202, flexShrink: 0, position: "sticky" }}>
<Stack className="w-[202px] shrink-0 sticky">
<h2 css={styles.sectionTitle}>Choose a starter template</h2>
<span css={styles.filterCaption}>Filter</span>
{tags.map((tag) => (
@@ -81,14 +81,7 @@ export const StarterTemplates: FC<StarterTemplatesProps> = ({
</Stack>
)}
<div
css={{
display: "flex",
flexWrap: "wrap",
gap: 32,
height: "max-content",
}}
>
<div className="flex flex-wrap gap-8 h-max">
{visibleTemplates?.map((example) => (
<TemplateExampleCard
css={(theme) => ({
@@ -435,7 +435,7 @@ const fillNameAndDisplayWithFilename = async (
const ProvisionerWarning: FC = () => {
return (
<Alert severity="warning" css={{ marginBottom: 16 }} prominent>
<Alert severity="warning" className="mb-4" prominent>
This organization does not have any provisioners. Before you create a
template, you&apos;ll need to configure a provisioner.{" "}
<Link href={docs("/admin/provisioners#organization-scoped-provisioners")}>
@@ -79,7 +79,7 @@ export const DuplicateTemplateView: FC<CreateTemplatePageViewProps> = ({
return (
<>
{totalPrebuilds > 0 && (
<Alert severity="warning" css={{ marginBottom: 16 }}>
<Alert severity="warning" className="mb-4">
This template has prebuilds configured. Duplicating this template will
automatically cause {totalPrebuilds}{" "}
{totalPrebuilds === 1 ? "prebuild" : "prebuilds"} to be created.
@@ -79,12 +79,7 @@ const CreateTokenPage: FC<CreateTokenPageProps> = ({ now }) => {
<CodeExample
secret={false}
code={newToken?.key ?? ""}
css={{
minHeight: "auto",
userSelect: "all",
width: "100%",
marginTop: 24,
}}
className="min-h-0 select-all w-full mt-6"
/>
</>
);
@@ -41,7 +41,7 @@ export const AnnouncementBannerDialog: FC<AnnouncementBannerDialogProps> = ({
return (
<Dialog css={styles.dialogWrapper} open onClose={onCancel}>
{/* Banner preview */}
<div css={{ position: "fixed", top: 0, left: 0, right: 0 }}>
<div className="fixed top-0 left-0 right-0">
<AnnouncementBannerView
message={bannerForm.values.message}
backgroundColor={bannerForm.values.background_color}
@@ -53,12 +53,7 @@ export const ExternalAuthSettingsPageView: FC<
}}
/>
<div
css={{
marginTop: 24,
marginBottom: 24,
}}
>
<div className="mt-6 mb-6">
<Alert severity="info" actions={<PremiumBadge key="enterprise" />}>
Integrating with multiple External authentication providers is an
Premium feature.
@@ -90,7 +85,7 @@ export const ExternalAuthSettingsPageView: FC<
config.external_auth?.length === 0) && (
<TableRow>
<TableCell colSpan={999}>
<div css={{ textAlign: "center" }}>
<div className="text-center">
No providers have been configured!
</div>
</TableCell>
@@ -82,7 +82,7 @@ export const AddNewLicensePageView: FC<AddNewLicenseProps> = ({
description="Select a text file that contains your license key."
/>
<Stack css={{ paddingTop: 40 }}>
<Stack className="pt-10">
<DividerWithText>or</DividerWithText>
<Fieldset
@@ -107,11 +107,7 @@ export const NotificationEvents: FC<NotificationEventsProps> = ({
)}
{Object.entries(templatesByGroup).map(([group, templates]) => (
<Card
key={group}
variant="outlined"
css={{ background: "transparent", width: "100%" }}
>
<Card key={group} variant="outlined" className="bg-transparent w-full">
<List>
<ListItem css={styles.listHeader}>
<ListItemText css={styles.listItemText} primary={group} />
@@ -117,12 +117,7 @@ export const EditOAuth2AppPageView: FC<EditOAuth2AppProps> = ({
</p>
<CodeExample
code={fullNewSecret.client_secret_full}
css={{
minHeight: "auto",
userSelect: "all",
width: "100%",
marginTop: 24,
}}
className="min-h-auto select-all w-full mt-6"
/>
</>
}
@@ -260,7 +255,7 @@ const OAuth2AppSecretsTable: FC<OAuth2AppSecretsTableProps> = ({
{!isLoadingSecrets && (!secrets || secrets.length === 0) && (
<TableRow>
<TableCell colSpan={999}>
<div css={{ textAlign: "center" }}>
<div className="text-center">
No client secrets have been generated.
</div>
</TableCell>
@@ -80,7 +80,7 @@ const OAuth2AppsSettingsPageView: FC<OAuth2AppsSettingsProps> = ({
{apps?.length === 0 && (
<TableRow>
<TableCell colSpan={999}>
<div css={{ textAlign: "center" }}>
<div className="text-center">
No OAuth2 applications have been configured.
</div>
</TableCell>
@@ -113,7 +113,7 @@ const OAuth2AppRow: FC<OAuth2AppRowProps> = ({ app }) => {
</TableCell>
<TableCell>
<div css={{ display: "flex", paddingLeft: 16 }}>
<div className="flex pl-4">
<ChevronRightIcon className="size-icon-sm" />
</div>
</TableCell>
@@ -58,7 +58,7 @@ export const OptionValue: FC<OptionValueProps> = (props) => {
if (typeof value === "object" && !Array.isArray(value)) {
return (
<ul css={{ listStyle: "none" }} className="option-array">
<ul className="option-array list-none">
{Object.entries(value)
.sort((a, b) => a[0].localeCompare(b[0]))
.map(([option, isEnabled]) => (
@@ -75,12 +75,7 @@ export const OptionValue: FC<OptionValueProps> = (props) => {
isEnabled ? "option-enabled" : "option-disabled"
}`}
>
<div
css={{
display: "inline-flex",
alignItems: "center",
}}
>
<div className="inline-flex items-center">
{isEnabled && <WrenchIcon className="size-4 mx-2" />}
{option}
</div>
@@ -92,7 +87,7 @@ export const OptionValue: FC<OptionValueProps> = (props) => {
if (Array.isArray(value)) {
return (
<ul css={{ listStylePosition: "inside" }} className="option-array">
<ul className="option-array list-inside">
{value.map((item) => (
<li key={item} css={styles.option}>
{item}
@@ -83,7 +83,7 @@ const ExternalAuthPage: FC = () => {
<SignInLayout>
<Welcome>Failed to validate oauth access token</Welcome>
<p css={{ textAlign: "center" }}>
<p className="text-center">
Attempted to validate the user&apos;s oauth access token from the
authentication flow. This situation may occur as a result of an
external authentication provider misconfiguration. Verify the
@@ -216,7 +216,7 @@ const GroupMemberRow: FC<GroupMemberRowProps> = ({
css={[styles.status, member.status === "suspended" && styles.suspended]}
>
<div>{member.status}</div>
<LastSeen at={member.last_seen_at} css={{ fontSize: 12 }} />
<LastSeen at={member.last_seen_at} className="text-xs" />
</TableCell>
<TableCell width="1%">
{canUpdate && (
+1 -1
View File
@@ -167,7 +167,7 @@ const TableLoader: FC = () => {
<TableLoaderSkeleton>
<TableRowSkeleton>
<TableCell>
<div css={{ display: "flex", alignItems: "center", gap: 8 }}>
<div className="flex items-center gap-2">
<AvatarDataSkeleton />
</div>
</TableCell>
+11 -41
View File
@@ -22,12 +22,8 @@ const CONTENT_PADDING = 36;
export const Header: FC<HTMLAttributes<HTMLDivElement>> = (props) => {
return (
<header
css={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
padding: `36px ${CONTENT_PADDING}px`,
}}
className="flex items-center justify-between"
style={{ padding: `36px ${CONTENT_PADDING}px` }}
{...props}
/>
);
@@ -36,15 +32,7 @@ export const Header: FC<HTMLAttributes<HTMLDivElement>> = (props) => {
export const HeaderTitle: FC<HTMLAttributes<HTMLDivElement>> = (props) => {
return (
<h2
css={{
margin: 0,
lineHeight: "1.2",
fontSize: 20,
fontWeight: 500,
display: "flex",
alignItems: "center",
gap: 16,
}}
className="m-0 leading-[1.2] text-xl font-medium flex items-center gap-4"
{...props}
/>
);
@@ -85,12 +73,8 @@ export const HealthyDot: FC<HealthyDotProps> = ({ severity }) => {
export const Main: FC<HTMLAttributes<HTMLDivElement>> = (props) => {
return (
<div
css={{
padding: `0 ${CONTENT_PADDING}px ${CONTENT_PADDING}px`,
display: "flex",
flexDirection: "column",
gap: 36,
}}
className="flex flex-col gap-9"
style={{ padding: `0 ${CONTENT_PADDING}px ${CONTENT_PADDING}px` }}
{...props}
/>
);
@@ -99,15 +83,10 @@ export const Main: FC<HTMLAttributes<HTMLDivElement>> = (props) => {
export const GridData: FC<HTMLAttributes<HTMLDivElement>> = (props) => {
return (
<div
css={{
lineHeight: "1.4",
display: "grid",
gridTemplateColumns: "auto auto",
gap: 12,
columnGap: 48,
width: "min-content",
whiteSpace: "nowrap",
}}
className={`
leading-[1.4] w-min whitespace-nowrap
grid grid-cols-[auto_auto] gap-3 gap-x-12
`}
{...props}
/>
);
@@ -142,16 +121,7 @@ export const GridDataValue: FC<HTMLAttributes<HTMLSpanElement>> = (props) => {
export const SectionLabel: FC<HTMLAttributes<HTMLHeadingElement>> = (props) => {
return (
<h4
{...props}
css={{
fontSize: 14,
fontWeight: 500,
margin: 0,
lineHeight: "1.2",
marginBottom: 16,
}}
/>
<h4 {...props} className="text-sm font-medium m-0 leading-[1.2] mb-4" />
);
};
@@ -247,7 +217,7 @@ export const Logs: FC<LogsProps> = ({ lines, ...divProps }) => {
{...divProps}
>
{lines.map((line, index) => (
<span css={{ display: "block" }} key={index}>
<span className="block" key={index}>
{line}
</span>
))}
@@ -23,7 +23,7 @@ export const DismissWarningButton = (props: { healthcheck: HealthSection }) => {
variant="rectangular"
height={36}
width={170}
css={{ borderRadius: 8 }}
className="rounded-lg"
/>
);
}
@@ -76,42 +76,24 @@ const WorkspaceProxyPage: FC = () => {
fontSize: 14,
}}
>
<header
css={{
padding: 24,
display: "flex",
alignItems: "center",
justifyContent: "space-between",
gap: 24,
}}
>
<div css={{ display: "flex", alignItems: "center", gap: 24 }}>
<div
css={{
width: 36,
height: 36,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<header className="p-6 flex items-center justify-between gap-6">
<div className="flex items-center gap-6">
<div className="w-9 h-9 flex items-center justify-center">
<img
src={region.icon_url}
css={{ objectFit: "fill", width: "100%", height: "100%" }}
className="object-fill w-full h-full"
alt=""
/>
</div>
<div css={{ lineHeight: "160%" }}>
<h4 css={{ fontWeight: 500, margin: 0 }}>
{region.display_name}
</h4>
<div className="leading-[160%]">
<h4 className="font-medium m-0">{region.display_name}</h4>
<span css={{ color: theme.palette.text.secondary }}>
{region.version}
</span>
</div>
</div>
<div css={{ display: "flex", flexWrap: "wrap", gap: 12 }}>
<div className="flex flex-wrap gap-3">
{region.wildcard_hostname && (
<Tooltip>
<TooltipTrigger asChild>
@@ -166,14 +148,9 @@ const WorkspaceProxyPage: FC = () => {
) : warnings.length === 0 && errors.length === 0 ? (
<span>OK</span>
) : (
<div css={{ display: "flex", flexDirection: "column" }}>
<div className="flex flex-col">
{[...errors, ...warnings].map((msg) => (
<span
key={msg}
css={{
":first-letter": { textTransform: "uppercase" },
}}
>
<span key={msg} className="[&::first-letter]:uppercase">
{msg}
</span>
))}
+1 -10
View File
@@ -172,16 +172,7 @@ const IconsPage: FC = () => {
),
]}
/>
<figcaption
css={{
width: 88,
height: 48,
fontSize: 13,
textOverflow: "ellipsis",
textAlign: "center",
overflow: "hidden",
}}
>
<figcaption className="w-[88px] h-12 text-[13px] text-ellipsis text-center overflow-hidden">
{icon.description}
</figcaption>
</div>
+1 -1
View File
@@ -17,7 +17,7 @@ export const OAuthSignInForm: FC<OAuthSignInFormProps> = ({
authMethods,
}) => {
return (
<div css={{ display: "grid", gap: "16px" }}>
<div className="grid gap-4">
{authMethods?.github.enabled && (
<Button
variant="outline"
@@ -75,7 +75,7 @@ export const CreateOrganizationPageView: FC<
<div className="flex flex-col gap-4 w-full min-w-96 mx-auto">
<div className="flex flex-col items-center">
{Boolean(error) && !isApiValidationError(error) && (
<div css={{ marginBottom: 32 }}>
<div className="mb-8">
<ErrorAlert error={error} />
</div>
)}
@@ -95,7 +95,7 @@ export const OrganizationSettingsPageView: FC<
</SettingsHeader>
{Boolean(error) && !isApiValidationError(error) && (
<div css={{ marginBottom: 32 }}>
<div className="mb-8">
<ErrorAlert error={error} />
</div>
)}
@@ -110,7 +110,7 @@ export const OrganizationSettingsPageView: FC<
>
<fieldset
disabled={form.isSubmitting}
css={{ border: "unset", padding: 0, margin: 0, width: "100%" }}
className="border-0 p-0 m-0 w-full"
>
<FormFields>
<TextField
+7 -24
View File
@@ -142,15 +142,9 @@ export const SetupPageView: FC<SetupPageViewProps> = ({
return (
<SignInLayout>
<header css={{ textAlign: "center", marginBottom: 32 }}>
<header className="text-center mb-8">
<CoderIcon className="w-12 h-12" />
<h1
css={{
fontWeight: 400,
margin: 0,
marginTop: 16,
}}
>
<h1 className="font-normal m-0 mt-4">
Welcome to <strong>Coder</strong>
</h1>
<div
@@ -201,14 +195,7 @@ export const SetupPageView: FC<SetupPageViewProps> = ({
/>
<label
htmlFor="trial"
css={{
display: "flex",
cursor: "pointer",
alignItems: "flex-start",
gap: 4,
marginTop: -4,
marginBottom: 8,
}}
className="flex cursor-pointer items-start gap-1 -mt-1 mb-2"
>
<Checkbox
id="trial"
@@ -219,8 +206,8 @@ export const SetupPageView: FC<SetupPageViewProps> = ({
size="small"
/>
<div css={{ fontSize: 14, paddingTop: 4 }}>
<span css={{ display: "block", fontWeight: 600 }}>
<div className="text-sm pt-1">
<span className="block font-semibold">
Start a free trial of Enterprise
</span>
<span
@@ -237,7 +224,7 @@ export const SetupPageView: FC<SetupPageViewProps> = ({
<Link
href="https://coder.com/pricing"
target="_blank"
css={{ marginTop: 4, display: "inline-block", fontSize: 13 }}
className="mt-1 inline-block text-[13px]"
>
Read more
</Link>
@@ -293,11 +280,7 @@ export const SetupPageView: FC<SetupPageViewProps> = ({
onChange={(_, newValue) =>
form.setFieldValue("trial_info.country", newValue?.name)
}
css={{
"&:not(:has(label))": {
margin: 0,
},
}}
className="[&:not(:has(label))]:m-0"
renderInput={(params) => (
<TextField
{...params}
@@ -60,19 +60,7 @@ export const StarterTemplatePageView: FC<StarterTemplatePageViewProps> = ({
}
>
<Stack direction="row" spacing={3} alignItems="center">
<div
css={{
height: 48,
width: 48,
display: "flex",
alignItems: "center",
justifyContent: "center",
"& img": {
width: "100%",
},
}}
>
<div className="h-12 w-12 flex items-center justify-center [&_img]:w-full">
<ExternalImage src={starterTemplate.icon} />
</div>
<div>
@@ -92,13 +80,7 @@ export const StarterTemplatePageView: FC<StarterTemplatePageViewProps> = ({
}}
id="readme"
>
<div
css={{
padding: "40px 40px 64px",
maxWidth: 800,
margin: "auto",
}}
>
<div className="px-10 pt-10 pb-16 max-w-[800px] mx-auto">
<MemoizedMarkdown>{starterTemplate.markdown}</MemoizedMarkdown>
</div>
</div>
@@ -32,13 +32,7 @@ export default function TemplateDocsPage() {
>
README.md
</div>
<div
css={{
padding: "0 24px 40px",
maxWidth: 800,
margin: "auto",
}}
>
<div className="px-6 pb-10 max-w-[800px] mx-auto">
<MemoizedMarkdown>{readme.body}</MemoizedMarkdown>
</div>
</div>
@@ -174,9 +174,7 @@ export const TemplateEmbedPageView: FC<TemplateEmbedPageViewProps> = ({
</div>
{templateParameters.length > 0 && (
<div
css={{ display: "flex", flexDirection: "column", gap: 36 }}
>
<div className="flex flex-col gap-9">
{templateParameters.map((parameter) => {
const parameterValue =
buttonValues[`param.${parameter.name}`] ?? "";
@@ -218,17 +216,7 @@ export const TemplateEmbedPageView: FC<TemplateEmbedPageViewProps> = ({
})}
>
<img src="/open-in-coder.svg" alt="Open in Coder button" />
<div
css={{
padding: "48px 16px",
position: "absolute",
bottom: 0,
left: 0,
display: "flex",
justifyContent: "center",
width: "100%",
}}
>
<div className="px-4 py-12 absolute bottom-0 left-0 flex justify-center w-full">
<Button
className="rounded-full"
disabled={clipboard.showCopiedSuccess}
@@ -74,7 +74,7 @@ export const VersionsTable: FC<VersionsTableProps> = ({
{versions && versions.length === 0 && (
<TableRow>
<TableCell colSpan={999}>
<div css={{ padding: 32 }}>
<div className="p-8">
<EmptyState message={Language.emptyMessage} />
</div>
</TableCell>
@@ -221,7 +221,7 @@ export const TemplateSettingsForm: FC<TemplateSettingsForm> = ({
direction="row"
spacing={2}
alignItems="center"
css={{ marginTop: 16 }}
className="mt-4"
>
<PremiumBadge />
<span>Premium license required to be enabled.</span>
@@ -33,7 +33,7 @@ export const TemplateSettingsPageView: FC<TemplateSettingsPageViewProps> = ({
}) => {
return (
<>
<PageHeader css={{ paddingTop: 0 }}>
<PageHeader className="pt-0">
<PageHeaderTitle>General Settings</PageHeaderTitle>
</PageHeader>
@@ -79,7 +79,7 @@ export const ScheduleDialog: FC<ScheduleDialogProps> = ({
inactivity period for all template workspaces?
</p>
<FormControlLabel
css={{ marginTop: 16 }}
className="mt-4"
control={
<Checkbox
size="small"
@@ -109,7 +109,7 @@ export const ScheduleDialog: FC<ScheduleDialogProps> = ({
dormancy period for all template workspaces?
</p>
<FormControlLabel
css={{ marginTop: 16 }}
className="mt-4"
control={
<Checkbox
size="small"
@@ -29,7 +29,7 @@ export const TemplateSchedulePageView: FC<TemplateSchedulePageViewProps> = ({
}) => {
return (
<>
<PageHeader css={{ paddingTop: 0 }}>
<PageHeader className="pt-0">
<PageHeaderTitle>Template schedule</PageHeaderTitle>
</PageHeader>
@@ -54,7 +54,7 @@ export const TemplateSettingsLayout: FC = () => {
<title>{pageTitle(templateName, "Settings")}</title>
<Margins>
<Stack css={{ padding: "48px 0" }} direction="row" spacing={10}>
<Stack className="py-12" direction="row" spacing={10}>
{templateQuery.isError || permissionsQuery.isError ? (
<ErrorAlert error={templateQuery.error} />
) : (
@@ -47,11 +47,11 @@ export const TemplateVariablesPageView: FC<TemplateVariablesPageViewProps> = ({
return (
<>
<PageHeader css={{ paddingTop: 0 }}>
<PageHeader className="pt-0">
<PageHeaderTitle>Template variables</PageHeaderTitle>
</PageHeader>
{hasError && (
<Stack css={{ marginBottom: 64 }}>
<Stack className="mb-16">
{Boolean(errors.buildError) && (
<ErrorAlert error={errors.buildError} />
)}
@@ -78,7 +78,7 @@ export const EmptyTemplates: FC<EmptyTemplatesProps> = ({
))}
</div>
<Button size="sm" asChild css={{ borderRadius: 9999 }}>
<Button size="sm" asChild className="rounded-full">
<RouterLink to="/starter-templates">
View all starter templates
</RouterLink>
@@ -303,7 +303,7 @@ const TableLoader: FC = () => {
<TableLoaderSkeleton>
<TableRowSkeleton>
<TableCell>
<div css={{ display: "flex", alignItems: "center", gap: 8 }}>
<div className="flex items-center gap-2">
<AvatarDataSkeleton />
</div>
</TableCell>
+1 -4
View File
@@ -418,10 +418,7 @@ const TerminalPage: FC = () => {
</title>
)}
<div
css={{ display: "flex", flexDirection: "column", height: "100vh" }}
data-status={connectionStatus}
>
<div className="flex flex-col h-screen" data-status={connectionStatus}>
<TerminalAlerts
agent={workspaceAgent}
status={connectionStatus}
@@ -162,7 +162,7 @@ const ExternalAuthRow: FC<ExternalAuthRowProps> = ({
)}
</Stack>
</TableCell>
<TableCell css={{ textAlign: "right" }}>
<TableCell className="text-right">
<Button
disabled={authenticated || externalAuthPollingState === "polling"}
onClick={() => {
@@ -46,7 +46,7 @@ const OAuth2ProviderPageView: FC<OAuth2ProviderPageViewProps> = ({
{apps?.length === 0 && (
<TableRow>
<TableCell colSpan={999}>
<div css={{ textAlign: "center" }}>
<div className="text-center">
No OAuth2 applications have been authorized.
</div>
</TableCell>
@@ -24,7 +24,7 @@ export const SSHKeysPageView: FC<SSHKeysPageViewProps> = ({
if (isLoading) {
return (
<div css={{ padding: 32 }}>
<div className="p-8">
<CircularProgress size={26} />
</div>
);
+4 -13
View File
@@ -34,27 +34,18 @@ export const Section: FC<SectionProps> = ({
}) => {
return (
<section className={className} id={id} data-testid={id}>
<div css={{ maxWidth: layout === "fluid" ? "100%" : 500 }}>
<div className={layout === "fluid" ? "max-w-full" : "max-w-[500px]"}>
{(title || description) && (
<div css={styles.header}>
<div>
{title && (
<Stack direction="row" alignItems="center">
<h4
css={{
fontSize: 24,
fontWeight: 500,
margin: 0,
marginBottom: 8,
}}
>
{title}
</h4>
<h4 className="text-2xl font-medium m-0 mb-2">{title}</h4>
{featureStage && (
<FeatureStageBadge
contentType={featureStage}
size="md"
css={{ marginBottom: "5px" }}
className="mb-[5px]"
/>
)}
</Stack>
@@ -69,7 +60,7 @@ export const Section: FC<SectionProps> = ({
{toolbar && <div>{toolbar}</div>}
</div>
)}
{alert && <div css={{ marginBottom: 8 }}>{alert}</div>}
{alert && <div className="mb-2">{alert}</div>}
{children}
</div>
</section>
@@ -65,7 +65,7 @@ const TokensPage: FC = () => {
};
const TokenActions: FC = () => (
<Stack direction="row" justifyContent="end" css={{ marginBottom: 8 }}>
<Stack direction="row" justifyContent="end" className="mb-2">
<Button asChild variant="outline">
<RouterLink to="new">
<PlusIcon />
@@ -36,12 +36,7 @@ export const ResetPasswordDialog: FC<ResetPasswordDialogProps> = ({
<CodeExample
secret={false}
code={newPassword ?? ""}
css={{
minHeight: "auto",
userSelect: "all",
width: "100%",
marginTop: 24,
}}
className="min-h-auto select-all w-full mt-6"
/>
</>
);
@@ -25,23 +25,13 @@ export const UserGroupsCell: FC<GroupsCellProps> = ({ userGroups }) => {
return (
<TableCell>
{userGroups === undefined ? (
// Felt right to add emphasis to the undefined state for semantics
// ("hey, this isn't normal"), but the default italics looked weird in
// the table UI
<em css={{ fontStyle: "normal" }}>N/A</em>
<span>No groups</span>
) : (
<TooltipProvider>
<Tooltip delayDuration={0}>
<TooltipTrigger asChild>
<button
css={{
cursor: "pointer",
backgroundColor: "transparent",
border: "none",
padding: 0,
color: "inherit",
lineHeight: "1",
}}
className="cursor-pointer bg-transparent border-0 p-0 text-inherit leading-none"
type="button"
>
<div className="flex flex-row gap-2 items-center">
@@ -63,12 +53,9 @@ export const UserGroupsCell: FC<GroupsCellProps> = ({ userGroups }) => {
<OverflowY maxHeight={400}>
<List
component="ul"
css={{
display: "flex",
flexFlow: "column nowrap",
className="flex flex-col flex-nowrap gap-0 px-0.5 py-1"
style={{
fontSize: theme.typography.body2.fontSize,
padding: "4px 2px",
gap: 0,
}}
>
{userGroups.map((group) => {
@@ -76,10 +63,7 @@ export const UserGroupsCell: FC<GroupsCellProps> = ({ userGroups }) => {
return (
<ListItem
key={group.id}
css={{
columnGap: 10,
alignItems: "center",
}}
className="gap-x-[10px] items-center"
>
<Avatar
size="sm"
@@ -88,15 +72,7 @@ export const UserGroupsCell: FC<GroupsCellProps> = ({ userGroups }) => {
fallback={groupName}
/>
<span
css={{
whiteSpace: "nowrap",
textOverflow: "ellipsis",
overflow: "hidden",
lineHeight: 1,
margin: 0,
}}
>
<span className="whitespace-nowrap text-ellipsis overflow-hidden leading-none m-0">
{groupName || <em>N/A</em>}
</span>
</ListItem>
@@ -136,7 +136,7 @@ export const UsersTableBody: FC<UsersTableBodyProps> = ({
<Cond condition={isNonInitialPage}>
<TableRow>
<TableCell colSpan={999}>
<div css={{ padding: 32 }}>
<div className="p-8">
<EmptyState message="No users found on this page" />
</div>
</TableCell>
@@ -146,7 +146,7 @@ export const UsersTableBody: FC<UsersTableBodyProps> = ({
<Cond>
<TableRow>
<TableCell colSpan={999}>
<div css={{ padding: 32 }}>
<div className="p-8">
<EmptyState message="No users found" />
</div>
</TableCell>
@@ -194,7 +194,7 @@ export const UsersTableBody: FC<UsersTableBodyProps> = ({
>
<div>{user.status}</div>
{(user.status === "active" || user.status === "dormant") && (
<LastSeen at={user.last_seen_at} css={{ fontSize: 12 }} />
<LastSeen at={user.last_seen_at} className="text-xs" />
)}
</TableCell>
@@ -309,7 +309,7 @@ const LoginType: FC<LoginTypeProps> = ({ authMethods, value }) => {
}
return (
<div css={{ display: "flex", alignItems: "center", gap: 8, fontSize: 14 }}>
<div className="flex items-center gap-2 text-sm">
{icon}
{displayName}
</div>
@@ -49,7 +49,7 @@ export const HistorySidebar: FC<HistorySidebarProps> = ({ workspace }) => {
</SidebarItem>
))}
{buildsQuery.hasNextPage && (
<div css={{ padding: 16 }}>
<div className="p-4">
<Button
onClick={() => buildsQuery.fetchNextPage()}
disabled={buildsQuery.isFetchingNextPage}
@@ -55,26 +55,14 @@ export const ResourcesSidebar: FC<ResourcesSidebarProps> = ({
key={r.id}
css={styles.root}
>
<div
css={{
display: "flex",
alignItems: "center",
justifyContent: "center",
lineHeight: 0,
width: 16,
height: 16,
padding: 2,
}}
>
<div className="flex items-center justify-center leading-none w-4 h-4 p-0.5">
<img
css={{ width: "100%", height: "100%", objectFit: "contain" }}
className="w-full h-full object-contain"
src={getResourceIconPath(r.type)}
alt=""
/>
</div>
<div
css={{ display: "flex", flexDirection: "column", fontWeight: 500 }}
>
<div className="flex flex-col font-medium">
<span>{r.name}</span>
<span css={{ fontSize: 12, color: theme.palette.text.secondary }}>
{r.type}
@@ -92,12 +80,7 @@ const ResourceSidebarItemSkeleton: FC = () => {
<Skeleton variant="circular" width={16} height={16} />
<div>
<Skeleton variant="text" width={94} height={16} />
<Skeleton
variant="text"
width={60}
height={14}
css={{ marginTop: 2 }}
/>
<Skeleton variant="text" width={60} height={14} className="mt-0.5" />
</div>
</div>
);
@@ -171,10 +171,7 @@ export const WorkspaceActions: FC<WorkspaceActionsProps> = ({
};
return (
<div
css={{ display: "flex", alignItems: "center", gap: 8 }}
data-testid="workspace-actions"
>
<div className="flex items-center gap-2" data-testid="workspace-actions">
{/* Restarting must be handled separately, because it otherwise would appear as stopping */}
{isUpdating
? buttonMapping.updating
@@ -36,7 +36,7 @@ export const WorkspaceBuildLogsSection: FC<WorkspaceBuildLogsSectionProps> = ({
>
Build logs
</header>
<div css={{ height: "400px", overflowY: "auto" }}>
<div className="h-[400px] overflow-y-auto">
{logs ? (
<WorkspaceBuildLogs
sticky
@@ -44,15 +44,7 @@ export const WorkspaceBuildLogsSection: FC<WorkspaceBuildLogsSectionProps> = ({
css={{ border: 0, borderRadius: 0 }}
/>
) : (
<div
css={{
display: "flex",
alignItems: "center",
justifyContent: "center",
width: "100%",
height: "100%",
}}
>
<div className="flex items-center justify-center w-full h-full">
<Loader />
</div>
)}
@@ -95,7 +95,7 @@ interface NotificationItemProps {
const NotificationItem: FC<NotificationItemProps> = ({ notification }) => {
return (
<article css={styles.notificationItem}>
<h4 css={{ margin: 0, fontWeight: 500 }}>{notification.title}</h4>
<h4 className="m-0 font-medium">{notification.title}</h4>
{notification.detail && (
<p css={styles.notificationDetail}>{notification.detail}</p>
)}
@@ -208,7 +208,7 @@ export const WorkspaceNotifications: FC<WorkspaceNotificationsProps> = ({
This workspace build job is waiting for a provisioner to become
available. If you have been waiting for an extended period of time,
please contact your administrator for assistance.
<span css={{ display: "block", marginTop: 12 }}>
<span className="block mt-3">
Position in queue:{" "}
<strong>{workspace.latest_build.job.queue_position}</strong>
</span>
@@ -108,7 +108,7 @@ const WorkspacePage: FC = () => {
return pageError ? (
<Margins>
<ErrorAlert error={pageError} css={{ marginTop: 16, marginBottom: 16 }} />
<ErrorAlert error={pageError} className="my-4" />
</Margins>
) : isLoading ? (
<Loader />
@@ -275,12 +275,7 @@ const ScheduleSettingsLink: React.FC<LinkProps> = ({ ...props }) => {
<Link
component={RouterLink}
to="settings/schedule"
css={{
color: "inherit",
"&:first-letter": {
textTransform: "uppercase",
},
}}
className="text-inherit [&::first-letter]:uppercase"
{...props}
/>
);
@@ -1,4 +1,4 @@
import { type Interpolation, type Theme, useTheme } from "@emotion/react";
import type { Interpolation, Theme } from "@emotion/react";
import Link from "@mui/material/Link";
import { ChevronLeftIcon, CircleDollarSign, TrashIcon } from "lucide-react";
import type { FC } from "react";
@@ -74,7 +74,6 @@ export const WorkspaceTopbar: FC<WorkspaceProps> = ({
}) => {
const { entitlements, organizations, showOrganizations } = useDashboard();
const getLink = useLinks();
const theme = useTheme();
// Quota
const hasDailyCost = workspace.latest_build.daily_cost > 0;
@@ -112,7 +111,7 @@ export const WorkspaceTopbar: FC<WorkspaceProps> = ({
);
return (
<Topbar css={{ gridArea: "topbar" }}>
<Topbar className="[grid-area:topbar]">
<Tooltip>
<TooltipTrigger asChild>
<TopbarIconButton component={RouterLink} to="/workspaces">
@@ -159,7 +158,7 @@ export const WorkspaceTopbar: FC<WorkspaceProps> = ({
{quota && quota.budget > 0 && (
<Link
component={RouterLink}
css={{ color: "inherit" }}
className="text-inherit"
to={
showOrganizations
? `/workspaces?filter=organization:${encodeURIComponent(workspace.organization_name)}`
@@ -181,9 +180,7 @@ export const WorkspaceTopbar: FC<WorkspaceProps> = ({
<span>
{workspace.latest_build.daily_cost}{" "}
<span css={{ color: theme.palette.text.secondary }}>
credits of
</span>{" "}
<span className="text-content-secondary">credits of</span>{" "}
{quota.budget}
</span>
</TopbarData>
@@ -199,7 +196,7 @@ export const WorkspaceTopbar: FC<WorkspaceProps> = ({
component={RouterLink}
to={`${templateLink}/settings/schedule`}
title="Schedule settings"
css={{ color: "inherit" }}
className="text-inherit"
>
{workspace.deleting_at ? (
<>Deletion on {formatDate(new Date(workspace.deleting_at))}</>
@@ -309,7 +306,7 @@ const OrganizationBreadcrumb: FC<OrganizationBreadcrumbProps> = ({
<Link
component={RouterLink}
to={orgPageUrl}
css={{ color: "inherit" }}
className="text-inherit"
>
{orgName}
</Link>
@@ -374,7 +371,7 @@ const WorkspaceBreadcrumb: FC<WorkspaceBreadcrumbProps> = ({
<Link
component={RouterLink}
to={rootTemplateUrl}
css={{ color: "inherit" }}
className="text-inherit"
>
{templateDisplayName}
</Link>
@@ -383,7 +380,7 @@ const WorkspaceBreadcrumb: FC<WorkspaceBreadcrumbProps> = ({
<Link
component={RouterLink}
to={`${rootTemplateUrl}/versions/${encodeURIComponent(templateVersionName)}`}
css={{ color: "inherit" }}
className="text-inherit"
>
Version: {latestBuildVersionName}
</Link>
@@ -151,7 +151,7 @@ export const WorkspaceParametersPageView: FC<
</header>
{submitError && !isApiValidationError(submitError) ? (
<ErrorAlert error={submitError} css={{ marginBottom: 48 }} />
<ErrorAlert error={submitError} className="mb-12" />
) : null}
{templateVersionParameters && buildParameters ? (
@@ -74,7 +74,7 @@ const WorkspaceSchedulePage: FC = () => {
<>
<title>{pageTitle(workspaceName, "Schedule")}</title>
<PageHeader css={{ paddingTop: 0 }}>
<PageHeader className="pt-0">
<PageHeaderTitle>Workspace Schedule</PageHeaderTitle>
</PageHeader>
@@ -37,7 +37,7 @@ export const WorkspaceSettingsLayout: FC = () => {
<title>{pageTitle(workspaceName, "Settings")}</title>
<Margins>
<Stack css={{ padding: "48px 0" }} direction="row" spacing={10}>
<Stack className="py-12" direction="row" spacing={10}>
{error ? (
<ErrorAlert error={error} />
) : (
@@ -21,11 +21,7 @@ export const WorkspaceSettingsPageView: FC<WorkspaceSettingsPageViewProps> = ({
}) => {
return (
<>
<PageHeader
css={{
paddingTop: 0,
}}
>
<PageHeader className="pt-0">
<PageHeaderTitle>Workspace Settings</PageHeaderTitle>
</PageHeader>
@@ -67,21 +67,13 @@ export const WorkspacesButton: FC<WorkspacesButtonProps> = ({
>
<MenuSearch
value={searchTerm}
autoFocus={true}
autoFocus
onChange={setSearchTerm}
placeholder="Type/select a workspace template"
aria-label="Template select for workspace"
/>
<OverflowY
maxHeight={380}
css={{
display: "flex",
flexDirection: "column",
paddingTop: "8px",
paddingBottom: "8px",
}}
>
<OverflowY maxHeight={380} className="flex flex-col py-2">
{templatesFetchStatus === "pending" ? (
<Loader size="sm" />
) : (
@@ -132,11 +124,7 @@ const WorkspaceResultsRow: FC<WorkspaceResultsRowProps> = ({ template }) => {
return (
<PopoverLink
to={`${templateLink}/workspace`}
css={{
display: "flex",
gap: 12,
alignItems: "center",
}}
className="flex gap-3 items-center"
>
<Avatar
variant="icon"
@@ -154,7 +142,7 @@ const WorkspaceResultsRow: FC<WorkspaceResultsRowProps> = ({ template }) => {
overflow: "hidden",
})}
>
<span css={{ whiteSpace: "nowrap", textOverflow: "ellipsis" }}>
<span className="whitespace-nowrap text-ellipsis">
{template.display_name || template.name || "[Unnamed]"}
</span>
<span
@@ -240,7 +240,7 @@ export const WorkspacesPageView: FC<WorkspacesPageViewProps> = ({
// Temporary styling stopgap before component is migrated to using
// PaginationContainer (which renders PaginationWidgetBase using CSS
// flexbox gaps)
<div css={{ paddingTop: "16px" }}>
<div className="pt-4">
<PaginationWidgetBase
totalRecords={count}
pageSize={limit}