@@ -3,13 +3,18 @@ import {
33 type WorkspaceAgent ,
44} from "coder/site/src/api/typesGenerated" ;
55import * as fs from "node:fs/promises" ;
6+ import * as os from "node:os" ;
67import * as path from "node:path" ;
78import * as semver from "semver" ;
89import * as vscode from "vscode" ;
910
1011import { createWorkspaceIdentifier , extractAgents } from "./api/api-helper" ;
1112import { type CoderApi } from "./api/coderApi" ;
12- import { getGlobalFlags , resolveCliAuth } from "./cliConfig" ;
13+ import {
14+ getGlobalFlags ,
15+ getGlobalFlagsForExec ,
16+ resolveCliAuth ,
17+ } from "./cliConfig" ;
1318import { type CliManager } from "./core/cliManager" ;
1419import * as cliUtils from "./core/cliUtils" ;
1520import { type ServiceContainer } from "./core/container" ;
@@ -22,7 +27,7 @@ import { toError } from "./error/errorUtils";
2227import { featureSetForVersion } from "./featureSet" ;
2328import { type Logger } from "./logging/logger" ;
2429import { type LoginCoordinator } from "./login/loginCoordinator" ;
25- import { withProgress } from "./progress" ;
30+ import { withCancellableProgress , withProgress } from "./progress" ;
2631import { maybeAskAgent , maybeAskUrl } from "./promptUtils" ;
2732import {
2833 RECOMMENDED_SSH_SETTINGS ,
@@ -147,21 +152,32 @@ export class Commands {
147152 }
148153
149154 /**
150- * Run a speed test against the currently connected workspace and display the
151- * results in a new editor document .
155+ * Run a speed test against the currently connected workspace and save the
156+ * results to a file chosen by the user .
152157 */
153158 public async speedTest ( ) : Promise < void > {
154- if ( ! this . workspace ) {
159+ const workspace = this . workspace ;
160+ if ( ! workspace ) {
155161 vscode . window . showInformationMessage ( "No workspace connected." ) ;
156162 return ;
157163 }
158164
159- await withProgress (
160- {
161- location : vscode . ProgressLocation . Notification ,
162- title : "Running speed test..." ,
165+ const duration = await vscode . window . showInputBox ( {
166+ title : "Speed Test Duration" ,
167+ prompt : "Duration for the speed test (e.g., 5s, 10s, 1m)" ,
168+ value : "5s" ,
169+ validateInput : ( v ) => {
170+ return / ^ \d + [ s m ] $ / . test ( v . trim ( ) )
171+ ? null
172+ : "Enter a duration like 5s, 10s, or 1m" ;
163173 } ,
164- async ( ) => {
174+ } ) ;
175+ if ( duration === undefined ) {
176+ return ;
177+ }
178+
179+ const result = await withCancellableProgress (
180+ async ( { signal } ) => {
165181 const baseUrl = this . requireExtensionBaseUrl ( ) ;
166182 const safeHost = toSafeHost ( baseUrl ) ;
167183 const binary = await this . cliManager . fetchBinary ( this . extensionClient ) ;
@@ -170,27 +186,54 @@ export class Commands {
170186 const configDir = this . pathResolver . getGlobalConfigDir ( safeHost ) ;
171187 const configs = vscode . workspace . getConfiguration ( ) ;
172188 const auth = resolveCliAuth ( configs , featureSet , baseUrl , configDir ) ;
173- const workspaceName = createWorkspaceIdentifier ( this . workspace ! ) ;
189+ const globalFlags = getGlobalFlagsForExec ( configs , auth ) ;
190+ const workspaceName = createWorkspaceIdentifier ( workspace ) ;
174191
175- try {
176- const stdout = await cliUtils . speedtest (
177- binary ,
178- auth ,
179- workspaceName ,
180- ) ;
181- const doc = await vscode . workspace . openTextDocument ( {
182- content : stdout ,
183- language : "json" ,
184- } ) ;
185- await vscode . window . showTextDocument ( doc ) ;
186- } catch ( error ) {
187- this . logger . error ( "Speed test failed" , error ) ;
188- vscode . window . showErrorMessage (
189- `Speed test failed: ${ error instanceof Error ? error . message : String ( error ) } ` ,
190- ) ;
191- }
192+ return cliUtils . speedtest ( binary , globalFlags , workspaceName , {
193+ signal,
194+ duration : duration . trim ( ) ,
195+ } ) ;
196+ } ,
197+ {
198+ location : vscode . ProgressLocation . Notification ,
199+ title : `Running speed test (${ duration . trim ( ) } )...` ,
200+ cancellable : true ,
192201 } ,
193202 ) ;
203+
204+ if ( ! result . ok ) {
205+ if ( ! result . cancelled ) {
206+ this . logger . error ( "Speed test failed" , result . error ) ;
207+ vscode . window . showErrorMessage (
208+ `Speed test failed: ${ result . error instanceof Error ? result . error . message : String ( result . error ) } ` ,
209+ ) ;
210+ }
211+ return ;
212+ }
213+
214+ const defaultName = `speedtest-${ workspace . name } -${ new Date ( ) . toISOString ( ) . slice ( 0 , 10 ) } .json` ;
215+ const defaultUri = vscode . Uri . joinPath (
216+ vscode . workspace . workspaceFolders ?. [ 0 ] ?. uri ??
217+ vscode . Uri . file ( os . homedir ( ) ) ,
218+ defaultName ,
219+ ) ;
220+ const uri = await vscode . window . showSaveDialog ( {
221+ defaultUri,
222+ filters : { JSON : [ "json" ] } ,
223+ } ) ;
224+ if ( ! uri ) {
225+ return ;
226+ }
227+
228+ await vscode . workspace . fs . writeFile ( uri , Buffer . from ( result . value ) ) ;
229+ const action = await vscode . window . showInformationMessage (
230+ "Speed test results saved." ,
231+ "Open File" ,
232+ ) ;
233+ if ( action === "Open File" ) {
234+ const doc = await vscode . workspace . openTextDocument ( uri ) ;
235+ await vscode . window . showTextDocument ( doc ) ;
236+ }
194237 }
195238
196239 /**
0 commit comments