Skip to content

Commit

Permalink
Simplify retry all functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
felixmosh committed Jan 1, 2023
1 parent dd7e3eb commit fec2d72
Show file tree
Hide file tree
Showing 10 changed files with 42 additions and 38 deletions.
5 changes: 3 additions & 2 deletions packages/api/typings/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { BaseAdapter } from '../src/queueAdapters/base';

export type JobCleanStatus = 'completed' | 'wait' | 'active' | 'delayed' | 'failed';

export type JobFinishedStatus = 'completed' | 'failed';
export type JobRetryStatus = 'completed' | 'failed';

export type Status = keyof typeof STATUSES;

Expand All @@ -15,6 +15,7 @@ export type JobCounts = Record<Status, number>;
export interface QueueAdapterOptions {
readOnlyMode: boolean;
allowRetries: boolean;
allowCompletedRetries: boolean;
prefix: string;
description: string;
}
Expand All @@ -30,7 +31,7 @@ export interface QueueJob {

remove(): Promise<void>;

retry(state?: JobFinishedStatus): Promise<void>;
retry(state?: JobRetryStatus): Promise<void>;

toJSON(): QueueJobJson;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const App = () => {
path="/queue/:name"
render={() => (
<QueuePage
queue={activeQueue || undefined}
queue={activeQueue || null}
actions={actions}
selectedStatus={selectedStatuses}
/>
Expand Down
20 changes: 8 additions & 12 deletions packages/ui/src/components/JobCard/JobActions/JobActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,44 +13,40 @@ interface JobActionsProps {
allowRetries: boolean;
actions: {
promoteJob: () => Promise<void>;
retryFailedJob: () => Promise<void>;
retryCompletedJob: () => Promise<void>;
retryJob: () => Promise<void>;
cleanJob: () => Promise<void>;
};
}

interface ButtonType {
title: string;
Icon: React.ElementType;
actionKey: 'promoteJob' | 'cleanJob' | 'retryFailedJob' | 'retryCompletedJob';
actionKey: 'promoteJob' | 'cleanJob' | 'retryJob';
}

const buttonTypes: Record<string, ButtonType> = {
promote: { title: 'Promote', Icon: PromoteIcon, actionKey: 'promoteJob' },
clean: { title: 'Clean', Icon: TrashIcon, actionKey: 'cleanJob' },
retryFailed: { title: 'Retry', Icon: RetryIcon, actionKey: 'retryFailedJob' },
retryCompleted: { title: 'Retry', Icon: RetryIcon, actionKey: 'retryCompletedJob' },
retry: { title: 'Retry', Icon: RetryIcon, actionKey: 'retryJob' },
};

const statusToButtonsMap: Record<string, ButtonType[]> = {
[STATUSES.failed]: [buttonTypes.retryFailed, buttonTypes.clean],
[STATUSES.failed]: [buttonTypes.retry, buttonTypes.clean],
[STATUSES.delayed]: [buttonTypes.promote, buttonTypes.clean],
[STATUSES.completed]: [buttonTypes.retryCompleted, buttonTypes.clean],
[STATUSES.completed]: [buttonTypes.retry, buttonTypes.clean],
[STATUSES.waiting]: [buttonTypes.clean],
};

function isRetry(actionKey: ButtonType['actionKey']) {
return ['retryFailedJob', 'retryCompletedJob'].includes(actionKey);
}

export const JobActions = ({ actions, status, allowRetries }: JobActionsProps) => {
let buttons = statusToButtonsMap[status];
if (!buttons) {
return null;
}

if (!allowRetries) {
buttons = buttons.filter((btn) => !isRetry(btn.actionKey));
buttons = buttons.filter((btn) => btn.actionKey !== 'retryJob');
}

return (
<ul className={s.jobActions}>
{buttons.map((type) => (
Expand Down
3 changes: 1 addition & 2 deletions packages/ui/src/components/JobCard/JobCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ interface JobCardProps {
allowRetries: boolean;
actions: {
promoteJob: () => Promise<void>;
retryFailedJob: () => Promise<void>;
retryCompletedJob: () => Promise<void>;
retryJob: () => Promise<void>;
cleanJob: () => Promise<void>;
getJobLogs: () => Promise<string[]>;
};
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/src/components/QueueActions/QueueActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const QueueActions = ({ status, actions, queue, allowRetries }: QueueActi
<>
{allowRetries && (
<li>
<RetryAllButton onClick={actions.retryAllFailed(queue.name)} />
<RetryAllButton onClick={actions.retryAll(queue.name, status)} />
</li>
)}
<li>
Expand All @@ -60,7 +60,7 @@ export const QueueActions = ({ status, actions, queue, allowRetries }: QueueActi
<>
{allowRetries && (
<li>
<RetryAllButton onClick={actions.retryAllCompleted(queue.name)} />
<RetryAllButton onClick={actions.retryAll(queue.name, status)} />
</li>
)}
<li>
Expand Down
16 changes: 10 additions & 6 deletions packages/ui/src/components/QueuePage/QueuePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,24 @@ import { JobCard } from '../JobCard/JobCard';
import { QueueActions } from '../QueueActions/QueueActions';
import { StatusMenu } from '../StatusMenu/StatusMenu';
import s from './QueuePage.module.css';
import { AppQueue } from '@bull-board/api/typings/app';
import { AppQueue, JobRetryStatus } from '@bull-board/api/typings/app';
import { Pagination } from '../Pagination/Pagination';

export const QueuePage = ({
selectedStatus,
actions,
queue,
}: {
queue: AppQueue | undefined;
queue: AppQueue | null;
actions: Store['actions'];
selectedStatus: Store['selectedStatuses'];
}) => {
if (!queue) {
return <section>Queue Not found</section>;
}

const status = selectedStatus[queue.name];

return (
<section>
<div className={s.stickyHeader}>
Expand All @@ -31,7 +33,10 @@ export const QueuePage = ({
queue={queue}
actions={actions}
status={selectedStatus[queue.name]}
allowRetries={(selectedStatus[queue.name] == 'failed' || queue.allowCompletedRetries) && queue.allowRetries}
allowRetries={
(selectedStatus[queue.name] == 'failed' || queue.allowCompletedRetries) &&
queue.allowRetries
}
/>
)}
</div>
Expand All @@ -42,12 +47,11 @@ export const QueuePage = ({
<JobCard
key={job.id}
job={job}
status={selectedStatus[queue.name]}
status={status}
actions={{
cleanJob: actions.cleanJob(queue?.name)(job),
promoteJob: actions.promoteJob(queue?.name)(job),
retryFailedJob: actions.retryJob(queue?.name)(job, 'failed'),
retryCompletedJob: actions.retryJob(queue?.name)(job, 'completed'),
retryJob: actions.retryJob(queue?.name, status as JobRetryStatus)(job),
getJobLogs: actions.getJobLogs(queue?.name)(job),
}}
readOnlyMode={queue?.readOnlyMode}
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/QueueTitle/QueueTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React from 'react';
import s from './QueueTitle.module.css';

interface QueueTitleProps {
queue: AppQueue;
queue: Pick<AppQueue, 'name' | 'description'>;
}
export const QueueTitle = ({ queue }: QueueTitleProps) => (
<div className={s.queueTitle}>
Expand Down
8 changes: 4 additions & 4 deletions packages/ui/src/hooks/useStore.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AppJob, JobFinishedStatus } from '@bull-board/api/typings/app';
import { AppJob, JobRetryStatus } from '@bull-board/api/typings/app';
import { GetQueuesResponse } from '@bull-board/api/typings/responses';
import { useState } from 'react';
import { QueueActions, SelectedStatuses } from '../../typings/app';
Expand Down Expand Up @@ -88,7 +88,7 @@ export const useStore = (): Store => {
confirmJobActions
);

const retryJob = (queueName: string) => (job: AppJob, status: JobFinishedStatus) =>
const retryJob = (queueName: string, status: JobRetryStatus) => (job: AppJob) =>
withConfirmAndUpdate(
() => api.retryJob(queueName, job.id, status),
'Are you sure that you want to retry this job?',
Expand All @@ -102,7 +102,7 @@ export const useStore = (): Store => {
confirmJobActions
);

const retryAll = (queueName: string, status: JobFinishedStatus) =>
const retryAll = (queueName: string, status: JobRetryStatus) =>
withConfirmAndUpdate(
() => api.retryAll(queueName, status),
`Are you sure that you want to retry all ${status} jobs?`,
Expand Down Expand Up @@ -150,7 +150,7 @@ export const useStore = (): Store => {
'Are you sure that you want to empty the queue?',
confirmQueueActions
);

const getJobLogs = (queueName: string) => (job: AppJob) => () =>
api.getJobLogs(queueName, job.id);

Expand Down
14 changes: 9 additions & 5 deletions packages/ui/src/services/Api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AppJob, JobFinishedStatus, RedisStats, Status } from '@bull-board/api/typings/app';
import { AppJob, JobRetryStatus, RedisStats, Status } from '@bull-board/api/typings/app';
import { GetQueuesResponse } from '@bull-board/api/typings/responses';
import Axios, { AxiosInstance, AxiosResponse } from 'axios';
import { toast } from 'react-toastify';
Expand All @@ -25,8 +25,10 @@ export class Api {
return this.axios.get(`/queues`, { params: { activeQueue, status, page, jobsPerPage } });
}

public retryAll(queueName: string, status: JobFinishedStatus): Promise<void> {
return this.axios.put(`/queues/${encodeURIComponent(queueName)}/retry/${encodeURIComponent(status)}`);
public retryAll(queueName: string, status: JobRetryStatus): Promise<void> {
return this.axios.put(
`/queues/${encodeURIComponent(queueName)}/retry/${encodeURIComponent(status)}`
);
}

public cleanAllDelayed(queueName: string): Promise<void> {
Expand All @@ -47,9 +49,11 @@ export class Api {
);
}

public retryJob(queueName: string, jobId: AppJob['id'], status: JobFinishedStatus): Promise<void> {
public retryJob(queueName: string, jobId: AppJob['id'], status: JobRetryStatus): Promise<void> {
return this.axios.put(
`/queues/${encodeURIComponent(queueName)}/${encodeURIComponent(`${jobId}`)}/retry/${encodeURIComponent(status)}`,
`/queues/${encodeURIComponent(queueName)}/${encodeURIComponent(
`${jobId}`
)}/retry/${encodeURIComponent(status)}`
);
}

Expand Down
6 changes: 3 additions & 3 deletions packages/ui/typings/app.d.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { AppJob, AppQueue, JobFinishedStatus, Status } from '@bull-board/api/typings/app';
import { AppJob, AppQueue, JobRetryStatus, Status } from '@bull-board/api/typings/app';

export { Status } from '@bull-board/api/typings/app';

export type SelectedStatuses = Record<AppQueue['name'], Status>;

export interface QueueActions {
promoteJob: (queueName: string) => (job: AppJob) => () => Promise<void>;
retryJob: (queueName: string) => (job: AppJob, status: JobFinishedStatus) => () => Promise<void>;
retryJob: (queueName: string, status: JobRetryStatus) => (job: AppJob) => () => Promise<void>;
cleanJob: (queueName: string) => (job: AppJob) => () => Promise<void>;
getJobLogs: (queueName: string) => (job: AppJob) => () => Promise<string[]>;
retryAll: (queueName: string, status: JobFinishedStatus) => () => Promise<void>;
retryAll: (queueName: string, status: JobRetryStatus) => () => Promise<void>;
cleanAllDelayed: (queueName: string) => () => Promise<void>;
cleanAllFailed: (queueName: string) => () => Promise<void>;
cleanAllCompleted: (queueName: string) => () => Promise<void>;
Expand Down

0 comments on commit fec2d72

Please sign in to comment.