Skip to content

Commit

Permalink
F/692 pause resume jobs at once (#868)
Browse files Browse the repository at this point in the history
* feat(OverviewActions): add OverviewActions component with pause and resume functionality; update OverviewPage layout and styles

- Introduced a new `OverviewActions` component that provides pause and resume actions for queues.
- Updated `OverviewPage` to include the new `OverviewActions` component in the header.
- Enhanced CSS for the header layout to improve UI alignment and spacing.
- Added new translation keys for pause and resume actions in the localization files.

* feat(OverviewActions): integrate pause and resume actions into OverviewActions component

- Updated the OverviewActions component to accept actions as props, enabling pause and resume functionality for queues.
- Implemented pauseAll and resumeAll actions in the useQueues hook.
- Modified OverviewPage to pass the actions prop to OverviewActions, enhancing the user interface for queue management.

* feat(api): add pause and resume queue functionality

- Introduced `pauseAllHandler` and `resumeAllHandler` to handle pausing and resuming all queues.
- Updated `appRoutes` to include new API endpoints for pausing and resuming queues.
- Enhanced `useQueues` hook to integrate API calls for pausing and resuming queues with user confirmation.
- Added corresponding methods in the `Api` service for making requests to the new endpoints.

* refactor: renamed component

OverviewActions is renamed to OverviewDropDownActions

* feat: check for the queue pause state before resuming or pausing

---------

Co-authored-by: ahmad anwar <[email protected]>
  • Loading branch information
ahnwarez and ahnwarez authored Jan 19, 2025
1 parent 11cf428 commit 62ecfbb
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 3 deletions.
13 changes: 13 additions & 0 deletions packages/api/src/handlers/pauseAll.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { BullBoardRequest, ControllerHandlerReturnType } from '../../typings/app';

async function pauseAll(req: BullBoardRequest): Promise<ControllerHandlerReturnType> {
req.queues.forEach(async (queue) => {
const isPaused = await queue.isPaused();
if (!isPaused) {
queue.pause();
}
});
return { status: 200, body: { message: 'All queues paused' } };
}

export const pauseAllHandler = pauseAll;
13 changes: 13 additions & 0 deletions packages/api/src/handlers/resumeAll.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { BullBoardRequest, ControllerHandlerReturnType } from '../../typings/app';

async function resumeAll(req: BullBoardRequest): Promise<ControllerHandlerReturnType> {
req.queues.forEach(async (queue) => {
const isPaused = await queue.isPaused();
if (isPaused) {
await queue.resume();
}
});
return { status: 200, body: { message: 'All queues resumed' } };
}

export const resumeAllHandler = resumeAll;
4 changes: 4 additions & 0 deletions packages/api/src/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { retryAllHandler } from './handlers/retryAll';
import { retryJobHandler } from './handlers/retryJob';
import { promoteAllHandler } from './handlers/promoteAll';
import { updateJobDataHandler } from './handlers/updateJobData';
import { pauseAllHandler } from './handlers/pauseAll';
import { resumeAllHandler } from './handlers/resumeAll';

export const appRoutes: AppRouteDefs = {
entryPoint: {
Expand All @@ -25,6 +27,8 @@ export const appRoutes: AppRouteDefs = {
api: [
{ method: 'get', route: '/api/redis/stats', handler: redisStatsHandler },
{ method: 'get', route: '/api/queues', handler: queuesHandler },
{ method: 'put', route: '/api/queues/pause', handler: pauseAllHandler },
{ method: 'put', route: '/api/queues/resume', handler: resumeAllHandler },
{
method: 'get',
route: '/api/queues/:queueName/:jobId/logs',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from 'react';
import { Item, Portal, Root, Trigger } from '@radix-ui/react-dropdown-menu';
import { Button } from '../Button/Button';
import { DropdownContent } from '../DropdownContent/DropdownContent';
import { EllipsisVerticalIcon } from '../Icons/EllipsisVertical';
import { PauseIcon } from '../Icons/Pause';
import { PlayIcon } from '../Icons/Play';
import { useTranslation } from 'react-i18next';
import { useQueues } from '../../hooks/useQueues';

export const OverviewActions = ({
actions,
}: {
actions: ReturnType<typeof useQueues>['actions'];
}) => {
const { t } = useTranslation();

return (
<Root>
<Trigger asChild>
<Button>
<EllipsisVerticalIcon />
</Button>
</Trigger>

<Portal>
<DropdownContent align="end">
<Item onClick={actions.pauseAll}>
<PauseIcon />
{t('QUEUE.ACTIONS.PAUSE_ALL')}
</Item>
<Item onClick={actions.resumeAll}>
<PlayIcon />
{t('QUEUE.ACTIONS.RESUME_ALL')}
</Item>
</DropdownContent>
</Portal>
</Root>
);
};

export default OverviewActions;
13 changes: 13 additions & 0 deletions packages/ui/src/hooks/useQueues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,23 @@ export function useQueues(): Omit<QueuesState, 'updateQueues'> & { actions: Queu
jobOptions: Record<any, any>
) => withConfirmAndUpdate(() => api.addJob(queueName, jobName, jobData, jobOptions), '', false);

const pauseAll = withConfirmAndUpdate(
() => api.pauseAllQueues(),
t('QUEUE.ACTIONS.CONFIRM.PAUSE_ALL'),
confirmQueueActions
);
const resumeAll = withConfirmAndUpdate(
() => api.resumeAllQueues(),
t('QUEUE.ACTIONS.CONFIRM.RESUME_ALL'),
confirmQueueActions
);

return {
queues,
loading,
actions: {
pauseAll,
resumeAll,
updateQueues,
pollQueues,
retryAll,
Expand Down
6 changes: 6 additions & 0 deletions packages/ui/src/pages/OverviewPage/OverviewPage.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,9 @@
}
}
}

.header {
display: flex;
justify-content: space-between;
align-items: center;
}
7 changes: 5 additions & 2 deletions packages/ui/src/pages/OverviewPage/OverviewPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useQuery } from '../../hooks/useQuery';
import { useQueues } from '../../hooks/useQueues';
import { links } from '../../utils/links';
import s from './OverviewPage.module.css';
import OverviewDropDownActions from '../../components/OverviewDropDownActions/OverviewDropDownActions';

export const OverviewPage = () => {
const { t } = useTranslation();
Expand All @@ -20,8 +21,10 @@ export const OverviewPage = () => {
queues?.filter((queue) => !selectedStatus || queue.counts[selectedStatus] > 0) || [];
return (
<section>
<StatusLegend />

<div className={s.header}>
<StatusLegend />
<OverviewDropDownActions actions={actions} />
</div>
{queuesToView.length > 0 && (
<ul className={s.overview}>
{queuesToView.map((queue) => (
Expand Down
8 changes: 8 additions & 0 deletions packages/ui/src/services/Api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ export class Api {
return this.axios.put(`/queues/${encodeURIComponent(queueName)}/resume`);
}

public pauseAllQueues() {
return this.axios.put(`/queues/pause`);
}

public resumeAllQueues() {
return this.axios.put(`/queues/resume`);
}

public emptyQueue(queueName: string) {
return this.axios.put(`/queues/${encodeURIComponent(queueName)}/empty`);
}
Expand Down
6 changes: 5 additions & 1 deletion packages/ui/src/static/locales/en-US/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
"CLEAN_ALL": "Clean all",
"RESUME": "Resume",
"PAUSE": "Pause",
"RESUME_ALL": "Resume all",
"PAUSE_ALL": "Pause all",
"EMPTY": "Empty",
"ADD_JOB": "Add job",
"CONFIRM": {
Expand All @@ -72,7 +74,9 @@
"PROMOTE_ALL": "Are you sure that you want to promote all delayed jobs?",
"PAUSE_QUEUE": "Are you sure that you want to pause queue processing?",
"EMPTY_QUEUE": "Are you sure that you want to empty the queue?",
"RESUME_QUEUE": "Are you sure that you want to resume queue processing?"
"RESUME_QUEUE": "Are you sure that you want to resume queue processing?",
"PAUSE_ALL": "Are you sure that you want to pause all queues?",
"RESUME_ALL": "Are you sure that you want to resume all queues?"
}
},
"STATUS": {
Expand Down
2 changes: 2 additions & 0 deletions packages/ui/typings/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export { Status } from '@bull-board/api/typings/app';
export type SelectedStatuses = Record<AppQueue['name'], Status>;

export interface QueueActions {
pauseAll: () => Promise<void>;
resumeAll: () => Promise<void>;
retryAll: (queueName: string, status: JobRetryStatus) => () => Promise<void>;
promoteAll: (queueName: string) => () => Promise<void>;
cleanAll: (queueName: string, status: JobCleanStatus) => () => Promise<void>;
Expand Down

0 comments on commit 62ecfbb

Please sign in to comment.