Merge pull request #33298 from backstage/freben/devtools-cancel-task
devtools: Add cancel task operation to scheduled tasks
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-devtools-common': patch
|
||||
'@backstage/plugin-devtools': patch
|
||||
---
|
||||
|
||||
Added `cancelScheduledTask` to the DevTools API and a cancel button to the scheduled tasks UI.
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export {
|
||||
devToolsTaskSchedulerReadPermission,
|
||||
devToolsTaskSchedulerCreatePermission,
|
||||
|
||||
@@ -38,4 +38,5 @@ export interface DevToolsApi {
|
||||
plugin: string,
|
||||
taskId: string,
|
||||
): Promise<TriggerScheduledTask>;
|
||||
cancelScheduledTask(plugin: string, taskId: string): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
ScheduledTasks,
|
||||
TriggerScheduledTask,
|
||||
} from '@backstage/plugin-devtools-common/alpha';
|
||||
import { ResponseError } from '@backstage/errors';
|
||||
import { ResponseError, NotFoundError, ConflictError } from '@backstage/errors';
|
||||
import { DevToolsApi } from './DevToolsApi';
|
||||
|
||||
export class DevToolsClient implements DevToolsApi {
|
||||
@@ -82,7 +82,31 @@ export class DevToolsClient implements DevToolsApi {
|
||||
throw await ResponseError.fromResponse(response);
|
||||
}
|
||||
|
||||
return response.json() as Promise<TriggerScheduledTask>;
|
||||
return {};
|
||||
}
|
||||
|
||||
public async cancelScheduledTask(
|
||||
plugin: string,
|
||||
taskId: string,
|
||||
): Promise<void> {
|
||||
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) {
|
||||
if (response.status === 404) {
|
||||
throw new NotFoundError(`Task ${taskId} not found`);
|
||||
} else if (response.status === 409) {
|
||||
throw new ConflictError(`Task ${taskId} is not running`);
|
||||
}
|
||||
throw await ResponseError.fromResponse(response);
|
||||
}
|
||||
}
|
||||
|
||||
public async getExternalDependencies(): Promise<
|
||||
|
||||
+52
-26
@@ -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={<CreateNotAllowed />}
|
||||
>
|
||||
<Tooltip title="Run Task">
|
||||
<IconButton
|
||||
aria-label="Trigger"
|
||||
disabled={isTriggering}
|
||||
onClick={() => {
|
||||
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',
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<RefreshIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Box display="flex" justifyContent="center">
|
||||
<Tooltip title="Run Task">
|
||||
<IconButton
|
||||
aria-label="Trigger"
|
||||
disabled={isLoading}
|
||||
onClick={async () => {
|
||||
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',
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<RefreshIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Cancel Task">
|
||||
<IconButton
|
||||
aria-label="Cancel"
|
||||
disabled={isLoading}
|
||||
onClick={async () => {
|
||||
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',
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<StopIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
</RequirePermission>
|
||||
),
|
||||
sorting: false,
|
||||
@@ -263,7 +288,7 @@ export const ScheduledTasksContent = () => {
|
||||
)}
|
||||
/>
|
||||
|
||||
{loading && <Progress />}
|
||||
{loading && !scheduledTasks && <Progress />}
|
||||
|
||||
{error && (
|
||||
<ErrorPanel
|
||||
@@ -292,7 +317,7 @@ export const ScheduledTasksContent = () => {
|
||||
</ErrorPanel>
|
||||
)}
|
||||
|
||||
{!loading && !error && (
|
||||
{scheduledTasks && (
|
||||
<Table
|
||||
title={`Scheduled Tasks (${selectedPlugin})`}
|
||||
options={{
|
||||
@@ -300,6 +325,7 @@ export const ScheduledTasksContent = () => {
|
||||
search: true,
|
||||
sorting: true,
|
||||
searchFieldAlignment: 'right',
|
||||
padding: 'dense',
|
||||
}}
|
||||
columns={columns}
|
||||
data={scheduledTasks || []}
|
||||
|
||||
@@ -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';
|
||||
|
||||
+25
-6
@@ -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<Error | undefined>();
|
||||
|
||||
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,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user