Skip to content
This repository has been archived by the owner on Dec 7, 2023. It is now read-only.

Commit

Permalink
feat(ui): bulk remove/retry
Browse files Browse the repository at this point in the history
  • Loading branch information
s-r-x committed May 16, 2021
1 parent d81e9d2 commit 7f8e6be
Show file tree
Hide file tree
Showing 12 changed files with 250 additions and 5 deletions.
4 changes: 3 additions & 1 deletion packages/ui/src/demoMocks/network/mutations/remove-job.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ export const removeJobMock = (
}
return !Boolean(target);
});
return found;
return Promise.resolve({
removeJob: found,
});
};
21 changes: 21 additions & 0 deletions packages/ui/src/demoMocks/network/mutations/remove-jobs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type {
RemoveJobsMutation,
RemoveJobsMutationVariables,
} from '@/typings/gql';
import { networkMockData } from '../data';

export const removeJobsMock = (
args: RemoveJobsMutationVariables,
): Promise<RemoveJobsMutation> => {
const found: any[] = [];
networkMockData.jobs = networkMockData.jobs.filter((job) => {
const target = args.jobs.includes(job.id) && job.queue === args.queue;
if (target) {
found.push(target);
}
return !Boolean(target);
});
return Promise.resolve({
removeJobs: found,
});
};
12 changes: 12 additions & 0 deletions packages/ui/src/demoMocks/network/mutations/retry-jobs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type {
RetryJobsMutation,
RetryJobsMutationVariables,
} from '@/typings/gql';

export const retryJobsMock = (
_args: RetryJobsMutationVariables,
): Promise<RetryJobsMutation> => {
return Promise.resolve({
retryJobs: [],
});
};
20 changes: 20 additions & 0 deletions packages/ui/src/network/mutations/remove-jobs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { gqlClient } from '@/network/gql-client';
import type {
RemoveJobsMutation,
RemoveJobsMutationVariables,
} from '@/typings/gql';
import { gql } from 'graphql-request';

export const removeJobs = (
args: RemoveJobsMutationVariables,
): Promise<RemoveJobsMutation> =>
gqlClient.request(
gql`
mutation RemoveJobs($queue: String!, $jobs: [ID!]!) {
removeJobs(queue: $queue, jobs: $jobs) {
id
}
}
`,
args,
);
20 changes: 20 additions & 0 deletions packages/ui/src/network/mutations/retry-jobs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { gqlClient } from '@/network/gql-client';
import type {
RetryJobsMutation,
RetryJobsMutationVariables,
} from '@/typings/gql';
import { gql } from 'graphql-request';

export const retryJobs = (
args: RetryJobsMutationVariables,
): Promise<RetryJobsMutation> =>
gqlClient.request(
gql`
mutation RetryJobs($queue: String!, $jobs: [ID!]!) {
retryJobs(queue: $queue, jobs: $jobs) {
id
}
}
`,
args,
);
6 changes: 6 additions & 0 deletions packages/ui/src/providers/network/value.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,12 @@ import { removeJobsByPatternMock } from '@/demoMocks/network/mutations/remove-jo
import { removeJobsByPattern } from '@/network/mutations/remove-jobs-by-pattern';
import { cleanQueueMock } from '@/demoMocks/network/mutations/clean-queue';
import { cleanQueue } from '@/network/mutations/clean-queue';
import { retryJobs } from '@/network/mutations/retry-jobs';
import { removeJobs } from '@/network/mutations/remove-jobs';
import { removeJobsMock } from '@/demoMocks/network/mutations/remove-jobs';

import { EnvConfig } from '@/config/env';
import { retryJobsMock } from '@/demoMocks/network/mutations/retry-jobs';

const { useMocks: m } = EnvConfig;

Expand Down Expand Up @@ -76,6 +80,8 @@ const mutations = {
closeQueue: m ? closeQueueMock : closeQueue,
removeJobsByPattern: m ? removeJobsByPatternMock : removeJobsByPattern,
cleanQueue: m ? cleanQueueMock : cleanQueue,
retryJobs: m ? retryJobsMock : retryJobs,
removeJobs: m ? removeJobsMock : removeJobs,
};

export const networkContextValue = { mutations, queries };
5 changes: 3 additions & 2 deletions packages/ui/src/screens/jobs/List/Head.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import shallow from 'zustand/shallow';
import type { GetJobsQuery } from '@/typings/gql';
import isempty from 'lodash/isEmpty';

const actionsWidth = '190';
type TProps = {
jobs?: GetJobsQuery['jobs'];
};
Expand Down Expand Up @@ -41,9 +42,9 @@ export default function TableHead({ jobs }: TProps) {
</TableCell>
<TableCell
style={{
minWidth: '190px',
minWidth: `${actionsWidth}px`,
}}
width="190"
width={actionsWidth}
>
Actions
</TableCell>
Expand Down
97 changes: 97 additions & 0 deletions packages/ui/src/screens/jobs/List/Toolbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from 'react';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import { makeStyles } from '@material-ui/core/styles';
import { useSelectedJobsStore } from '@/stores/selected-jobs';
import ReplayIcon from '@material-ui/icons/Replay';
import DeleteIcon from '@material-ui/icons/Delete';
import IconButton from '@material-ui/core/IconButton';
import Tooltip from '@material-ui/core/Tooltip';
import { useFiltersStore } from '@/stores/filters';
import { JobStatus } from '@/typings/gql';
import { useNetwork } from '@/hooks/use-network';
import { useAbstractMutation } from '@/hooks/use-abstract-mutation';
import { useActiveQueueStore } from '@/stores/active-queue';

const useStyles = makeStyles((theme) => ({
title: {
marginRight: theme.spacing(3),
},
}));

export default function TableToolbar() {
const cls = useStyles();
const activeStatus = useFiltersStore((state) => state.status);
const queue = useActiveQueueStore((state) => state.active as string);
const { mutations } = useNetwork();
const [selectedJobs, clearSelectedJobs] = useSelectedJobsStore((state) => [
state.selected,
state.clear,
]);
const selectedCount = selectedJobs.size;
const removeMutation = useAbstractMutation({
mutation: mutations.removeJobs,
confirm: {
description: 'Delete selected jobs',
},
invalidateSharedQueries: true,
toast: 'Jobs have been removed',
onSuccess: clearSelectedJobs,
});
const retryMutation = useAbstractMutation({
mutation: mutations.retryJobs,
confirm: {
description: 'Retry selected jobs',
},
invalidateSharedQueries: true,
toast: 'Retried',
onSuccess: clearSelectedJobs,
});
return (
<Toolbar>
{selectedCount > 0 ? (
<>
<Typography
className={cls.title}
color="inherit"
variant="subtitle1"
component="div"
>
{selectedCount} selected
</Typography>
{activeStatus === JobStatus.Failed && (
<Tooltip title="Retry selected jobs">
<IconButton
onClick={() =>
retryMutation.mutate({
queue,
jobs: Array.from(selectedJobs),
})
}
>
<ReplayIcon />
</IconButton>
</Tooltip>
)}
<Tooltip title="Delete selected jobs">
<IconButton
onClick={() =>
removeMutation.mutate({
queue,
jobs: Array.from(selectedJobs),
})
}
color="secondary"
>
<DeleteIcon />
</IconButton>
</Tooltip>
</>
) : (
<Typography variant="h6" component="div">
Jobs
</Typography>
)}
</Toolbar>
);
}
2 changes: 2 additions & 0 deletions packages/ui/src/screens/jobs/List/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import JobLogsModal from './Logs';
import { useJobsQuery } from './hooks';
import NetworkRequest from '@/components/NetworkRequest';
import TableHead from './Head';
import TableToolbar from './Toolbar';
import { useSelectedJobsStore } from '@/stores/selected-jobs';
import shallow from 'zustand/shallow';

Expand All @@ -24,6 +25,7 @@ export default function Jobs() {
return (
<Paper>
<NetworkRequest status={status} refetch={refetch}>
<TableToolbar />
<TableContainer>
<Table size="medium">
<TableHead jobs={data?.jobs} />
Expand Down
30 changes: 30 additions & 0 deletions packages/ui/src/stores/selected-jobs.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { useEffect } from 'react';
import createStore from 'zustand';
import { useActiveQueueStore } from './active-queue';
import { useFiltersStore } from './filters';
import shallow from 'zustand/shallow';
import { usePaginationStore } from './pagination';

type TState = {
selected: Set<string>;
Expand Down Expand Up @@ -43,3 +48,28 @@ export const useSelectedJobsStore = createStore<TState>((set, get) => ({
}
},
}));

export const useRunSelectedJobsSideEffects = () => {
const clear = useSelectedJobsStore((state) => state.clear);
useEffect(() => {
const effect = clear;
const unsubActiveQueue = useActiveQueueStore.subscribe(
effect,
(state) => state.active,
);
const unsubFilters = useFiltersStore.subscribe(
effect,
(state) => [state.order, state.status, state.jobId],
shallow,
);
const unsubPagination = usePaginationStore.subscribe(
effect,
(state) => state.page,
);
return () => {
unsubActiveQueue();
unsubFilters();
unsubPagination();
};
}, []);
};
2 changes: 2 additions & 0 deletions packages/ui/src/stores/side-effects.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { useRunPaginationSideEffects } from './pagination';
import { useRunRefetchJobsLockSideEffects } from './refetch-jobs-lock';
import { useRunSelectedJobsSideEffects } from './selected-jobs';

export const useRunStoreSideEffects = () => {
useRunPaginationSideEffects();
useRunRefetchJobsLockSideEffects();
useRunSelectedJobsSideEffects();
};
36 changes: 34 additions & 2 deletions packages/ui/src/typings/gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ export type Mutation = {
emptyQueue?: Maybe<Queue>;
/** https://github.com/OptimalBits/bull/blob/develop/REFERENCE.md#jobremove */
removeJob?: Maybe<Job>;
/** calls https://github.com/OptimalBits/bull/blob/develop/REFERENCE.md#jobremove on every passed job */
removeJobs: Array<Maybe<Job>>;
/** https://github.com/OptimalBits/bull/blob/develop/REFERENCE.md#jobmovetocompleted */
moveJobToCompleted?: Maybe<Job>;
/** https://github.com/OptimalBits/bull/blob/develop/REFERENCE.md#jobmovetofailed */
Expand All @@ -94,6 +96,8 @@ export type Mutation = {
updateJobData?: Maybe<Job>;
/** https://github.com/OptimalBits/bull/blob/develop/REFERENCE.md#jobretry */
retryJob?: Maybe<Job>;
/** calls https://github.com/OptimalBits/bull/blob/develop/REFERENCE.md#jobretry on every passed job */
retryJobs: Array<Maybe<Job>>;
/** https://github.com/OptimalBits/bull/blob/develop/REFERENCE.md#joblog */
log?: Maybe<Job>;
/** https://github.com/OptimalBits/bull/blob/develop/REFERENCE.md#queueadd */
Expand Down Expand Up @@ -137,6 +141,12 @@ export type MutationRemoveJobArgs = {
};


export type MutationRemoveJobsArgs = {
queue: Scalars['String'];
jobs: Array<Scalars['ID']>;
};


export type MutationMoveJobToCompletedArgs = {
queue: Scalars['String'];
id: Scalars['ID'];
Expand Down Expand Up @@ -164,7 +174,7 @@ export type MutationPromoteJobArgs = {
export type MutationUpdateJobDataArgs = {
queue: Scalars['String'];
id: Scalars['ID'];
data?: Maybe<Scalars['String']>;
data?: Maybe<Scalars['JSON']>;
};


Expand All @@ -174,6 +184,12 @@ export type MutationRetryJobArgs = {
};


export type MutationRetryJobsArgs = {
queue: Scalars['String'];
jobs: Array<Scalars['ID']>;
};


export type MutationLogArgs = {
queue: Scalars['String'];
id: Scalars['ID'];
Expand Down Expand Up @@ -378,6 +394,14 @@ export type RemoveJobsByPatternMutationVariables = Exact<{

export type RemoveJobsByPatternMutation = Pick<Mutation, 'removeJobsByPattern'>;

export type RemoveJobsMutationVariables = Exact<{
queue: Scalars['String'];
jobs: Array<Scalars['ID']> | Scalars['ID'];
}>;


export type RemoveJobsMutation = { removeJobs: Array<Maybe<Pick<Job, 'id'>>> };

export type ResumeQueueMutationVariables = Exact<{
queue: Scalars['String'];
}>;
Expand All @@ -393,10 +417,18 @@ export type RetryJobMutationVariables = Exact<{

export type RetryJobMutation = { retryJob?: Maybe<Pick<Job, 'id'>> };

export type RetryJobsMutationVariables = Exact<{
queue: Scalars['String'];
jobs: Array<Scalars['ID']> | Scalars['ID'];
}>;


export type RetryJobsMutation = { retryJobs: Array<Maybe<Pick<Job, 'id'>>> };

export type UpdateJobDataMutationVariables = Exact<{
queue: Scalars['String'];
id: Scalars['ID'];
data?: Maybe<Scalars['String']>;
data?: Maybe<Scalars['JSON']>;
}>;


Expand Down

0 comments on commit 7f8e6be

Please sign in to comment.