mirror of
https://github.com/coder/coder.git
synced 2026-09-22 05:05:20 +08:00
refactor(site): Update workspace header (#7433)
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import { FC, PropsWithChildren } from "react"
|
||||
|
||||
export const FullWidthPageHeader: FC<PropsWithChildren> = ({ children }) => {
|
||||
const styles = useStyles()
|
||||
|
||||
return (
|
||||
<header className={styles.header} data-testid="header">
|
||||
{children}
|
||||
</header>
|
||||
)
|
||||
}
|
||||
|
||||
export const PageHeaderActions: FC<PropsWithChildren> = ({ children }) => {
|
||||
const styles = useStyles()
|
||||
return <div className={styles.actions}>{children}</div>
|
||||
}
|
||||
|
||||
export const PageHeaderTitle: FC<PropsWithChildren> = ({ children }) => {
|
||||
const styles = useStyles()
|
||||
return <h1 className={styles.title}>{children}</h1>
|
||||
}
|
||||
|
||||
export const PageHeaderSubtitle: FC<PropsWithChildren> = ({ children }) => {
|
||||
const styles = useStyles()
|
||||
return <span className={styles.subtitle}>{children}</span>
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
header: {
|
||||
padding: theme.spacing(3),
|
||||
background: theme.palette.background.paper,
|
||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: theme.spacing(6),
|
||||
position: "sticky",
|
||||
top: 0,
|
||||
zIndex: 10,
|
||||
flexWrap: "wrap",
|
||||
|
||||
[theme.breakpoints.down("md")]: {
|
||||
position: "unset",
|
||||
alignItems: "flex-start",
|
||||
},
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
flexDirection: "column",
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
marginLeft: "auto",
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
marginLeft: "unset",
|
||||
},
|
||||
},
|
||||
title: {
|
||||
fontSize: 18,
|
||||
fontWeight: 500,
|
||||
margin: 0,
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 14,
|
||||
color: theme.palette.text.secondary,
|
||||
marginTop: theme.spacing(0.25),
|
||||
display: "block",
|
||||
},
|
||||
}))
|
||||
@@ -1,19 +1,30 @@
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import { ComponentProps, FC, PropsWithChildren } from "react"
|
||||
import { combineClasses } from "utils/combineClasses"
|
||||
|
||||
export const Stats: FC<PropsWithChildren<ComponentProps<"div">>> = (props) => {
|
||||
export const Stats: FC<ComponentProps<"div">> = (props) => {
|
||||
const styles = useStyles()
|
||||
return <div className={styles.stats} {...props} />
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={combineClasses([styles.stats, props.className])}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export const StatsItem: FC<{
|
||||
label: string
|
||||
value: string | number | JSX.Element
|
||||
}> = ({ label, value }) => {
|
||||
export const StatsItem: FC<
|
||||
{
|
||||
label: string
|
||||
value: string | number | JSX.Element
|
||||
} & ComponentProps<"div">
|
||||
> = ({ label, value, ...divProps }) => {
|
||||
const styles = useStyles()
|
||||
|
||||
return (
|
||||
<div className={styles.statItem}>
|
||||
<div
|
||||
{...divProps}
|
||||
className={combineClasses([styles.statItem, divProps.className])}
|
||||
>
|
||||
<span className={styles.statsLabel}>{label}:</span>
|
||||
<span className={styles.statsValue}>{value}</span>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
ActiveTransition,
|
||||
WorkspaceBuildProgress,
|
||||
} from "components/WorkspaceBuildProgress/WorkspaceBuildProgress"
|
||||
import { WorkspaceStatusBadge } from "components/WorkspaceStatusBadge/WorkspaceStatusBadge"
|
||||
import { FC } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
@@ -16,16 +15,17 @@ import * as TypesGen from "../../api/typesGenerated"
|
||||
import { AlertBanner } from "../AlertBanner/AlertBanner"
|
||||
import { BuildsTable } from "../BuildsTable/BuildsTable"
|
||||
import { Margins } from "../Margins/Margins"
|
||||
import {
|
||||
PageHeader,
|
||||
PageHeaderSubtitle,
|
||||
PageHeaderTitle,
|
||||
} from "../PageHeader/PageHeader"
|
||||
import { Resources } from "../Resources/Resources"
|
||||
import { Stack } from "../Stack/Stack"
|
||||
import { WorkspaceActions } from "../WorkspaceActions/WorkspaceActions"
|
||||
import { WorkspaceDeletedBanner } from "../WorkspaceDeletedBanner/WorkspaceDeletedBanner"
|
||||
import { WorkspaceStats } from "../WorkspaceStats/WorkspaceStats"
|
||||
import {
|
||||
FullWidthPageHeader,
|
||||
PageHeaderActions,
|
||||
PageHeaderTitle,
|
||||
PageHeaderSubtitle,
|
||||
} from "components/PageHeader/FullWidthPageHeader"
|
||||
|
||||
export enum WorkspaceErrors {
|
||||
GET_BUILDS_ERROR = "getBuildsError",
|
||||
@@ -125,31 +125,11 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
|
||||
transitionStats = ActiveTransition(template, workspace)
|
||||
}
|
||||
return (
|
||||
<Margins>
|
||||
<PageHeader
|
||||
actions={
|
||||
<Stack direction="row" spacing={1} className={styles.actions}>
|
||||
<WorkspaceActions
|
||||
workspaceStatus={workspace.latest_build.status}
|
||||
isOutdated={workspace.outdated}
|
||||
handleStart={handleStart}
|
||||
handleStop={handleStop}
|
||||
handleRestart={handleRestart}
|
||||
handleDelete={handleDelete}
|
||||
handleUpdate={handleUpdate}
|
||||
handleCancel={handleCancel}
|
||||
handleSettings={handleSettings}
|
||||
handleChangeVersion={handleChangeVersion}
|
||||
canChangeVersions={canChangeVersions}
|
||||
isUpdating={isUpdating}
|
||||
isRestarting={isRestarting}
|
||||
/>
|
||||
</Stack>
|
||||
}
|
||||
>
|
||||
<>
|
||||
<FullWidthPageHeader>
|
||||
<Stack direction="row" spacing={3} alignItems="center">
|
||||
<Avatar
|
||||
size="xl"
|
||||
size="md"
|
||||
src={workspace.template_icon}
|
||||
variant={workspace.template_icon ? "square" : undefined}
|
||||
fitImage={Boolean(workspace.template_icon)}
|
||||
@@ -157,32 +137,10 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
|
||||
{workspace.name}
|
||||
</Avatar>
|
||||
<div>
|
||||
<PageHeaderTitle>
|
||||
{workspace.name}
|
||||
<WorkspaceStatusBadge
|
||||
build={workspace.latest_build}
|
||||
className={styles.statusBadge}
|
||||
/>
|
||||
</PageHeaderTitle>
|
||||
<PageHeaderSubtitle condensed>
|
||||
{workspace.owner_name}
|
||||
</PageHeaderSubtitle>
|
||||
<PageHeaderTitle>{workspace.name}</PageHeaderTitle>
|
||||
<PageHeaderSubtitle>{workspace.owner_name}</PageHeaderSubtitle>
|
||||
</div>
|
||||
</Stack>
|
||||
</PageHeader>
|
||||
|
||||
<Stack
|
||||
direction="column"
|
||||
className={styles.firstColumnSpacer}
|
||||
spacing={4}
|
||||
>
|
||||
{buildError}
|
||||
{cancellationError}
|
||||
|
||||
<WorkspaceDeletedBanner
|
||||
workspace={workspace}
|
||||
handleClick={() => navigate(`/templates`)}
|
||||
/>
|
||||
|
||||
<WorkspaceStats
|
||||
workspace={workspace}
|
||||
@@ -195,76 +153,110 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
|
||||
onDeadlinePlus={scheduleProps.onDeadlinePlus}
|
||||
/>
|
||||
|
||||
{failedBuildLogs && (
|
||||
<Stack>
|
||||
<AlertBanner severity="error">
|
||||
<Stack
|
||||
className={styles.fullWidth}
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Stack spacing={0}>
|
||||
<span>Workspace build failed</span>
|
||||
<span className={styles.errorDetails}>
|
||||
{workspace.latest_build.job.error}
|
||||
</span>
|
||||
</Stack>
|
||||
<PageHeaderActions>
|
||||
<WorkspaceActions
|
||||
workspaceStatus={workspace.latest_build.status}
|
||||
isOutdated={workspace.outdated}
|
||||
handleStart={handleStart}
|
||||
handleStop={handleStop}
|
||||
handleRestart={handleRestart}
|
||||
handleDelete={handleDelete}
|
||||
handleUpdate={handleUpdate}
|
||||
handleCancel={handleCancel}
|
||||
handleSettings={handleSettings}
|
||||
handleChangeVersion={handleChangeVersion}
|
||||
canChangeVersions={canChangeVersions}
|
||||
isUpdating={isUpdating}
|
||||
isRestarting={isRestarting}
|
||||
/>
|
||||
</PageHeaderActions>
|
||||
</FullWidthPageHeader>
|
||||
|
||||
{canUpdateTemplate && (
|
||||
<div>
|
||||
<Button
|
||||
onClick={handleBuildRetry}
|
||||
startIcon={<RefreshOutlined />}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
>
|
||||
{t("actionButton.retryDebugMode")}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</Stack>
|
||||
</AlertBanner>
|
||||
<WorkspaceBuildLogs logs={failedBuildLogs} />
|
||||
</Stack>
|
||||
)}
|
||||
<Margins className={styles.content}>
|
||||
<Stack
|
||||
direction="column"
|
||||
className={styles.firstColumnSpacer}
|
||||
spacing={4}
|
||||
>
|
||||
{buildError}
|
||||
{cancellationError}
|
||||
|
||||
{transitionStats !== undefined && (
|
||||
<WorkspaceBuildProgress
|
||||
<WorkspaceDeletedBanner
|
||||
workspace={workspace}
|
||||
transitionStats={transitionStats}
|
||||
handleClick={() => navigate(`/templates`)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{typeof resources !== "undefined" && resources.length > 0 && (
|
||||
<Resources
|
||||
resources={resources}
|
||||
agentRow={(agent) => (
|
||||
<AgentRow
|
||||
key={agent.id}
|
||||
agent={agent}
|
||||
workspace={workspace}
|
||||
sshPrefix={sshPrefix}
|
||||
showApps={canUpdateWorkspace}
|
||||
hideSSHButton={hideSSHButton}
|
||||
hideVSCodeDesktopButton={hideVSCodeDesktopButton}
|
||||
serverVersion={serverVersion}
|
||||
onUpdateAgent={handleUpdate} // On updating the workspace the agent version is also updated
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{failedBuildLogs && (
|
||||
<Stack>
|
||||
<AlertBanner severity="error">
|
||||
<Stack
|
||||
className={styles.fullWidth}
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Stack spacing={0}>
|
||||
<span>Workspace build failed</span>
|
||||
<span className={styles.errorDetails}>
|
||||
{workspace.latest_build.job.error}
|
||||
</span>
|
||||
</Stack>
|
||||
|
||||
{workspaceErrors[WorkspaceErrors.GET_BUILDS_ERROR] ? (
|
||||
<AlertBanner
|
||||
severity="error"
|
||||
error={workspaceErrors[WorkspaceErrors.GET_BUILDS_ERROR]}
|
||||
/>
|
||||
) : (
|
||||
<BuildsTable builds={builds} />
|
||||
)}
|
||||
</Stack>
|
||||
</Margins>
|
||||
{canUpdateTemplate && (
|
||||
<div>
|
||||
<Button
|
||||
onClick={handleBuildRetry}
|
||||
startIcon={<RefreshOutlined />}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
>
|
||||
{t("actionButton.retryDebugMode")}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</Stack>
|
||||
</AlertBanner>
|
||||
<WorkspaceBuildLogs logs={failedBuildLogs} />
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{transitionStats !== undefined && (
|
||||
<WorkspaceBuildProgress
|
||||
workspace={workspace}
|
||||
transitionStats={transitionStats}
|
||||
/>
|
||||
)}
|
||||
|
||||
{typeof resources !== "undefined" && resources.length > 0 && (
|
||||
<Resources
|
||||
resources={resources}
|
||||
agentRow={(agent) => (
|
||||
<AgentRow
|
||||
key={agent.id}
|
||||
agent={agent}
|
||||
workspace={workspace}
|
||||
sshPrefix={sshPrefix}
|
||||
showApps={canUpdateWorkspace}
|
||||
hideSSHButton={hideSSHButton}
|
||||
hideVSCodeDesktopButton={hideVSCodeDesktopButton}
|
||||
serverVersion={serverVersion}
|
||||
onUpdateAgent={handleUpdate} // On updating the workspace the agent version is also updated
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{workspaceErrors[WorkspaceErrors.GET_BUILDS_ERROR] ? (
|
||||
<AlertBanner
|
||||
severity="error"
|
||||
error={workspaceErrors[WorkspaceErrors.GET_BUILDS_ERROR]}
|
||||
/>
|
||||
) : (
|
||||
<BuildsTable builds={builds} />
|
||||
)}
|
||||
</Stack>
|
||||
</Margins>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -272,6 +264,10 @@ const spacerWidth = 300
|
||||
|
||||
export const useStyles = makeStyles((theme) => {
|
||||
return {
|
||||
content: {
|
||||
marginTop: theme.spacing(4),
|
||||
},
|
||||
|
||||
statusBadge: {
|
||||
marginLeft: theme.spacing(2),
|
||||
},
|
||||
|
||||
@@ -7,7 +7,6 @@ import ReplayIcon from "@material-ui/icons/Replay"
|
||||
import { LoadingButton } from "components/LoadingButton/LoadingButton"
|
||||
import { FC, PropsWithChildren } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
|
||||
interface WorkspaceAction {
|
||||
handleAction: () => void
|
||||
@@ -17,15 +16,14 @@ export const UpdateButton: FC<PropsWithChildren<WorkspaceAction>> = ({
|
||||
handleAction,
|
||||
}) => {
|
||||
const { t } = useTranslation("workspacePage")
|
||||
const styles = useStyles()
|
||||
|
||||
return (
|
||||
<Button
|
||||
size="small"
|
||||
data-testid="workspace-update-button"
|
||||
variant="outlined"
|
||||
startIcon={<CloudQueueIcon />}
|
||||
onClick={handleAction}
|
||||
className={styles.fixedWidth}
|
||||
>
|
||||
{t("actionButton.update")}
|
||||
</Button>
|
||||
@@ -36,14 +34,12 @@ export const StartButton: FC<PropsWithChildren<WorkspaceAction>> = ({
|
||||
handleAction,
|
||||
}) => {
|
||||
const { t } = useTranslation("workspacePage")
|
||||
const styles = useStyles()
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={<PlayCircleOutlineIcon />}
|
||||
onClick={handleAction}
|
||||
className={styles.fixedWidth}
|
||||
>
|
||||
{t("actionButton.start")}
|
||||
</Button>
|
||||
@@ -54,14 +50,13 @@ export const StopButton: FC<PropsWithChildren<WorkspaceAction>> = ({
|
||||
handleAction,
|
||||
}) => {
|
||||
const { t } = useTranslation("workspacePage")
|
||||
const styles = useStyles()
|
||||
|
||||
return (
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
startIcon={<CropSquareIcon />}
|
||||
onClick={handleAction}
|
||||
className={styles.fixedWidth}
|
||||
>
|
||||
{t("actionButton.stop")}
|
||||
</Button>
|
||||
@@ -72,14 +67,13 @@ export const RestartButton: FC<PropsWithChildren<WorkspaceAction>> = ({
|
||||
handleAction,
|
||||
}) => {
|
||||
const { t } = useTranslation("workspacePage")
|
||||
const styles = useStyles()
|
||||
|
||||
return (
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
startIcon={<ReplayIcon />}
|
||||
onClick={handleAction}
|
||||
className={styles.fixedWidth}
|
||||
>
|
||||
{t("actionButton.restart")}
|
||||
</Button>
|
||||
@@ -104,7 +98,7 @@ export const DisabledButton: FC<PropsWithChildren<DisabledProps>> = ({
|
||||
label,
|
||||
}) => {
|
||||
return (
|
||||
<Button variant="outlined" disabled>
|
||||
<Button variant="outlined" size="small" disabled>
|
||||
{label}
|
||||
</Button>
|
||||
)
|
||||
@@ -117,20 +111,12 @@ interface LoadingProps {
|
||||
export const ActionLoadingButton: FC<PropsWithChildren<LoadingProps>> = ({
|
||||
label,
|
||||
}) => {
|
||||
const styles = useStyles()
|
||||
return (
|
||||
<LoadingButton
|
||||
loading
|
||||
size="small"
|
||||
variant="outlined"
|
||||
loadingLabel={label}
|
||||
className={styles.fixedWidth}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
fixedWidth: {
|
||||
// Make it fixed so the loading changes will not "flick" the UI
|
||||
width: theme.spacing(16),
|
||||
},
|
||||
}))
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import MenuItem from "@material-ui/core/MenuItem"
|
||||
import Button from "@material-ui/core/Button"
|
||||
import Menu from "@material-ui/core/Menu"
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import MoreVertOutlined from "@material-ui/icons/MoreVertOutlined"
|
||||
@@ -23,6 +22,7 @@ import {
|
||||
import SettingsOutlined from "@material-ui/icons/SettingsOutlined"
|
||||
import HistoryOutlined from "@material-ui/icons/HistoryOutlined"
|
||||
import DeleteOutlined from "@material-ui/icons/DeleteOutlined"
|
||||
import IconButton from "@material-ui/core/IconButton"
|
||||
|
||||
export interface WorkspaceActionsProps {
|
||||
workspaceStatus: WorkspaceStatus
|
||||
@@ -148,17 +148,18 @@ export const WorkspaceActions: FC<WorkspaceActionsProps> = ({
|
||||
))}
|
||||
{canCancel && <CancelButton handleAction={handleCancel} />}
|
||||
<div>
|
||||
<Button
|
||||
<IconButton
|
||||
title="More options"
|
||||
size="small"
|
||||
data-testid="workspace-options-button"
|
||||
aria-controls="workspace-options"
|
||||
aria-haspopup="true"
|
||||
variant="outlined"
|
||||
disabled={!canAcceptJobs}
|
||||
ref={menuTriggerRef}
|
||||
onClick={() => setIsMenuOpen(true)}
|
||||
>
|
||||
<MoreVertOutlined />
|
||||
</Button>
|
||||
</IconButton>
|
||||
<Menu
|
||||
id="workspace-options"
|
||||
anchorEl={menuTriggerRef.current}
|
||||
@@ -189,6 +190,6 @@ const useStyles = makeStyles((theme) => ({
|
||||
actions: {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: theme.spacing(2),
|
||||
gap: theme.spacing(1.5),
|
||||
},
|
||||
}))
|
||||
|
||||
@@ -19,6 +19,7 @@ import AddIcon from "@material-ui/icons/AddOutlined"
|
||||
import Popover from "@material-ui/core/Popover"
|
||||
import TextField from "@material-ui/core/TextField"
|
||||
import Button from "@material-ui/core/Button"
|
||||
import { WorkspaceStatusText } from "components/WorkspaceStatusBadge/WorkspaceStatusBadge"
|
||||
|
||||
const Language = {
|
||||
workspaceDetails: "Workspace Details",
|
||||
@@ -67,8 +68,14 @@ export const WorkspaceStats: FC<WorkspaceStatsProps> = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<Stats aria-label={Language.workspaceDetails}>
|
||||
<Stats aria-label={Language.workspaceDetails} className={styles.stats}>
|
||||
<StatsItem
|
||||
className={styles.statsItem}
|
||||
label="Status"
|
||||
value={<WorkspaceStatusText build={workspace.latest_build} />}
|
||||
/>
|
||||
<StatsItem
|
||||
className={styles.statsItem}
|
||||
label={Language.templateLabel}
|
||||
value={
|
||||
<Link
|
||||
@@ -80,6 +87,7 @@ export const WorkspaceStats: FC<WorkspaceStatsProps> = ({
|
||||
}
|
||||
/>
|
||||
<StatsItem
|
||||
className={styles.statsItem}
|
||||
label={Language.versionLabel}
|
||||
value={
|
||||
<>
|
||||
@@ -100,6 +108,7 @@ export const WorkspaceStats: FC<WorkspaceStatsProps> = ({
|
||||
}
|
||||
/>
|
||||
<StatsItem
|
||||
className={styles.statsItem}
|
||||
label={Language.lastBuiltLabel}
|
||||
value={
|
||||
<>
|
||||
@@ -110,6 +119,7 @@ export const WorkspaceStats: FC<WorkspaceStatsProps> = ({
|
||||
/>
|
||||
{shouldDisplayScheduleLabel(workspace) && (
|
||||
<StatsItem
|
||||
className={styles.statsItem}
|
||||
label={getScheduleLabel(workspace)}
|
||||
value={
|
||||
<span className={styles.scheduleValue}>
|
||||
@@ -152,6 +162,7 @@ export const WorkspaceStats: FC<WorkspaceStatsProps> = ({
|
||||
)}
|
||||
{workspace.latest_build.daily_cost > 0 && (
|
||||
<StatsItem
|
||||
className={styles.statsItem}
|
||||
label={Language.costLabel}
|
||||
value={`${workspace.latest_build.daily_cost} ${
|
||||
quota_budget ? `/ ${quota_budget}` : ""
|
||||
@@ -296,6 +307,32 @@ const getScheduleLabel = (workspace: Workspace) => {
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
stats: {
|
||||
padding: 0,
|
||||
border: 0,
|
||||
gap: theme.spacing(6),
|
||||
rowGap: theme.spacing(3),
|
||||
flex: 1,
|
||||
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "flex-start",
|
||||
gap: theme.spacing(1),
|
||||
},
|
||||
},
|
||||
|
||||
statsItem: {
|
||||
flexDirection: "column",
|
||||
gap: 0,
|
||||
padding: 0,
|
||||
|
||||
"& > span:first-child": {
|
||||
fontSize: 12,
|
||||
fontWeight: 500,
|
||||
},
|
||||
},
|
||||
|
||||
scheduleValue: {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
|
||||
@@ -8,6 +8,8 @@ import { Pill } from "components/Pill/Pill"
|
||||
import i18next from "i18next"
|
||||
import { FC, ReactNode, PropsWithChildren } from "react"
|
||||
import { PaletteIndex } from "theme/palettes"
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import { combineClasses } from "utils/combineClasses"
|
||||
|
||||
const LoadingIcon: FC = () => {
|
||||
return <CircularProgress size={10} style={{ color: "#FFF" }} />
|
||||
@@ -102,3 +104,47 @@ export const WorkspaceStatusBadge: FC<
|
||||
const { text, icon, type } = getStatus(build.status)
|
||||
return <Pill className={className} icon={icon} text={text} type={type} />
|
||||
}
|
||||
|
||||
export const WorkspaceStatusText: FC<
|
||||
PropsWithChildren<WorkspaceStatusBadgeProps>
|
||||
> = ({ build, className }) => {
|
||||
const styles = useStyles()
|
||||
const { text, type } = getStatus(build.status)
|
||||
return (
|
||||
<span
|
||||
role="status"
|
||||
className={combineClasses([
|
||||
className,
|
||||
styles.root,
|
||||
styles[`type-${type}`],
|
||||
])}
|
||||
>
|
||||
{text}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: { fontWeight: 600 },
|
||||
"type-error": {
|
||||
color: theme.palette.error.light,
|
||||
},
|
||||
"type-warning": {
|
||||
color: theme.palette.warning.light,
|
||||
},
|
||||
"type-success": {
|
||||
color: theme.palette.success.light,
|
||||
},
|
||||
"type-info": {
|
||||
color: theme.palette.info.light,
|
||||
},
|
||||
"type-undefined": {
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
"type-primary": {
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
"type-secondary": {
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
}))
|
||||
|
||||
Reference in New Issue
Block a user