From 7f90d068b66d010dadefb7b2f1c819dde643446c Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Mon, 31 Oct 2022 19:27:44 +0000 Subject: [PATCH 1/4] refactor: Improve build page --- .../components/BuildsTable/BuildAvatar.tsx | 13 +- site/src/components/Logs/Logs.tsx | 1 + site/src/components/Stats/Stats.tsx | 67 +++++++++ .../WorkspaceBuildLogs/WorkspaceBuildLogs.tsx | 21 ++- .../WorkspaceBuildStats.tsx | 142 +++--------------- .../WorkspaceBuildPageView.tsx | 30 +++- 6 files changed, 142 insertions(+), 132 deletions(-) create mode 100644 site/src/components/Stats/Stats.tsx diff --git a/site/src/components/BuildsTable/BuildAvatar.tsx b/site/src/components/BuildsTable/BuildAvatar.tsx index d4976d0e2a984..231fe761caa58 100644 --- a/site/src/components/BuildsTable/BuildAvatar.tsx +++ b/site/src/components/BuildsTable/BuildAvatar.tsx @@ -30,16 +30,19 @@ const StyledAvatar = withStyles((theme) => ({ background: theme.palette.divider, color: theme.palette.text.primary, border: `2px solid ${theme.palette.divider}`, + width: ({ size }: { size?: number }) => size, + height: ({ size }: { size?: number }) => size, "& svg": { - width: 18, - height: 18, + width: ({ size }: { size?: number }) => (size ? size / 2 : 18), + height: ({ size }: { size?: number }) => (size ? size / 2 : 18), }, }, }))(Avatar) export type BuildAvatarProps = { build: WorkspaceBuild + size?: number } const iconByTransition: Record = { @@ -48,7 +51,7 @@ const iconByTransition: Record = { delete: , } -export const BuildAvatar: FC = ({ build }) => { +export const BuildAvatar: FC = ({ build, size }) => { const theme = useTheme() const displayBuildStatus = getDisplayWorkspaceBuildStatus(theme, build) @@ -65,7 +68,9 @@ export const BuildAvatar: FC = ({ build }) => { }} badgeContent={
} > - {iconByTransition[build.transition]} + + {iconByTransition[build.transition]} + ) } diff --git a/site/src/components/Logs/Logs.tsx b/site/src/components/Logs/Logs.tsx index f992eb2b8af4c..d5fd60d037c6c 100644 --- a/site/src/components/Logs/Logs.tsx +++ b/site/src/components/Logs/Logs.tsx @@ -57,5 +57,6 @@ const useStyles = makeStyles((theme) => ({ userSelect: "none", width: theme.spacing(12.5), display: "inline-block", + color: theme.palette.text.secondary, }, })) diff --git a/site/src/components/Stats/Stats.tsx b/site/src/components/Stats/Stats.tsx new file mode 100644 index 0000000000000..1cb05d554bc8d --- /dev/null +++ b/site/src/components/Stats/Stats.tsx @@ -0,0 +1,67 @@ +import { makeStyles } from "@material-ui/core/styles" +import { ComponentProps, FC, PropsWithChildren } from "react" + +export const Stats: FC>> = (props) => { + const styles = useStyles() + return
+} + +export const StatsItem: FC<{ + label: string + value: string | number | JSX.Element +}> = ({ label, value }) => { + const styles = useStyles() + + return ( +
+ {label}: + {value} +
+ ) +} + +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, + + "& a": { + color: theme.palette.text.primary, + textDecoration: "none", + fontWeight: 600, + + "&:hover": { + textDecoration: "underline", + }, + }, + }, +})) diff --git a/site/src/components/WorkspaceBuildLogs/WorkspaceBuildLogs.tsx b/site/src/components/WorkspaceBuildLogs/WorkspaceBuildLogs.tsx index f0dc70c5609bc..edf9aaeed5626 100644 --- a/site/src/components/WorkspaceBuildLogs/WorkspaceBuildLogs.tsx +++ b/site/src/components/WorkspaceBuildLogs/WorkspaceBuildLogs.tsx @@ -1,6 +1,6 @@ import { makeStyles } from "@material-ui/core/styles" import dayjs from "dayjs" -import { FC } from "react" +import { FC, Fragment } from "react" import { ProvisionerJobLog } from "../../api/typesGenerated" import { MONOSPACE_FONT_FAMILY } from "../../theme/constants" import { Logs } from "../Logs/Logs" @@ -59,7 +59,7 @@ export const WorkspaceBuildLogs: FC = ({ logs }) => { const shouldDisplayDuration = duration !== undefined return ( -
+
{stage}
{shouldDisplayDuration && ( @@ -69,7 +69,7 @@ export const WorkspaceBuildLogs: FC = ({ logs }) => { )}
{!isEmpty && } -
+ ) })}
@@ -84,7 +84,7 @@ const useStyles = makeStyles((theme) => ({ }, header: { - fontSize: theme.typography.body1.fontSize, + fontSize: 14, padding: theme.spacing(2), paddingLeft: theme.spacing(4), paddingRight: theme.spacing(4), @@ -92,6 +92,19 @@ const useStyles = makeStyles((theme) => ({ backgroundColor: theme.palette.background.paper, display: "flex", alignItems: "center", + fontFamily: "Inter", + + "&:first-child": { + borderTopLeftRadius: theme.shape.borderRadius, + borderTopRightRadius: theme.shape.borderRadius, + }, + + "&:last-child": { + borderBottom: 0, + borderTop: `1px solid ${theme.palette.divider}`, + borderBottomLeftRadius: theme.shape.borderRadius, + borderBottomRightRadius: theme.shape.borderRadius, + }, }, duration: { diff --git a/site/src/components/WorkspaceBuildStats/WorkspaceBuildStats.tsx b/site/src/components/WorkspaceBuildStats/WorkspaceBuildStats.tsx index 10a16dc1d5f4f..7194d0c0c28f8 100644 --- a/site/src/components/WorkspaceBuildStats/WorkspaceBuildStats.tsx +++ b/site/src/components/WorkspaceBuildStats/WorkspaceBuildStats.tsx @@ -1,15 +1,8 @@ -import Link from "@material-ui/core/Link" -import { makeStyles, useTheme } from "@material-ui/core/styles" +import { Stats, StatsItem } from "components/Stats/Stats" import { FC } from "react" -import { Link as RouterLink } from "react-router-dom" +import { Link } from "react-router-dom" import { WorkspaceBuild } from "../../api/typesGenerated" -import { MONOSPACE_FONT_FAMILY } from "../../theme/constants" -import { combineClasses } from "../../util/combineClasses" -import { - displayWorkspaceBuildDuration, - getDisplayWorkspaceBuildInitiatedBy, - getDisplayWorkspaceBuildStatus, -} from "../../util/workspace" +import { displayWorkspaceBuildDuration } from "../../util/workspace" export interface WorkspaceBuildStatsProps { build: WorkspaceBuild @@ -18,116 +11,25 @@ export interface WorkspaceBuildStatsProps { export const WorkspaceBuildStats: FC = ({ build, }) => { - const styles = useStyles() - const theme = useTheme() - const status = getDisplayWorkspaceBuildStatus(theme, build) - const initiatedBy = getDisplayWorkspaceBuildInitiatedBy(build) - return ( -
-
- Workspace Name - - {build.workspace_name} - -
-
- -
- Duration - - {displayWorkspaceBuildDuration(build)} - -
-
-
- Started at - - {new Date(build.created_at).toLocaleString()} - -
-
-
- Status - - {status.status} - -
-
-
- Action - - {build.transition} - -
-
-
- Initiated by - {initiatedBy} -
-
+ + + {build.workspace_name} + + } + /> + + + + ) } - -const useStyles = makeStyles((theme) => ({ - stats: { - paddingLeft: theme.spacing(2), - paddingRight: theme.spacing(2), - backgroundColor: theme.palette.background.paper, - borderRadius: theme.shape.borderRadius, - display: "flex", - alignItems: "center", - color: theme.palette.text.secondary, - fontFamily: MONOSPACE_FONT_FAMILY, - border: `1px solid ${theme.palette.divider}`, - [theme.breakpoints.down("sm")]: { - display: "block", - }, - }, - - statItem: { - minWidth: "13%", - padding: theme.spacing(2), - paddingTop: theme.spacing(1.75), - }, - - statsLabel: { - fontSize: 12, - textTransform: "uppercase", - display: "block", - fontWeight: 600, - wordWrap: "break-word", - }, - - statsValue: { - fontSize: 16, - marginTop: theme.spacing(0.25), - display: "block", - wordWrap: "break-word", - }, - - statsDivider: { - width: 1, - height: theme.spacing(5), - backgroundColor: theme.palette.divider, - marginRight: theme.spacing(2), - [theme.breakpoints.down("sm")]: { - display: "none", - }, - }, - - capitalize: { - textTransform: "capitalize", - }, - - link: { - color: theme.palette.text.primary, - fontWeight: 600, - }, -})) diff --git a/site/src/pages/WorkspaceBuildPage/WorkspaceBuildPageView.tsx b/site/src/pages/WorkspaceBuildPage/WorkspaceBuildPageView.tsx index a690697684cd4..acf7b746fcd95 100644 --- a/site/src/pages/WorkspaceBuildPage/WorkspaceBuildPageView.tsx +++ b/site/src/pages/WorkspaceBuildPage/WorkspaceBuildPageView.tsx @@ -1,9 +1,12 @@ +import { BuildAvatar } from "components/BuildsTable/BuildAvatar" import { FC } from "react" +import { useParams } from "react-router-dom" import { ProvisionerJobLog, WorkspaceBuild } from "../../api/typesGenerated" import { Loader } from "../../components/Loader/Loader" import { Margins } from "../../components/Margins/Margins" import { PageHeader, + PageHeaderSubtitle, PageHeaderTitle, } from "../../components/PageHeader/PageHeader" import { Stack } from "../../components/Stack/Stack" @@ -18,6 +21,13 @@ const sortLogsByCreatedAt = (logs: ProvisionerJobLog[]) => { ) } +const useBuildNumber = () => { + const { buildNumber } = useParams() + if (!buildNumber) { + throw new Error("Build number not found") + } + return buildNumber +} export interface WorkspaceBuildPageViewProps { logs: ProvisionerJobLog[] | undefined build: WorkspaceBuild | undefined @@ -27,13 +37,25 @@ export const WorkspaceBuildPageView: FC = ({ logs, build, }) => { + const buildNumber = useBuildNumber() + return ( - - Logs - + {build && ( + + + +
+ Build #{buildNumber} + + {build.initiator_name} + +
+
+
+ )} - + {build && build.transition === "delete" && build.job.status === "failed" && ( From 94424aade008e4f2032fda5c427758a60e6cbb76 Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Mon, 31 Oct 2022 19:31:20 +0000 Subject: [PATCH 2/4] Add build translation --- .../WorkspaceBuildStats/WorkspaceBuildStats.tsx | 11 +++++++---- site/src/i18n/en/buildPage.json | 8 ++++++++ site/src/i18n/en/index.ts | 2 ++ 3 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 site/src/i18n/en/buildPage.json diff --git a/site/src/components/WorkspaceBuildStats/WorkspaceBuildStats.tsx b/site/src/components/WorkspaceBuildStats/WorkspaceBuildStats.tsx index 7194d0c0c28f8..6399570f5799a 100644 --- a/site/src/components/WorkspaceBuildStats/WorkspaceBuildStats.tsx +++ b/site/src/components/WorkspaceBuildStats/WorkspaceBuildStats.tsx @@ -1,5 +1,6 @@ import { Stats, StatsItem } from "components/Stats/Stats" import { FC } from "react" +import { useTranslation } from "react-i18next" import { Link } from "react-router-dom" import { WorkspaceBuild } from "../../api/typesGenerated" import { displayWorkspaceBuildDuration } from "../../util/workspace" @@ -11,10 +12,12 @@ export interface WorkspaceBuildStatsProps { export const WorkspaceBuildStats: FC = ({ build, }) => { + const { t } = useTranslation("buildPage") + return ( {build.workspace_name} @@ -22,14 +25,14 @@ export const WorkspaceBuildStats: FC = ({ } /> - + ) } diff --git a/site/src/i18n/en/buildPage.json b/site/src/i18n/en/buildPage.json new file mode 100644 index 0000000000000..134c040e9f65f --- /dev/null +++ b/site/src/i18n/en/buildPage.json @@ -0,0 +1,8 @@ +{ + "stats": { + "workspace": "Workspace", + "duration": "Duration", + "startedAt": "Started at", + "action": "Action" + } +} diff --git a/site/src/i18n/en/index.ts b/site/src/i18n/en/index.ts index f5a8efe7f2be2..653ac3ed8553b 100644 --- a/site/src/i18n/en/index.ts +++ b/site/src/i18n/en/index.ts @@ -5,6 +5,7 @@ import templatePage from "./templatePage.json" import templatesPage from "./templatesPage.json" import workspacePage from "./workspacePage.json" import agent from "./agent.json" +import buildPage from "./buildPage.json" export const en = { common, @@ -14,4 +15,5 @@ export const en = { templatesPage, createWorkspacePage, agent, + buildPage, } From c78f22c73402e036b481051c511caef62c72a963 Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Mon, 31 Oct 2022 19:33:56 +0000 Subject: [PATCH 3/4] Add build avatar better props --- site/src/components/BuildsTable/BuildAvatar.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/site/src/components/BuildsTable/BuildAvatar.tsx b/site/src/components/BuildsTable/BuildAvatar.tsx index 231fe761caa58..c891aeaca95be 100644 --- a/site/src/components/BuildsTable/BuildAvatar.tsx +++ b/site/src/components/BuildsTable/BuildAvatar.tsx @@ -25,24 +25,27 @@ const StyledBadge = withStyles((theme) => ({ }, }))(Badge) +interface StyledAvatarProps { + size?: number +} + const StyledAvatar = withStyles((theme) => ({ root: { background: theme.palette.divider, color: theme.palette.text.primary, border: `2px solid ${theme.palette.divider}`, - width: ({ size }: { size?: number }) => size, - height: ({ size }: { size?: number }) => size, + width: ({ size }: StyledAvatarProps) => size, + height: ({ size }: StyledAvatarProps) => size, "& svg": { - width: ({ size }: { size?: number }) => (size ? size / 2 : 18), - height: ({ size }: { size?: number }) => (size ? size / 2 : 18), + width: ({ size }: StyledAvatarProps) => (size ? size / 2 : 18), + height: ({ size }: StyledAvatarProps) => (size ? size / 2 : 18), }, }, }))(Avatar) -export type BuildAvatarProps = { +export interface BuildAvatarProps extends StyledAvatarProps { build: WorkspaceBuild - size?: number } const iconByTransition: Record = { From bbca39d8c42c0fe1f1d817ddb0e514ff02d9099a Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Tue, 1 Nov 2022 14:20:21 +0000 Subject: [PATCH 4/4] Get build number from build --- .../WorkspaceBuildPage/WorkspaceBuildPageView.tsx | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/site/src/pages/WorkspaceBuildPage/WorkspaceBuildPageView.tsx b/site/src/pages/WorkspaceBuildPage/WorkspaceBuildPageView.tsx index acf7b746fcd95..17cfb72e0c12f 100644 --- a/site/src/pages/WorkspaceBuildPage/WorkspaceBuildPageView.tsx +++ b/site/src/pages/WorkspaceBuildPage/WorkspaceBuildPageView.tsx @@ -1,6 +1,5 @@ import { BuildAvatar } from "components/BuildsTable/BuildAvatar" import { FC } from "react" -import { useParams } from "react-router-dom" import { ProvisionerJobLog, WorkspaceBuild } from "../../api/typesGenerated" import { Loader } from "../../components/Loader/Loader" import { Margins } from "../../components/Margins/Margins" @@ -21,13 +20,6 @@ const sortLogsByCreatedAt = (logs: ProvisionerJobLog[]) => { ) } -const useBuildNumber = () => { - const { buildNumber } = useParams() - if (!buildNumber) { - throw new Error("Build number not found") - } - return buildNumber -} export interface WorkspaceBuildPageViewProps { logs: ProvisionerJobLog[] | undefined build: WorkspaceBuild | undefined @@ -37,8 +29,6 @@ export const WorkspaceBuildPageView: FC = ({ logs, build, }) => { - const buildNumber = useBuildNumber() - return ( {build && ( @@ -46,7 +36,7 @@ export const WorkspaceBuildPageView: FC = ({
- Build #{buildNumber} + Build #{build.build_number} {build.initiator_name}