Skip to content

Commit 349338a

Browse files
committed
chore: ranges instead of range
1 parent feaa3ea commit 349338a

File tree

2 files changed

+75
-57
lines changed

2 files changed

+75
-57
lines changed

site/src/modules/workspaces/WorkspaceTiming/StagesChart.tsx

Lines changed: 58 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Interpolation, Theme } from "@emotion/react";
22
import type { TimingStage } from "api/typesGenerated";
3+
import { T } from "lodash/fp";
34
import { CircleAlertIcon, InfoIcon } from "lucide-react";
45
import type { FC } from "react";
56
import { Bar, ClickableBar } from "./Chart/Bar";
@@ -52,7 +53,7 @@ export type Stage = {
5253
tooltip: Omit<TooltipProps, "children">;
5354
};
5455

55-
type StageTiming = {
56+
export type StageTiming = {
5657
stage: Stage;
5758
/**
5859
* Represents the number of resources included in this stage that can be
@@ -65,7 +66,7 @@ type StageTiming = {
6566
* duration of the stage and to position the stage within the chart. This can
6667
* be undefined if a stage has no timing data.
6768
*/
68-
range: TimeRange | undefined;
69+
ranges: TimeRange[] | undefined;
6970
/**
7071
* Display an error icon within the bar to indicate when a stage has failed.
7172
* This is used in the agent scripts stage.
@@ -83,11 +84,15 @@ export const StagesChart: FC<StagesChartProps> = ({
8384
onSelectStage,
8485
}) => {
8586
const totalRange = mergeTimeRanges(
86-
timings.map((t) => t.range).filter((t) => t !== undefined),
87+
timings
88+
.map((t) => t.ranges)
89+
.filter((t) => t !== undefined)
90+
.flat(),
8791
);
8892
const totalTime = calcDuration(totalRange);
8993
const [ticks, scale] = makeTicks(totalTime);
9094
const sections = Array.from(new Set(timings.map((t) => t.stage.section)));
95+
console.log("timings", timings);
9196

9297
return (
9398
<Chart>
@@ -129,11 +134,12 @@ export const StagesChart: FC<StagesChartProps> = ({
129134
const stageTimings = timings.filter(
130135
(t) => t.stage.section === section,
131136
);
137+
132138
return (
133139
<XAxisSection key={section}>
134140
{stageTimings.map((t) => {
135141
// If the stage has no timing data, we just want to render an empty row
136-
if (t.range === undefined) {
142+
if (t.ranges === undefined) {
137143
return (
138144
<XAxisRow
139145
key={t.stage.name}
@@ -142,53 +148,55 @@ export const StagesChart: FC<StagesChartProps> = ({
142148
);
143149
}
144150

145-
const value = calcDuration(t.range);
146-
const offset = calcOffset(t.range, totalRange);
147-
const validDuration = value > 0 && !Number.isNaN(value);
151+
return t.ranges?.map((range, index) => {
152+
const value = calcDuration(range);
153+
const offset = calcOffset(range, totalRange);
154+
const validDuration = value > 0 && !Number.isNaN(value);
148155

149-
return (
150-
<XAxisRow
151-
key={t.stage.name}
152-
yAxisLabelId={encodeURIComponent(t.stage.name)}
153-
>
154-
{/** We only want to expand stages with more than one resource */}
155-
{t.visibleResources > 1 ? (
156-
<ClickableBar
157-
aria-label={`View ${t.stage.label} details`}
158-
scale={scale}
159-
value={value}
160-
offset={offset}
161-
onClick={() => {
162-
onSelectStage(t.stage);
163-
}}
164-
>
165-
{t.error && (
166-
<CircleAlertIcon
167-
className="size-icon-sm"
168-
css={{
169-
color: "#F87171",
170-
marginRight: 4,
171-
}}
172-
/>
173-
)}
174-
<Blocks count={t.visibleResources} />
175-
</ClickableBar>
176-
) : (
177-
<Bar scale={scale} value={value} offset={offset} />
178-
)}
179-
{validDuration ? (
180-
<span>{formatTime(value)}</span>
181-
) : (
182-
<span
183-
css={(theme) => ({
184-
color: theme.palette.error.main,
185-
})}
186-
>
187-
Invalid
188-
</span>
189-
)}
190-
</XAxisRow>
191-
);
156+
return (
157+
<XAxisRow
158+
key={t.stage.name + index}
159+
yAxisLabelId={encodeURIComponent(t.stage.name)}
160+
>
161+
{/** We only want to expand stages with more than one resource */}
162+
{t.visibleResources > 1 ? (
163+
<ClickableBar
164+
aria-label={`View ${t.stage.label} details`}
165+
scale={scale}
166+
value={value}
167+
offset={offset}
168+
onClick={() => {
169+
onSelectStage(t.stage);
170+
}}
171+
>
172+
{t.error && (
173+
<CircleAlertIcon
174+
className="size-icon-sm"
175+
css={{
176+
color: "#F87171",
177+
marginRight: 4,
178+
}}
179+
/>
180+
)}
181+
<Blocks count={t.visibleResources} />
182+
</ClickableBar>
183+
) : (
184+
<Bar scale={scale} value={value} offset={offset} />
185+
)}
186+
{validDuration ? (
187+
<span>{formatTime(value)}</span>
188+
) : (
189+
<span
190+
css={(theme) => ({
191+
color: theme.palette.error.main,
192+
})}
193+
>
194+
Invalid
195+
</span>
196+
)}
197+
</XAxisRow>
198+
);
199+
});
192200
})}
193201
</XAxisSection>
194202
);

site/src/modules/workspaces/WorkspaceTiming/WorkspaceTimings.tsx

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
provisioningStages,
2929
type Stage,
3030
StagesChart,
31+
type StageTiming,
3132
} from "./StagesChart";
3233

3334
type TimingView =
@@ -130,16 +131,25 @@ export const WorkspaceTimings: FC<WorkspaceTimingsProps> = ({
130131
<div css={styles.collapseBody}>
131132
{view.name === "default" && (
132133
<StagesChart
133-
timings={stages.map((s) => {
134+
timings={stages.map((s): StageTiming => {
134135
const stageTimings = timings.filter(
135136
// graph has 2 stages, `graph` and `graph_second`
136-
(t) => t.stage === s.name || s.alternativeNames?.includes(t.stage),
137+
(t) =>
138+
t.stage === s.name ||
139+
s.alternativeNames?.includes(t.stage),
137140
);
138-
// console.log(s.name, stageTimings)
139-
const stageRange =
140-
stageTimings.length === 0
141+
142+
143+
const keyedRanges = stageTimings.reduce<Record<string, TimeRange[]>>(
144+
(acc, t) => {
145+
acc[t.stage] = acc[t.stage] || [];
146+
acc[t.stage].push(toTimeRange(t));
147+
return acc;
148+
}, {});
149+
150+
const stageRanges = stageTimings.length === 0
141151
? undefined
142-
: mergeTimeRanges(stageTimings.map(toTimeRange));
152+
: Object.entries(keyedRanges).map(([_, ranges]) => mergeTimeRanges(ranges));
143153

144154
// Prevent users from inspecting internal coder resources in
145155
// provisioner timings because they were not useful to the
@@ -160,7 +170,7 @@ export const WorkspaceTimings: FC<WorkspaceTimingsProps> = ({
160170

161171
return {
162172
stage: s,
163-
range: stageRange,
173+
ranges: stageRanges,
164174
visibleResources: visibleResources.length,
165175
error: stageTimings.some(
166176
(t) => "status" in t && t.status === "exit_failure",

0 commit comments

Comments
 (0)