From ff91e4a59aa36c497d54ed7943d9b657540a397f Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Fri, 2 Sep 2022 17:54:17 +0000 Subject: [PATCH] feat: Add latency indicator to the UI With Tailscale, we now get latency of all regions. --- site/.storybook/main.js | 10 ++- .../ResourceAgentLatency.stories.tsx | 41 ++++++++++++ .../Resources/ResourceAgentLatency.tsx | 63 +++++++++++++++++++ site/src/components/Resources/Resources.tsx | 5 ++ site/src/testHelpers/entities.ts | 24 ++++++- 5 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 site/src/components/Resources/ResourceAgentLatency.stories.tsx create mode 100644 site/src/components/Resources/ResourceAgentLatency.tsx diff --git a/site/.storybook/main.js b/site/.storybook/main.js index 54f5a99d78a40..b25d3aacab6a9 100644 --- a/site/.storybook/main.js +++ b/site/.storybook/main.js @@ -14,7 +14,15 @@ module.exports = { // addons are official and community plugins to extend Storybook. // // SEE: https://storybook.js.org/addons - addons: ["@storybook/addon-links", "@storybook/addon-essentials"], + addons: [ + "@storybook/addon-links", + { + name: "@storybook/addon-essentials", + options: { + actions: false, + }, + }, + ], // Storybook uses babel under the hood, while we currently use ts-loader. // Sometimes, you may encounter an error in a Storybook that contains syntax diff --git a/site/src/components/Resources/ResourceAgentLatency.stories.tsx b/site/src/components/Resources/ResourceAgentLatency.stories.tsx new file mode 100644 index 0000000000000..2e3658c1fda68 --- /dev/null +++ b/site/src/components/Resources/ResourceAgentLatency.stories.tsx @@ -0,0 +1,41 @@ +import { Story } from "@storybook/react" +import { ResourceAgentLatency, ResourceAgentLatencyProps } from "./ResourceAgentLatency" + +export default { + title: "components/ResourceAgentLatency", + component: ResourceAgentLatency, +} + +const Template: Story = (args) => + +export const Single = Template.bind({}) +Single.args = { + latency: { + "Coder DERP": { + latency_ms: 100.52, + preferred: true, + }, + }, +} + +export const Multiple = Template.bind({}) +Multiple.args = { + latency: { + Chicago: { + latency_ms: 22.25551, + preferred: false, + }, + "New York": { + latency_ms: 56.1111, + preferred: true, + }, + "San Francisco": { + latency_ms: 125.11, + preferred: false, + }, + Tokyo: { + latency_ms: 255, + preferred: false, + }, + }, +} diff --git a/site/src/components/Resources/ResourceAgentLatency.tsx b/site/src/components/Resources/ResourceAgentLatency.tsx new file mode 100644 index 0000000000000..fa0fcbecd5ca3 --- /dev/null +++ b/site/src/components/Resources/ResourceAgentLatency.tsx @@ -0,0 +1,63 @@ +import { makeStyles } from "@material-ui/core/styles" +import StarIcon from "@material-ui/icons/Star" +import React from "react" +import { WorkspaceAgent } from "../../api/typesGenerated" +import { HelpTooltip, HelpTooltipText } from "../Tooltips/HelpTooltip" + +export interface ResourceAgentLatencyProps { + latency: WorkspaceAgent["latency"] +} + +export const ResourceAgentLatency: React.FC = (props) => { + const styles = useStyles() + if (Object.keys(props.latency).length === 0) { + return null + } + return ( +
+
+ Latency + + + Latency from relay servers, used when connections cannot connect peer-to-peer. Star + indicates the preferred relay. + + +
+ {Object.keys(props.latency) + .sort() + .map((region) => { + const value = props.latency[region] + return ( +
+ {region}: {Math.round(value.latency_ms * 100) / 100} ms + {value.preferred && } +
+ ) + })} +
+ ) +} + +const useStyles = makeStyles(() => ({ + root: { + display: "grid", + gap: 6, + }, + title: { + fontSize: "Something", + display: "flex", + alignItems: "center", + // This ensures that the latency aligns with other columns in the grid. + height: 20, + }, + region: { + display: "flex", + alignItems: "center", + }, + star: { + width: 14, + height: 14, + marginLeft: 4, + }, +})) diff --git a/site/src/components/Resources/Resources.tsx b/site/src/components/Resources/Resources.tsx index 60c1c9e82625b..91bd788e09f83 100644 --- a/site/src/components/Resources/Resources.tsx +++ b/site/src/components/Resources/Resources.tsx @@ -20,6 +20,7 @@ import { TerminalLink } from "../TerminalLink/TerminalLink" import { AgentHelpTooltip } from "../Tooltips/AgentHelpTooltip" import { AgentOutdatedTooltip } from "../Tooltips/AgentOutdatedTooltip" import { ResourcesHelpTooltip } from "../Tooltips/ResourcesHelpTooltip" +import { ResourceAgentLatency } from "./ResourceAgentLatency" import { ResourceAvatarData } from "./ResourceAvatarData" const Language = { @@ -129,6 +130,9 @@ export const Resources: FC> = ({ {displayVersion} +
+ +
@@ -232,6 +236,7 @@ const useStyles = makeStyles((theme) => ({ gridAutoFlow: "row", whiteSpace: "nowrap", gap: theme.spacing(0.75), + height: "fit-content", }, dataRow: { diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 143bb0c60624b..90e2d7ab8d7f0 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -311,7 +311,12 @@ export const MockWorkspaceAgent: TypesGen.WorkspaceAgent = { status: "connected", updated_at: "", version: MockBuildInfo.version, - latency: {}, + latency: { + "Coder Embedded DERP": { + latency_ms: 32.55, + preferred: true, + }, + }, } export const MockWorkspaceAgentDisconnected: TypesGen.WorkspaceAgent = { @@ -320,6 +325,7 @@ export const MockWorkspaceAgentDisconnected: TypesGen.WorkspaceAgent = { name: "another-workspace-agent", status: "disconnected", version: "", + latency: {}, } export const MockWorkspaceAgentOutdated: TypesGen.WorkspaceAgent = { @@ -328,6 +334,21 @@ export const MockWorkspaceAgentOutdated: TypesGen.WorkspaceAgent = { name: "an-outdated-workspace-agent", version: "v99.999.9998+abcdef", operating_system: "Windows", + latency: { + ...MockWorkspaceAgent.latency, + Chicago: { + preferred: false, + latency_ms: 95.11, + }, + "San Francisco": { + preferred: false, + latency_ms: 111.55, + }, + Paris: { + preferred: false, + latency_ms: 221.66, + }, + }, } export const MockWorkspaceAgentConnecting: TypesGen.WorkspaceAgent = { @@ -336,6 +357,7 @@ export const MockWorkspaceAgentConnecting: TypesGen.WorkspaceAgent = { name: "another-workspace-agent", status: "connecting", version: "", + latency: {}, } export const MockWorkspaceResource: TypesGen.WorkspaceResource = {