mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
chore: migrate some emotion styles to tailwind (#23817)
This commit is contained in:
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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=""
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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,
|
||||
])}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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'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"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
+1
-1
@@ -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}
|
||||
|
||||
+2
-7
@@ -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>
|
||||
|
||||
+1
-1
@@ -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} />
|
||||
|
||||
+2
-7
@@ -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>
|
||||
|
||||
+2
-2
@@ -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'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 && (
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
))}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
+1
-1
@@ -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>
|
||||
|
||||
+1
-1
@@ -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"
|
||||
|
||||
+1
-1
@@ -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} />
|
||||
) : (
|
||||
|
||||
+2
-2
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
|
||||
+1
-1
@@ -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 ? (
|
||||
|
||||
+1
-1
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user