refactor: Show template version in the workspace page (#5194)

This commit is contained in:
Bruno Quaresma
2022-11-30 11:13:07 -03:00
committed by GitHub
parent 5817d2a301
commit 41f10e7b69
8 changed files with 158 additions and 175 deletions

View File

@ -34,9 +34,18 @@ export const BuildRow: React.FC<BuildRowProps> = ({ build }) => {
alignItems="center"
className={styles.buildWrapper}
>
<Stack direction="row" alignItems="center">
<Stack
direction="row"
alignItems="center"
className={styles.fullWidth}
>
<BuildAvatar build={build} />
<div>
<Stack
direction="row"
justifyContent="space-between"
alignItems="center"
className={styles.fullWidth}
>
<Stack
className={styles.buildSummary}
direction="row"
@ -66,8 +75,13 @@ export const BuildRow: React.FC<BuildRowProps> = ({ build }) => {
{t("buildData.duration")}:{" "}
<strong>{displayWorkspaceBuildDuration(build)}</strong>
</span>
<span className={styles.buildInfo}>
{t("buildData.version")}:{" "}
<strong>{build.template_version_name}</strong>
</span>
</Stack>
</div>
</Stack>
</Stack>
</Stack>
</TableCell>
@ -114,4 +128,8 @@ const useStyles = makeStyles((theme) => ({
color: theme.palette.text.secondary,
whiteSpace: "nowrap",
},
fullWidth: {
width: "100%",
},
}))

View File

@ -30,17 +30,24 @@ const useStyles = makeStyles((theme) => ({
alignItems: "center",
color: theme.palette.text.secondary,
margin: "0px",
[theme.breakpoints.down("sm")]: {
display: "block",
padding: theme.spacing(2),
},
},
statItem: {
padding: theme.spacing(2),
paddingTop: theme.spacing(1.75),
padding: theme.spacing(1.75),
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2),
display: "flex",
alignItems: "baseline",
gap: theme.spacing(1),
[theme.breakpoints.down("sm")]: {
padding: theme.spacing(1),
},
},
statsLabel: {
@ -50,9 +57,10 @@ const useStyles = makeStyles((theme) => ({
statsValue: {
marginTop: theme.spacing(0.25),
display: "block",
display: "flex",
wordWrap: "break-word",
color: theme.palette.text.primary,
alignItems: "center",
"& a": {
color: theme.palette.text.primary,

View File

@ -4,6 +4,7 @@ import { makeStyles } from "@material-ui/core/styles"
import HelpIcon from "@material-ui/icons/HelpOutline"
import OpenInNewIcon from "@material-ui/icons/OpenInNew"
import React, { createContext, useContext, useRef, useState } from "react"
import { combineClasses } from "util/combineClasses"
import { Stack } from "../../Stack/Stack"
type Icon = typeof HelpIcon
@ -13,6 +14,9 @@ export interface HelpTooltipProps {
// Useful to test on storybook
open?: boolean
size?: Size
icon?: Icon
iconClassName?: string
buttonClassName?: string
}
export const Language = {
@ -66,7 +70,14 @@ export const HelpPopover: React.FC<
export const HelpTooltip: React.FC<
React.PropsWithChildren<HelpTooltipProps>
> = ({ children, open, size = "medium" }) => {
> = ({
children,
open,
size = "medium",
icon: Icon = HelpIcon,
iconClassName,
buttonClassName,
}) => {
const styles = useStyles({ size })
const anchorRef = useRef<HTMLButtonElement>(null)
const [isOpen, setIsOpen] = useState(Boolean(open))
@ -81,7 +92,7 @@ export const HelpTooltip: React.FC<
<button
ref={anchorRef}
aria-describedby={id}
className={styles.button}
className={combineClasses([styles.button, buttonClassName])}
onClick={(event) => {
event.stopPropagation()
setIsOpen(true)
@ -94,7 +105,7 @@ export const HelpTooltip: React.FC<
}}
aria-label={Language.ariaLabel}
>
<HelpIcon className={styles.icon} />
<Icon className={combineClasses([styles.icon, iconClassName])} />
</button>
<HelpPopover
id={id}

View File

@ -7,6 +7,9 @@ import {
HelpTooltipText,
HelpTooltipTitle,
} from "./HelpTooltip"
import InfoIcon from "@material-ui/icons/InfoOutlined"
import { makeStyles } from "@material-ui/core/styles"
import { colors } from "theme/colors"
export const Language = {
outdatedLabel: "Outdated",
@ -24,8 +27,15 @@ export const OutdatedHelpTooltip: FC<React.PropsWithChildren<TooltipProps>> = ({
onUpdateVersion,
ariaLabel,
}) => {
const styles = useStyles()
return (
<HelpTooltip size="small">
<HelpTooltip
size="small"
icon={InfoIcon}
iconClassName={styles.icon}
buttonClassName={styles.button}
>
<HelpTooltipTitle>{Language.outdatedLabel}</HelpTooltipTitle>
<HelpTooltipText>{Language.versionTooltipText}</HelpTooltipText>
<HelpTooltipLinksGroup>
@ -40,3 +50,17 @@ export const OutdatedHelpTooltip: FC<React.PropsWithChildren<TooltipProps>> = ({
</HelpTooltip>
)
}
const useStyles = makeStyles(() => ({
icon: {
color: colors.yellow[5],
},
button: {
opacity: 1,
"&:hover": {
opacity: 1,
},
},
}))

View File

@ -1,15 +1,14 @@
import Link from "@material-ui/core/Link"
import { makeStyles } from "@material-ui/core/styles"
import { OutdatedHelpTooltip } from "components/Tooltips"
import { FC } from "react"
import { Link as RouterLink } from "react-router-dom"
import { combineClasses } from "util/combineClasses"
import { createDayString } from "util/createDayString"
import {
getDisplayWorkspaceBuildInitiatedBy,
getDisplayWorkspaceTemplateName,
} from "util/workspace"
import { Workspace } from "../../api/typesGenerated"
import { Stats, StatsItem } from "components/Stats/Stats"
const Language = {
workspaceDetails: "Workspace Details",
@ -34,110 +33,57 @@ export const WorkspaceStats: FC<WorkspaceStatsProps> = ({
quota_budget,
handleUpdate,
}) => {
const styles = useStyles()
const initiatedBy = getDisplayWorkspaceBuildInitiatedBy(
workspace.latest_build,
)
const displayTemplateName = getDisplayWorkspaceTemplateName(workspace)
return (
<div className={styles.stats} aria-label={Language.workspaceDetails}>
<div className={styles.statItem}>
<span className={styles.statsLabel}>{Language.templateLabel}:</span>
<Link
component={RouterLink}
to={`/templates/${workspace.template_name}`}
className={combineClasses([styles.statsValue, styles.link])}
>
{displayTemplateName}
</Link>
</div>
<div className={styles.statItem}>
<span className={styles.statsLabel}>{Language.versionLabel}:</span>
<span className={styles.statsValue}>
{workspace.outdated ? (
<span className={styles.outdatedLabel}>
{Language.outdated}
<Stats aria-label={Language.workspaceDetails}>
<StatsItem
label={Language.templateLabel}
value={
<Link
component={RouterLink}
to={`/templates/${workspace.template_name}`}
>
{displayTemplateName}
</Link>
}
/>
<StatsItem
label={Language.versionLabel}
value={
<>
<Link
component={RouterLink}
to={`/templates/${workspace.template_name}/versions/${workspace.latest_build.template_version_name}`}
>
{workspace.latest_build.template_version_name}
</Link>
{workspace.outdated && (
<OutdatedHelpTooltip
onUpdateVersion={handleUpdate}
ariaLabel="update version"
/>
</span>
) : (
Language.upToDate
)}
</span>
</div>
<div className={styles.statItem}>
<span className={styles.statsLabel}>{Language.lastBuiltLabel}:</span>
<span className={styles.statsValue} data-chromatic="ignore">
{createDayString(workspace.latest_build.created_at)}
</span>
</div>
<div className={styles.statItem}>
<span className={styles.statsLabel}>{Language.byLabel}:</span>
<span className={styles.statsValue}>{initiatedBy}</span>
</div>
)}
</>
}
/>
<StatsItem
label={Language.lastBuiltLabel}
value={createDayString(workspace.latest_build.created_at)}
/>
<StatsItem label={Language.byLabel} value={initiatedBy} />
{workspace.latest_build.daily_cost > 0 && (
<div className={styles.statItem}>
<span className={styles.statsLabel}>{Language.costLabel}:</span>
<span className={styles.statsValue}>
{workspace.latest_build.daily_cost} / {quota_budget}
</span>
</div>
<StatsItem
label={Language.costLabel}
value={`${workspace.latest_build.daily_cost} ${
quota_budget ? `/ ${quota_budget}` : ""
}`}
/>
)}
</div>
</Stats>
)
}
const useStyles = makeStyles((theme) => ({
stats: {
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2),
borderRadius: theme.shape.borderRadius,
border: `1px solid ${theme.palette.divider}`,
display: "flex",
alignItems: "center",
color: theme.palette.text.secondary,
margin: "0px",
[theme.breakpoints.down("sm")]: {
display: "block",
},
},
statItem: {
padding: theme.spacing(2),
paddingTop: theme.spacing(1.75),
display: "flex",
alignItems: "baseline",
gap: theme.spacing(1),
},
statsLabel: {
display: "block",
wordWrap: "break-word",
},
statsValue: {
marginTop: theme.spacing(0.25),
display: "block",
wordWrap: "break-word",
color: theme.palette.text.primary,
},
capitalize: {
textTransform: "capitalize",
},
link: {
color: theme.palette.text.primary,
fontWeight: 600,
},
outdatedLabel: {
color: theme.palette.error.main,
display: "flex",
alignItems: "center",
gap: theme.spacing(0.5),
},
}))

View File

@ -1,53 +1,41 @@
import { makeStyles, Theme } from "@material-ui/core/styles"
import TableCell from "@material-ui/core/TableCell"
import { makeStyles } from "@material-ui/core/styles"
import TableRow from "@material-ui/core/TableRow"
import KeyboardArrowRight from "@material-ui/icons/KeyboardArrowRight"
import useTheme from "@material-ui/styles/useTheme"
import { useActor } from "@xstate/react"
import { AvatarData } from "components/AvatarData/AvatarData"
import { WorkspaceStatusBadge } from "components/WorkspaceStatusBadge/WorkspaceStatusBadge"
import { useClickable } from "hooks/useClickable"
import { FC } from "react"
import { useNavigate } from "react-router-dom"
import { getDisplayWorkspaceTemplateName } from "util/workspace"
import { WorkspaceItemMachineRef } from "../../xServices/workspaces/workspacesXService"
import { LastUsed } from "../LastUsed/LastUsed"
import {
TableCellData,
TableCellDataPrimary,
} from "../TableCellData/TableCellData"
import { TableCellLink } from "../TableCellLink/TableCellLink"
import { OutdatedHelpTooltip } from "../Tooltips"
const Language = {
upToDateLabel: "Up to date",
outdatedLabel: "Outdated",
}
export const WorkspacesRow: FC<
React.PropsWithChildren<{ workspaceRef: WorkspaceItemMachineRef }>
> = ({ workspaceRef }) => {
export const WorkspacesRow: FC<{ workspaceRef: WorkspaceItemMachineRef }> = ({
workspaceRef,
}) => {
const styles = useStyles()
const navigate = useNavigate()
const theme: Theme = useTheme()
const [workspaceState, send] = useActor(workspaceRef)
const { data: workspace } = workspaceState.context
const workspacePageLink = `/@${workspace.owner_name}/${workspace.name}`
const hasTemplateIcon =
workspace.template_icon && workspace.template_icon !== ""
const displayTemplateName = getDisplayWorkspaceTemplateName(workspace)
const clickable = useClickable(() => {
navigate(workspacePageLink)
})
return (
<TableRow
className={styles.row}
hover
data-testid={`workspace-${workspace.id}`}
tabIndex={0}
onKeyDown={(event) => {
if (event.key === "Enter") {
navigate(workspacePageLink)
}
}}
className={styles.clickableTableRow}
{...clickable}
>
<TableCellLink to={workspacePageLink}>
<TableCell>
<AvatarData
highlightTitle
title={workspace.name}
@ -60,78 +48,61 @@ export const WorkspacesRow: FC<
) : undefined
}
/>
</TableCellLink>
</TableCell>
<TableCellLink to={workspacePageLink}>
<TableCellDataPrimary>{displayTemplateName}</TableCellDataPrimary>
</TableCellLink>
<TableCellLink to={workspacePageLink}>
<TableCellData>
<LastUsed lastUsedAt={workspace.last_used_at} />
</TableCellData>
</TableCellLink>
<TableCell>{displayTemplateName}</TableCell>
<TableCellLink to={workspacePageLink}>
{workspace.outdated ? (
<span className={styles.outdatedLabel}>
{Language.outdatedLabel}
<TableCell>
<div className={styles.version}>
{workspace.latest_build.template_version_name}
{workspace.outdated && (
<OutdatedHelpTooltip
onUpdateVersion={() => {
send("UPDATE_VERSION")
}}
/>
</span>
) : (
<span style={{ color: theme.palette.text.secondary }}>
{Language.upToDateLabel}
</span>
)}
</TableCellLink>
)}
</div>
</TableCell>
<TableCellLink to={workspacePageLink}>
<TableCell>
<LastUsed lastUsedAt={workspace.last_used_at} />
</TableCell>
<TableCell>
<WorkspaceStatusBadge build={workspace.latest_build} />
</TableCellLink>
<TableCellLink to={workspacePageLink}>
</TableCell>
<TableCell>
<div className={styles.arrowCell}>
<KeyboardArrowRight className={styles.arrowRight} />
</div>
</TableCellLink>
</TableCell>
</TableRow>
)
}
const useStyles = makeStyles((theme) => ({
clickableTableRow: {
"&:hover td": {
backgroundColor: theme.palette.action.hover,
},
row: {
cursor: "pointer",
"&:focus": {
outline: `1px solid ${theme.palette.secondary.dark}`,
},
"& .MuiTableCell-root:last-child": {
paddingRight: theme.spacing(2),
outlineOffset: -1,
},
},
arrowRight: {
color: theme.palette.text.secondary,
width: 20,
height: 20,
},
arrowCell: {
display: "flex",
paddingLeft: theme.spacing(2),
},
outdatedLabel: {
color: theme.palette.error.main,
display: "flex",
alignItems: "center",
gap: theme.spacing(0.5),
},
buildTime: {
color: theme.palette.text.secondary,
fontSize: 12,
},
templateIconWrapper: {
// Same size then the avatar component
width: 36,
@ -142,4 +113,8 @@ const useStyles = makeStyles((theme) => ({
width: "100%",
},
},
version: {
display: "flex",
},
}))

View File

@ -32,10 +32,10 @@ export const WorkspacesTable: FC<
<Table>
<TableHead>
<TableRow>
<TableCell width="25%">{Language.name}</TableCell>
<TableCell width="35%">{Language.template}</TableCell>
<TableCell width="30%">{Language.name}</TableCell>
<TableCell width="25%">{Language.template}</TableCell>
<TableCell width="25%">{Language.version}</TableCell>
<TableCell width="20%">{Language.lastUsed}</TableCell>
<TableCell width="20%">{Language.version}</TableCell>
<TableCell width="20%">{Language.status}</TableCell>
<TableCell width="1%"></TableCell>
</TableRow>

View File

@ -50,6 +50,7 @@
},
"buildData": {
"reason": "Reason",
"duration": "Duration"
"duration": "Duration",
"version": "Version"
}
}