From eb453959f4c2eed26ec7511d94f71afc0cd6c61c Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Tue, 22 Apr 2025 16:45:53 +0000 Subject: [PATCH 1/2] fix: build timeline scale for longer builds --- .../workspaces/WorkspaceTiming/Chart/utils.ts | 40 ++++++++++++++++++- .../WorkspaceTimings.stories.tsx | 26 ++++++++++++ .../WorkspaceTiming/WorkspaceTimings.tsx | 9 ++++- 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/site/src/modules/workspaces/WorkspaceTiming/Chart/utils.ts b/site/src/modules/workspaces/WorkspaceTiming/Chart/utils.ts index 45c6f5bf681d1..dcfb546842292 100644 --- a/site/src/modules/workspaces/WorkspaceTiming/Chart/utils.ts +++ b/site/src/modules/workspaces/WorkspaceTiming/Chart/utils.ts @@ -29,7 +29,20 @@ export const calcDuration = (range: TimeRange): number => { // data in 200ms intervals. However, if the total time is 1 minute, we should // display the data in 5 seconds intervals. To achieve this, we define the // dimensions object that contains the time intervals for the chart. -const scales = [5_000, 500, 100]; +const second = 1_000; +const minute = 60 * second; +const hour = 60 * minute; +const day = 24 * hour; +const scales = [ + day, + hour, + 5 * minute, + minute, + 10 * second, + 5 * second, + 500, + 100, +]; const pickScale = (totalTime: number): number => { for (const s of scales) { @@ -48,7 +61,30 @@ export const makeTicks = (time: number) => { }; export const formatTime = (time: number): string => { - return `${time.toLocaleString()}ms`; + const seconds = Math.floor((time / 1000) % 60); + const minutes = Math.floor((time / (1000 * 60)) % 60); + const hours = Math.floor((time / (1000 * 60 * 60)) % 24); + const days = Math.floor(time / (1000 * 60 * 60 * 24)); + + const timeParts = []; + + if (days > 0) { + timeParts.push(`${days} day${days > 1 ? "s" : ""}`); + } + if (hours > 0) { + timeParts.push(`${hours} hour${hours > 1 ? "s" : ""}`); + } + if (minutes > 0) { + timeParts.push(`${minutes} minute${minutes > 1 ? "s" : ""}`); + } + if (seconds > 0) { + timeParts.push(`${seconds}s`); + } + if (time > 0 && time < 1000) { + timeParts.push(`${time}ms`); + } + + return timeParts.join(", "); }; export const calcOffset = (range: TimeRange, baseRange: TimeRange): number => { diff --git a/site/src/modules/workspaces/WorkspaceTiming/WorkspaceTimings.stories.tsx b/site/src/modules/workspaces/WorkspaceTiming/WorkspaceTimings.stories.tsx index 0210353488257..9c93b4bf6806e 100644 --- a/site/src/modules/workspaces/WorkspaceTiming/WorkspaceTimings.stories.tsx +++ b/site/src/modules/workspaces/WorkspaceTiming/WorkspaceTimings.stories.tsx @@ -126,3 +126,29 @@ export const LoadingWhenAgentScriptTimingsAreEmpty: Story = { agentScriptTimings: undefined, }, }; + +export const LongTimeRange = { + args: { + provisionerTimings: [ + { + ...WorkspaceTimingsResponse.provisioner_timings[0], + started_at: "2021-09-01T00:00:00Z", + ended_at: "2021-09-01T00:10:00Z", + }, + ], + agentConnectionTimings: [ + { + ...WorkspaceTimingsResponse.agent_connection_timings[0], + started_at: "2021-09-01T00:10:00Z", + ended_at: "2021-09-01T00:35:00Z", + }, + ], + agentScriptTimings: [ + { + ...WorkspaceTimingsResponse.agent_script_timings[0], + started_at: "2021-09-01T00:35:00Z", + ended_at: "2021-09-01T01:00:00Z", + }, + ], + }, +}; diff --git a/site/src/modules/workspaces/WorkspaceTiming/WorkspaceTimings.tsx b/site/src/modules/workspaces/WorkspaceTiming/WorkspaceTimings.tsx index 63fc03ad2a3de..2cb0a7c20d5d8 100644 --- a/site/src/modules/workspaces/WorkspaceTiming/WorkspaceTimings.tsx +++ b/site/src/modules/workspaces/WorkspaceTiming/WorkspaceTimings.tsx @@ -12,7 +12,12 @@ import type { import sortBy from "lodash/sortBy"; import uniqBy from "lodash/uniqBy"; import { type FC, useState } from "react"; -import { type TimeRange, calcDuration, mergeTimeRanges } from "./Chart/utils"; +import { + type TimeRange, + calcDuration, + formatTime, + mergeTimeRanges, +} from "./Chart/utils"; import { ResourcesChart, isCoderResource } from "./ResourcesChart"; import { ScriptsChart } from "./ScriptsChart"; import { @@ -85,7 +90,7 @@ export const WorkspaceTimings: FC = ({ const displayProvisioningTime = () => { const totalRange = mergeTimeRanges(timings.map(toTimeRange)); const totalDuration = calcDuration(totalRange); - return humanizeDuration(totalDuration); + return formatTime(totalDuration); }; return ( From ef7226cb657cc6131b2f558a2847addc637d6a51 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Tue, 22 Apr 2025 17:22:23 +0000 Subject: [PATCH 2/2] Fix format --- .../workspaces/WorkspaceTiming/Chart/utils.ts | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/site/src/modules/workspaces/WorkspaceTiming/Chart/utils.ts b/site/src/modules/workspaces/WorkspaceTiming/Chart/utils.ts index dcfb546842292..55df5b9ffad48 100644 --- a/site/src/modules/workspaces/WorkspaceTiming/Chart/utils.ts +++ b/site/src/modules/workspaces/WorkspaceTiming/Chart/utils.ts @@ -61,30 +61,29 @@ export const makeTicks = (time: number) => { }; export const formatTime = (time: number): string => { - const seconds = Math.floor((time / 1000) % 60); - const minutes = Math.floor((time / (1000 * 60)) % 60); - const hours = Math.floor((time / (1000 * 60 * 60)) % 24); - const days = Math.floor(time / (1000 * 60 * 60 * 24)); - - const timeParts = []; + const seconds = Math.floor(time / 1000); + const minutes = Math.floor(seconds / 60); + const hours = Math.floor(minutes / 60); + const days = Math.floor(hours / 24); + const parts: string[] = []; if (days > 0) { - timeParts.push(`${days} day${days > 1 ? "s" : ""}`); + parts.push(`${days}d`); } if (hours > 0) { - timeParts.push(`${hours} hour${hours > 1 ? "s" : ""}`); + parts.push(`${hours % 24}h`); } if (minutes > 0) { - timeParts.push(`${minutes} minute${minutes > 1 ? "s" : ""}`); + parts.push(`${minutes % 60}m`); } if (seconds > 0) { - timeParts.push(`${seconds}s`); + parts.push(`${seconds % 60}s`); } - if (time > 0 && time < 1000) { - timeParts.push(`${time}ms`); + if (time % 1000 > 0) { + parts.push(`${time % 1000}ms`); } - return timeParts.join(", "); + return parts.join(" "); }; export const calcOffset = (range: TimeRange, baseRange: TimeRange): number => {