@@ -33,6 +33,7 @@ import {
3333 WorkspaceTreeProvider ,
3434} from "./treeView" ;
3535import {
36+ cancelPendingJob ,
3637 getAzurePortalWorkspaceLink ,
3738 getJobFiles ,
3839 getPythonCodeForWorkspace ,
@@ -76,6 +77,7 @@ export async function initAzureWorkspaces(context: vscode.ExtensionContext) {
7677 let supportsQir = false ;
7778 let supportsDownload = false ;
7879 let isWorkspace = false ;
80+ let isCancelable = false ;
7981
8082 if ( e . selection . length === 1 ) {
8183 currentTreeItem = e . selection [ 0 ] as WorkspaceTreeItem ;
@@ -90,6 +92,9 @@ export async function initAzureWorkspaces(context: vscode.ExtensionContext) {
9092 if ( job . status === "Succeeded" && job . outputDataUri ) {
9193 supportsDownload = true ;
9294 }
95+ if ( job . status === "Waiting" || job . status === "Executing" ) {
96+ isCancelable = true ;
97+ }
9398 }
9499 if ( currentTreeItem . type === "workspace" ) {
95100 isWorkspace = true ;
@@ -113,6 +118,11 @@ export async function initAzureWorkspaces(context: vscode.ExtensionContext) {
113118 `${ qsharpExtensionId } .treeItemIsWorkspace` ,
114119 isWorkspace ,
115120 ) ;
121+ await vscode . commands . executeCommand (
122+ "setContext" ,
123+ `${ qsharpExtensionId } .treeItemIsCancelable` ,
124+ isCancelable ,
125+ ) ;
116126 } ) ,
117127 ) ;
118128
@@ -236,6 +246,43 @@ export async function initAzureWorkspaces(context: vscode.ExtensionContext) {
236246 ) ,
237247 ) ;
238248
249+ async function cancelJob ( arg ?: WorkspaceTreeItem ) {
250+ // Could be run via the treeItem icon or the menu command.
251+ const treeItem = arg || currentTreeItem ;
252+ if ( treeItem ?. type !== "job" ) return ;
253+
254+ const job = treeItem . itemData as Job ;
255+
256+ // Confirm cancellation with the user
257+ const confirm = await vscode . window . showWarningMessage (
258+ `Are you sure you want to cancel the job "${ job . name } "?` ,
259+ { modal : true } ,
260+ { title : "Yes" , isCloseAffordance : false } ,
261+ { title : "No" , isCloseAffordance : true } ,
262+ ) ;
263+ if ( confirm ?. title !== "Yes" ) return ;
264+
265+ try {
266+ // Get the token
267+ const token = await getTokenForWorkspace ( treeItem . workspace ) ;
268+ if ( ! token ) throw "Unable to get an authentication token" ;
269+
270+ // Call the network request
271+ await cancelPendingJob ( treeItem . workspace , token , job . id ) ;
272+
273+ // Report success/failure to the user
274+ vscode . window . showInformationMessage (
275+ "The cancel request has been submitted." ,
276+ ) ;
277+ } catch ( e : any ) {
278+ log . error ( "Failed to cancel the job: " , e ) ;
279+ vscode . window . showErrorMessage ( "Failed to cancel the job." , {
280+ modal : true ,
281+ detail : e instanceof Error ? e . message : undefined ,
282+ } ) ;
283+ }
284+ }
285+
239286 async function downloadResults ( arg ?: WorkspaceTreeItem , showText ?: boolean ) {
240287 // Could be run via the treeItem icon or the menu command.
241288 const treeItem = arg || currentTreeItem ;
@@ -287,6 +334,13 @@ export async function initAzureWorkspaces(context: vscode.ExtensionContext) {
287334 }
288335 }
289336
337+ context . subscriptions . push (
338+ vscode . commands . registerCommand (
339+ `${ qsharpExtensionId } .cancelJob` ,
340+ async ( arg : WorkspaceTreeItem ) => await cancelJob ( arg ) ,
341+ ) ,
342+ ) ;
343+
290344 context . subscriptions . push (
291345 vscode . commands . registerCommand (
292346 `${ qsharpExtensionId } .downloadResults` ,
0 commit comments