Skip to content

Commit 8acba0c

Browse files
authored
site: cleanup code in WorkspaceBuildProgress (coder#4584)
1 parent 6f5544e commit 8acba0c

File tree

1 file changed

+40
-35
lines changed

1 file changed

+40
-35
lines changed

site/src/components/WorkspaceBuildProgress/WorkspaceBuildProgress.tsx

Lines changed: 40 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,19 @@ dayjs.extend(duration)
1111

1212
const estimateFinish = (
1313
startedAt: Dayjs,
14-
templateAverage?: number,
14+
buildEstimate: number,
1515
): [number, string] => {
16-
if (templateAverage === undefined) {
17-
return [0, "Unknown"]
18-
}
19-
const realPercentage = dayjs().diff(startedAt) / templateAverage
16+
const realPercentage = dayjs().diff(startedAt) / buildEstimate
2017

21-
// Showing a full bar is frustrating.
22-
const maxPercentage = 0.99
18+
const maxPercentage = 1
2319
if (realPercentage > maxPercentage) {
24-
return [maxPercentage, "Any moment now..."]
20+
return [maxPercentage * 100, "Any moment now..."]
2521
}
2622

2723
return [
28-
realPercentage,
24+
realPercentage * 100,
2925
`~${Math.ceil(
30-
dayjs.duration((1 - realPercentage) * templateAverage).asSeconds(),
26+
dayjs.duration((1 - realPercentage) * buildEstimate).asSeconds(),
3127
)} seconds remaining...`,
3228
]
3329
}
@@ -62,49 +58,55 @@ export const WorkspaceBuildProgress: FC<WorkspaceBuildProgressProps> = ({
6258
}) => {
6359
const styles = useStyles()
6460
const job = workspace.latest_build.job
65-
const [progressValue, setProgressValue] = useState(0)
61+
const [progressValue, setProgressValue] = useState<number | undefined>(0)
6662

6763
// By default workspace is updated every second, which can cause visual stutter
6864
// when the build estimate is a few seconds. The timer ensures no observable
6965
// stutter in all cases.
7066
useEffect(() => {
7167
const updateProgress = () => {
72-
if (job.status !== "running") {
73-
setProgressValue(0)
68+
if (job.status !== "running" || buildEstimate === undefined) {
69+
setProgressValue(undefined)
7470
return
7571
}
76-
setProgressValue(
77-
estimateFinish(dayjs(job.started_at), buildEstimate)[0] * 100,
78-
)
72+
const est = estimateFinish(dayjs(job.started_at), buildEstimate)[0]
73+
setProgressValue(est)
7974
}
80-
setTimeout(updateProgress, 100)
75+
setTimeout(updateProgress, 5)
8176
}, [progressValue, job, buildEstimate])
8277

83-
// buildEstimate may be undefined if the template is new or coderd hasn't
84-
// finished initial metrics collection.
85-
if (buildEstimate === undefined) {
86-
return (
87-
<div className={styles.stack}>
88-
<LinearProgress value={0} variant="indeterminate" />
89-
<div className={styles.barHelpers}>
90-
<div className={styles.label}>{`Build ${job.status}`}</div>
91-
<div className={styles.label}>Unknown ETA</div>
92-
</div>
93-
</div>
94-
)
95-
}
96-
9778
return (
9879
<div className={styles.stack}>
9980
<LinearProgress
100-
value={(job.status === "running" && progressValue) || 0}
101-
variant={job.status === "running" ? "determinate" : "indeterminate"}
81+
value={progressValue !== undefined ? progressValue : 0}
82+
variant={
83+
// There is an initial state where progressValue may be undefined
84+
// (e.g. the build isn't yet running). If we flicker from the
85+
// indeterminate bar to the determinate bar, the vigilant user
86+
// perceives the bar jumping from 100% to 0%.
87+
progressValue !== undefined &&
88+
progressValue < 100 &&
89+
buildEstimate !== undefined
90+
? "determinate"
91+
: "indeterminate"
92+
}
93+
// If a transition is set, there is a moment on new load where the
94+
// bar accelerates to progressValue and then rapidly decelerates, which
95+
// is not indicative of true progress.
96+
classes={{ bar: styles.noTransition }}
10297
/>
10398
<div className={styles.barHelpers}>
10499
<div className={styles.label}>{`Build ${job.status}`}</div>
105100
<div className={styles.label}>
106-
{job.status === "running" &&
107-
estimateFinish(dayjs(job.started_at), buildEstimate)[1]}
101+
{(() => {
102+
if (job.status !== "running") {
103+
return ""
104+
} else if (buildEstimate !== undefined) {
105+
return estimateFinish(dayjs(job.started_at), buildEstimate)[1]
106+
} else {
107+
return "Unknown ETA"
108+
}
109+
})()}
108110
</div>
109111
</div>
110112
</div>
@@ -116,6 +118,9 @@ const useStyles = makeStyles((theme) => ({
116118
paddingLeft: theme.spacing(0.2),
117119
paddingRight: theme.spacing(0.2),
118120
},
121+
noTransition: {
122+
transition: "none",
123+
},
119124
barHelpers: {
120125
display: "flex",
121126
justifyContent: "space-between",

0 commit comments

Comments
 (0)