Merge pull request #2089 from automatisch/aut-1266

feat: use REST API endpoint to update flow status
This commit is contained in:
Ömer Faruk Aydın
2024-09-19 14:10:44 +03:00
committed by GitHub
7 changed files with 57 additions and 136 deletions

View File

@@ -7,7 +7,6 @@ import generateAuthUrl from './mutations/generate-auth-url.js';
import createConnection from './mutations/create-connection.js';
import resetConnection from './mutations/reset-connection.js';
import updateConnection from './mutations/update-connection.js';
import updateFlowStatus from './mutations/update-flow-status.js';
const mutationResolvers = {
createConnection,
@@ -16,7 +15,6 @@ const mutationResolvers = {
resetConnection,
updateConnection,
updateCurrentUser,
updateFlowStatus,
updateUser,
verifyConnection,
};

View File

@@ -1,91 +0,0 @@
import Flow from '../../models/flow.js';
import flowQueue from '../../queues/flow.js';
import {
REMOVE_AFTER_30_DAYS_OR_150_JOBS,
REMOVE_AFTER_7_DAYS_OR_50_JOBS,
} from '../../helpers/remove-job-configuration.js';
import globalVariable from '../../helpers/global-variable.js';
const JOB_NAME = 'flow';
const EVERY_15_MINUTES_CRON = '*/15 * * * *';
const updateFlowStatus = async (_parent, params, context) => {
const conditions = context.currentUser.can('publish', 'Flow');
const isCreator = conditions.isCreator;
const allFlows = Flow.query();
const userFlows = context.currentUser.$relatedQuery('flows');
const baseQuery = isCreator ? userFlows : allFlows;
let flow = await baseQuery
.clone()
.findOne({
id: params.input.id,
})
.throwIfNotFound();
const newActiveValue = params.input.active;
if (flow.active === newActiveValue) {
return flow;
}
const triggerStep = await flow.getTriggerStep();
if (triggerStep.status === 'incomplete') {
throw flow.IncompleteStepsError;
}
const trigger = await triggerStep.getTriggerCommand();
const interval = trigger.getInterval?.(triggerStep.parameters);
const repeatOptions = {
pattern: interval || EVERY_15_MINUTES_CRON,
};
if (trigger.type === 'webhook') {
const $ = await globalVariable({
flow,
connection: await triggerStep.$relatedQuery('connection'),
app: await triggerStep.getApp(),
step: triggerStep,
testRun: false,
});
if (newActiveValue && trigger.registerHook) {
await trigger.registerHook($);
} else if (!newActiveValue && trigger.unregisterHook) {
await trigger.unregisterHook($);
}
} else {
if (newActiveValue) {
flow = await flow.$query().patchAndFetch({
publishedAt: new Date().toISOString(),
});
const jobName = `${JOB_NAME}-${flow.id}`;
await flowQueue.add(
jobName,
{ flowId: flow.id },
{
repeat: repeatOptions,
jobId: flow.id,
removeOnComplete: REMOVE_AFTER_7_DAYS_OR_50_JOBS,
removeOnFail: REMOVE_AFTER_30_DAYS_OR_150_JOBS,
}
);
} else {
const repeatableJobs = await flowQueue.getRepeatableJobs();
const job = repeatableJobs.find((job) => job.id === flow.id);
await flowQueue.removeRepeatableByKey(job.key);
}
}
flow = await flow.$query().withGraphFetched('steps').patchAndFetch({
active: newActiveValue,
});
return flow;
};
export default updateFlowStatus;

View File

@@ -8,7 +8,6 @@ type Mutation {
resetConnection(input: ResetConnectionInput): Connection
updateConnection(input: UpdateConnectionInput): Connection
updateCurrentUser(input: UpdateCurrentUserInput): User
updateFlowStatus(input: UpdateFlowStatusInput): Flow
updateUser(input: UpdateUserInput): User
verifyConnection(input: VerifyConnectionInput): Connection
}
@@ -234,11 +233,6 @@ input VerifyConnectionInput {
id: String!
}
input UpdateFlowStatusInput {
id: String!
active: Boolean!
}
input ExecuteFlowInput {
stepId: String!
}

View File

@@ -125,7 +125,13 @@ class Flow extends Base {
get IncompleteStepsError() {
return new ValidationError({
message: 'All steps should be completed before updating flow status!',
data: {
flow: [
{
message: 'All steps should be completed before updating flow status!'
}
],
},
type: 'incompleteStepsError',
});
}
@@ -366,8 +372,13 @@ class Flow extends Base {
if (allSteps.length < 2) {
throw new ValidationError({
message:
'There should be at least one trigger and one action steps in the flow!',
data: {
flow: [
{
message: 'There should be at least one trigger and one action steps in the flow!'
}
],
},
type: 'insufficientStepsError',
});
}

View File

@@ -1,6 +1,5 @@
import * as React from 'react';
import { Link, useParams } from 'react-router-dom';
import { useMutation } from '@apollo/client';
import Stack from '@mui/material/Stack';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
@@ -16,12 +15,11 @@ import Container from 'components/Container';
import Editor from 'components/Editor';
import Can from 'components/Can';
import useFormatMessage from 'hooks/useFormatMessage';
import { UPDATE_FLOW_STATUS } from 'graphql/mutations/update-flow-status';
import * as URLS from 'config/urls';
import { TopBar } from './style';
import useFlow from 'hooks/useFlow';
import useUpdateFlow from 'hooks/useUpdateFlow';
import { useQueryClient } from '@tanstack/react-query';
import useUpdateFlowStatus from 'hooks/useUpdateFlowStatus';
import EditorNew from 'components/EditorNew/EditorNew';
const useNewFlowEditor = process.env.REACT_APP_USE_NEW_FLOW_EDITOR === 'true';
@@ -30,10 +28,9 @@ export default function EditorLayout() {
const { flowId } = useParams();
const formatMessage = useFormatMessage();
const { mutateAsync: updateFlow } = useUpdateFlow(flowId);
const [updateFlowStatus] = useMutation(UPDATE_FLOW_STATUS);
const { mutateAsync: updateFlowStatus } = useUpdateFlowStatus(flowId);
const { data, isLoading: isFlowLoading } = useFlow(flowId);
const flow = data?.data;
const queryClient = useQueryClient();
const onFlowNameUpdate = async (name) => {
await updateFlow({
@@ -41,24 +38,6 @@ export default function EditorLayout() {
});
};
const onFlowStatusUpdate = React.useCallback(
async (active) => {
try {
await updateFlowStatus({
variables: {
input: {
id: flowId,
active,
},
},
});
await queryClient.invalidateQueries({ queryKey: ['flows', flowId] });
} catch (err) {}
},
[flowId, queryClient],
);
return (
<>
<TopBar
@@ -107,7 +86,7 @@ export default function EditorLayout() {
disabled={!allowed || !flow}
variant="contained"
size="small"
onClick={() => onFlowStatusUpdate(!flow.active)}
onClick={() => updateFlowStatus(!flow.active)}
data-test={
flow?.active ? 'unpublish-flow-button' : 'publish-flow-button'
}
@@ -153,7 +132,7 @@ export default function EditorLayout() {
<Button
variant="contained"
size="small"
onClick={() => onFlowStatusUpdate(!flow.active)}
onClick={() => updateFlowStatus(!flow.active)}
data-test="unpublish-flow-from-snackbar"
>
{formatMessage('flowEditor.unpublish')}

View File

@@ -1,9 +0,0 @@
import { gql } from '@apollo/client';
export const UPDATE_FLOW_STATUS = gql`
mutation UpdateFlowStatus($input: UpdateFlowStatusInput) {
updateFlowStatus(input: $input) {
id
active
}
}
`;

View File

@@ -0,0 +1,39 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import api from 'helpers/api';
import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar';
export default function useUpdateFlowStatus(flowId) {
const queryClient = useQueryClient();
const enqueueSnackbar = useEnqueueSnackbar();
const query = useMutation({
mutationFn: async (active) => {
const { data } = await api.patch(`/v1/flows/${flowId}/status`, {
active,
});
return data;
},
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ['flows', flowId],
});
},
onError: (error) => {
const errors = Object.values(
error.response.data.errors || [['Failed while updating flow status!']],
);
for (const [error] of errors) {
enqueueSnackbar(error, {
variant: 'error',
SnackbarProps: {
'data-test': 'snackbar-error',
},
});
}
}
});
return query;
}