diff --git a/plugins/devtools-common/src/alpha.ts b/plugins/devtools-common/src/alpha.ts index 984967c4f3..d7f9f94d76 100644 --- a/plugins/devtools-common/src/alpha.ts +++ b/plugins/devtools-common/src/alpha.ts @@ -18,6 +18,7 @@ export { devToolsTaskSchedulerCreatePermission, } from './permissions'; export type { + CancelScheduledTask, ScheduledTasks, TaskApiTasksResponse, TriggerScheduledTask, diff --git a/plugins/devtools-common/src/types.ts b/plugins/devtools-common/src/types.ts index dc35188fde..3879fb1ae3 100644 --- a/plugins/devtools-common/src/types.ts +++ b/plugins/devtools-common/src/types.ts @@ -133,3 +133,8 @@ export type ScheduledTasks = { export type TriggerScheduledTask = { error?: string; }; + +/** @alpha */ +export type CancelScheduledTask = { + error?: string; +}; diff --git a/plugins/devtools/src/api/DevToolsApi.ts b/plugins/devtools/src/api/DevToolsApi.ts index 4fc579ee06..6894a0a8b2 100644 --- a/plugins/devtools/src/api/DevToolsApi.ts +++ b/plugins/devtools/src/api/DevToolsApi.ts @@ -21,6 +21,7 @@ import { ExternalDependency, } from '@backstage/plugin-devtools-common'; import { + CancelScheduledTask, ScheduledTasks, TriggerScheduledTask, } from '@backstage/plugin-devtools-common/alpha'; @@ -38,4 +39,8 @@ export interface DevToolsApi { plugin: string, taskId: string, ): Promise; + cancelScheduledTask( + plugin: string, + taskId: string, + ): Promise; } diff --git a/plugins/devtools/src/api/DevToolsClient.ts b/plugins/devtools/src/api/DevToolsClient.ts index 0577757838..c5b50193ea 100644 --- a/plugins/devtools/src/api/DevToolsClient.ts +++ b/plugins/devtools/src/api/DevToolsClient.ts @@ -21,6 +21,7 @@ import { ExternalDependency, } from '@backstage/plugin-devtools-common'; import { + CancelScheduledTask, ScheduledTasks, TriggerScheduledTask, } from '@backstage/plugin-devtools-common/alpha'; @@ -85,6 +86,27 @@ export class DevToolsClient implements DevToolsApi { return response.json() as Promise; } + public async cancelScheduledTask( + plugin: string, + taskId: string, + ): Promise { + const baseUrl = `${await this.discoveryApi.getBaseUrl(plugin)}/`; + const url = new URL( + `.backstage/scheduler/v1/tasks/${encodeURIComponent(taskId)}/cancel`, + baseUrl, + ); + + const response = await this.fetchApi.fetch(url.toString(), { + method: 'POST', + }); + + if (!response.ok) { + throw await ResponseError.fromResponse(response); + } + + return response.json() as Promise; + } + public async getExternalDependencies(): Promise< ExternalDependency[] | undefined > { diff --git a/plugins/devtools/src/components/Content/ScheduledTasksContent/ScheduledTasksContent.tsx b/plugins/devtools/src/components/Content/ScheduledTasksContent/ScheduledTasksContent.tsx index 7517cf8ea5..d115968a77 100644 --- a/plugins/devtools/src/components/Content/ScheduledTasksContent/ScheduledTasksContent.tsx +++ b/plugins/devtools/src/components/Content/ScheduledTasksContent/ScheduledTasksContent.tsx @@ -29,10 +29,11 @@ import { TableColumn, } from '@backstage/core-components'; import Alert from '@material-ui/lab/Alert'; -import { useScheduledTasks, useTriggerScheduledTask } from '../../../hooks'; +import { useScheduledTasks, useScheduledTasksOperations } from '../../../hooks'; import { TaskApiTasksResponse } from '@backstage/plugin-devtools-common/alpha'; import { alertApiRef, configApiRef, useApi } from '@backstage/core-plugin-api'; import RefreshIcon from '@material-ui/icons/Refresh'; +import StopIcon from '@material-ui/icons/Stop'; import NightsStay from '@material-ui/icons/NightsStay'; import ErrorIcon from '@material-ui/icons/Error'; import BlockIcon from '@material-ui/icons/Block'; @@ -105,7 +106,7 @@ export const ScheduledTasksContent = () => { configApi.getOptionalStringArray('devTools.scheduledTasks.plugins') || []; const [selectedPlugin, setSelectedPlugin] = useState(plugins[0] || ''); const { scheduledTasks, loading, error } = useScheduledTasks(selectedPlugin); - const { triggerTask, isTriggering, triggerError } = useTriggerScheduledTask(); + const { triggerTask, cancelTask, isLoading } = useScheduledTasksOperations(); const [inputValue, setInputValue] = useState(''); @@ -209,28 +210,52 @@ export const ScheduledTasksContent = () => { permission={devToolsTaskSchedulerCreatePermission} errorPage={} > - - { - triggerTask(selectedPlugin, rowData.taskId); - if (triggerError) { - alertApi.post({ - message: `Error triggering task ${rowData.taskId}: ${error}`, - severity: 'error', - }); - } else { - alertApi.post({ - message: `Successfully triggered task ${rowData.taskId}`, - severity: 'success', - }); - } - }} - > - - - + + + { + try { + await triggerTask(selectedPlugin, rowData.taskId); + alertApi.post({ + message: `Successfully triggered task ${rowData.taskId}`, + severity: 'success', + }); + } catch (e) { + alertApi.post({ + message: `Error triggering task ${rowData.taskId}: ${e.message}`, + severity: 'error', + }); + } + }} + > + + + + + { + try { + await cancelTask(selectedPlugin, rowData.taskId); + alertApi.post({ + message: `Successfully cancelled task ${rowData.taskId}`, + severity: 'success', + }); + } catch (e) { + alertApi.post({ + message: `Error cancelling task ${rowData.taskId}: ${e.message}`, + severity: 'error', + }); + } + }} + > + + + + ), sorting: false, diff --git a/plugins/devtools/src/hooks/index.ts b/plugins/devtools/src/hooks/index.ts index 105d03fb68..9d212bc3af 100644 --- a/plugins/devtools/src/hooks/index.ts +++ b/plugins/devtools/src/hooks/index.ts @@ -18,4 +18,4 @@ export { useConfig } from './useConfig'; export { useExternalDependencies } from './useExternalDependencies'; export { useInfo } from './useInfo'; export { useScheduledTasks } from './useScheduledTasks'; -export { useTriggerScheduledTask } from './useTriggerScheduledTask'; +export { useScheduledTasksOperations } from './useScheduledTasksOperations'; diff --git a/plugins/devtools/src/hooks/useTriggerScheduledTask.ts b/plugins/devtools/src/hooks/useScheduledTasksOperations.ts similarity index 66% rename from plugins/devtools/src/hooks/useTriggerScheduledTask.ts rename to plugins/devtools/src/hooks/useScheduledTasksOperations.ts index d26b7a8025..ff9d02b675 100644 --- a/plugins/devtools/src/hooks/useTriggerScheduledTask.ts +++ b/plugins/devtools/src/hooks/useScheduledTasksOperations.ts @@ -17,22 +17,40 @@ import { useState, useCallback } from 'react'; import { devToolsApiRef } from '../api'; import { useApi } from '@backstage/core-plugin-api'; -export const useTriggerScheduledTask = () => { +export const useScheduledTasksOperations = () => { const api = useApi(devToolsApiRef); - const [isTriggering, setIsTriggering] = useState(false); + const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(); const triggerTask = useCallback( async (plugin: string, taskId: string) => { - setIsTriggering(true); + setIsLoading(true); setError(undefined); try { await api.triggerScheduledTask(plugin, taskId); } catch (e) { setError(e); + throw e; } finally { - setIsTriggering(false); + setIsLoading(false); + } + }, + [api], + ); + + const cancelTask = useCallback( + async (plugin: string, taskId: string) => { + setIsLoading(true); + setError(undefined); + + try { + await api.cancelScheduledTask(plugin, taskId); + } catch (e) { + setError(e); + throw e; + } finally { + setIsLoading(false); } }, [api], @@ -40,7 +58,8 @@ export const useTriggerScheduledTask = () => { return { triggerTask, - isTriggering, - triggerError: error?.message, + cancelTask, + isLoading, + error: error?.message, }; };