Scaffold empty workflow (#6926)
- Create a workflow version when the user visits an empty workflow. - If the trigger is not defined yet and the user selects either the standard object type or the event type first, we automatically select the first option of the other value. Indeed, every state update is automatically saved on the backend and we need both standard object and event types to save the event name. - Introduces a change in the backend. I removed the assertions that throw when a workflow version is not complete, that is, when it doesn't have a defined trigger, which is the case when scaffolding a new workflow with a first empty workflow version. - We should keep validating the workflow versions, at least when we publish them. That should be done in a second step.
This commit is contained in:
committed by
GitHub
parent
3c4168759a
commit
3548751be2
@ -23,7 +23,10 @@ const getStepDefinitionOrThrow = ({
|
|||||||
|
|
||||||
if (stepId === TRIGGER_STEP_ID) {
|
if (stepId === TRIGGER_STEP_ID) {
|
||||||
if (!isDefined(currentVersion.trigger)) {
|
if (!isDefined(currentVersion.trigger)) {
|
||||||
throw new Error('Expected to find the definition of the trigger');
|
return {
|
||||||
|
type: 'trigger',
|
||||||
|
definition: undefined,
|
||||||
|
} as const;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -33,7 +36,9 @@ const getStepDefinitionOrThrow = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!isDefined(currentVersion.steps)) {
|
if (!isDefined(currentVersion.steps)) {
|
||||||
throw new Error('Expected to find an array of steps');
|
throw new Error(
|
||||||
|
'Malformed workflow version: missing steps information; be sure to create at least one step before trying to edit one',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedNodePosition = findStepPositionOrThrow({
|
const selectedNodePosition = findStepPositionOrThrow({
|
||||||
@ -74,7 +79,7 @@ export const RightDrawerWorkflowEditStepContent = ({
|
|||||||
return (
|
return (
|
||||||
<WorkflowEditTriggerForm
|
<WorkflowEditTriggerForm
|
||||||
trigger={stepDefinition.definition}
|
trigger={stepDefinition.definition}
|
||||||
onUpdateTrigger={updateTrigger}
|
onTriggerUpdate={updateTrigger}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -82,7 +87,7 @@ export const RightDrawerWorkflowEditStepContent = ({
|
|||||||
return (
|
return (
|
||||||
<WorkflowEditActionForm
|
<WorkflowEditActionForm
|
||||||
action={stepDefinition.definition}
|
action={stepDefinition.definition}
|
||||||
onUpdateAction={updateStep}
|
onActionUpdate={updateStep}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||||
import { WorkflowDiagramCanvas } from '@/workflow/components/WorkflowDiagramCanvas';
|
import { WorkflowDiagramCanvas } from '@/workflow/components/WorkflowDiagramCanvas';
|
||||||
import { WorkflowShowPageEffect } from '@/workflow/components/WorkflowShowPageEffect';
|
import { WorkflowEffect } from '@/workflow/components/WorkflowEffect';
|
||||||
import { workflowDiagramState } from '@/workflow/states/workflowDiagramState';
|
import { workflowDiagramState } from '@/workflow/states/workflowDiagramState';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import '@xyflow/react/dist/style.css';
|
import '@xyflow/react/dist/style.css';
|
||||||
@ -36,7 +36,7 @@ export const Workflow = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<WorkflowShowPageEffect workflowId={workflowId} />
|
<WorkflowEffect workflowId={workflowId} />
|
||||||
|
|
||||||
<StyledFlowContainer>
|
<StyledFlowContainer>
|
||||||
{workflowDiagram === undefined ? null : (
|
{workflowDiagram === undefined ? null : (
|
||||||
|
|||||||
@ -0,0 +1,109 @@
|
|||||||
|
import { WorkflowDiagramStepNodeData } from '@/workflow/types/WorkflowDiagram';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { Handle, Position } from '@xyflow/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { capitalize } from '~/utils/string/capitalize';
|
||||||
|
|
||||||
|
type Variant = 'placeholder';
|
||||||
|
|
||||||
|
const StyledStepNodeContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
padding-bottom: 12px;
|
||||||
|
padding-top: 6px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledStepNodeType = styled.div`
|
||||||
|
background-color: ${({ theme }) => theme.background.tertiary};
|
||||||
|
border-radius: ${({ theme }) => theme.border.radius.sm}
|
||||||
|
${({ theme }) => theme.border.radius.sm} 0 0;
|
||||||
|
|
||||||
|
color: ${({ theme }) => theme.color.gray50};
|
||||||
|
font-size: ${({ theme }) => theme.font.size.xs};
|
||||||
|
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||||
|
|
||||||
|
padding: ${({ theme }) => theme.spacing(1)} ${({ theme }) => theme.spacing(2)};
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
transform: translateY(-100%);
|
||||||
|
|
||||||
|
.selectable.selected &,
|
||||||
|
.selectable:focus &,
|
||||||
|
.selectable:focus-visible & {
|
||||||
|
background-color: ${({ theme }) => theme.color.blue};
|
||||||
|
color: ${({ theme }) => theme.font.color.inverted};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledStepNodeInnerContainer = styled.div<{ variant?: Variant }>`
|
||||||
|
background-color: ${({ theme }) => theme.background.secondary};
|
||||||
|
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||||
|
border-style: ${({ variant }) =>
|
||||||
|
variant === 'placeholder' ? 'dashed' : null};
|
||||||
|
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||||
|
display: flex;
|
||||||
|
gap: ${({ theme }) => theme.spacing(2)};
|
||||||
|
padding: ${({ theme }) => theme.spacing(2)};
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
box-shadow: ${({ variant, theme }) =>
|
||||||
|
variant === 'placeholder' ? 'none' : theme.boxShadow.superHeavy};
|
||||||
|
|
||||||
|
.selectable.selected &,
|
||||||
|
.selectable:focus &,
|
||||||
|
.selectable:focus-visible & {
|
||||||
|
background-color: ${({ theme }) => theme.color.blue10};
|
||||||
|
border-color: ${({ theme }) => theme.color.blue};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledStepNodeLabel = styled.div<{ variant?: Variant }>`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
font-size: ${({ theme }) => theme.font.size.md};
|
||||||
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
|
column-gap: ${({ theme }) => theme.spacing(2)};
|
||||||
|
color: ${({ variant, theme }) =>
|
||||||
|
variant === 'placeholder' ? theme.font.color.extraLight : null};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledSourceHandle = styled(Handle)`
|
||||||
|
background-color: ${({ theme }) => theme.color.gray50};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const StyledTargetHandle = styled(Handle)`
|
||||||
|
visibility: hidden;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const WorkflowDiagramBaseStepNode = ({
|
||||||
|
nodeType,
|
||||||
|
label,
|
||||||
|
variant,
|
||||||
|
Icon,
|
||||||
|
}: {
|
||||||
|
nodeType: WorkflowDiagramStepNodeData['nodeType'];
|
||||||
|
label: string;
|
||||||
|
variant?: Variant;
|
||||||
|
Icon?: React.ReactNode;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<StyledStepNodeContainer>
|
||||||
|
{nodeType !== 'trigger' ? (
|
||||||
|
<StyledTargetHandle type="target" position={Position.Top} />
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<StyledStepNodeInnerContainer variant={variant}>
|
||||||
|
<StyledStepNodeType>{capitalize(nodeType)}</StyledStepNodeType>
|
||||||
|
|
||||||
|
<StyledStepNodeLabel variant={variant}>
|
||||||
|
{Icon}
|
||||||
|
|
||||||
|
{label}
|
||||||
|
</StyledStepNodeLabel>
|
||||||
|
</StyledStepNodeInnerContainer>
|
||||||
|
|
||||||
|
<StyledSourceHandle type="source" position={Position.Bottom} />
|
||||||
|
</StyledStepNodeContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import { WorkflowDiagramCanvasEffect } from '@/workflow/components/WorkflowDiagramCanvasEffect';
|
import { WorkflowDiagramCanvasEffect } from '@/workflow/components/WorkflowDiagramCanvasEffect';
|
||||||
import { WorkflowDiagramCreateStepNode } from '@/workflow/components/WorkflowDiagramCreateStepNode';
|
import { WorkflowDiagramCreateStepNode } from '@/workflow/components/WorkflowDiagramCreateStepNode';
|
||||||
|
import { WorkflowDiagramEmptyTrigger } from '@/workflow/components/WorkflowDiagramEmptyTrigger';
|
||||||
import { WorkflowDiagramStepNode } from '@/workflow/components/WorkflowDiagramStepNode';
|
import { WorkflowDiagramStepNode } from '@/workflow/components/WorkflowDiagramStepNode';
|
||||||
import { workflowDiagramState } from '@/workflow/states/workflowDiagramState';
|
import { workflowDiagramState } from '@/workflow/states/workflowDiagramState';
|
||||||
import {
|
import {
|
||||||
@ -72,6 +73,7 @@ export const WorkflowDiagramCanvas = ({
|
|||||||
nodeTypes={{
|
nodeTypes={{
|
||||||
default: WorkflowDiagramStepNode,
|
default: WorkflowDiagramStepNode,
|
||||||
'create-step': WorkflowDiagramCreateStepNode,
|
'create-step': WorkflowDiagramCreateStepNode,
|
||||||
|
'empty-trigger': WorkflowDiagramEmptyTrigger,
|
||||||
}}
|
}}
|
||||||
fitView
|
fitView
|
||||||
nodes={nodes.map((node) => ({ ...node, draggable: false }))}
|
nodes={nodes.map((node) => ({ ...node, draggable: false }))}
|
||||||
|
|||||||
@ -0,0 +1,30 @@
|
|||||||
|
import { WorkflowDiagramBaseStepNode } from '@/workflow/components/WorkflowDiagramBaseStepNode';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { IconPlaylistAdd } from 'twenty-ui';
|
||||||
|
|
||||||
|
const StyledStepNodeLabelIconContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
background: ${({ theme }) => theme.background.transparent.light};
|
||||||
|
border-radius: ${({ theme }) => theme.spacing(1)};
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: ${({ theme }) => theme.spacing(1)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const WorkflowDiagramEmptyTrigger = () => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<WorkflowDiagramBaseStepNode
|
||||||
|
label="Add a Trigger"
|
||||||
|
nodeType="trigger"
|
||||||
|
variant="placeholder"
|
||||||
|
Icon={
|
||||||
|
<StyledStepNodeLabelIconContainer>
|
||||||
|
<IconPlaylistAdd size={16} color={theme.font.color.tertiary} />
|
||||||
|
</StyledStepNodeLabelIconContainer>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,67 +1,16 @@
|
|||||||
|
import { WorkflowDiagramBaseStepNode } from '@/workflow/components/WorkflowDiagramBaseStepNode';
|
||||||
import { WorkflowDiagramStepNodeData } from '@/workflow/types/WorkflowDiagram';
|
import { WorkflowDiagramStepNodeData } from '@/workflow/types/WorkflowDiagram';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { Handle, Position } from '@xyflow/react';
|
import { IconCode, IconPlaylistAdd } from 'twenty-ui';
|
||||||
|
|
||||||
const StyledStepNodeContainer = styled.div`
|
const StyledStepNodeLabelIconContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
background: ${({ theme }) => theme.background.transparent.light};
|
||||||
|
border-radius: ${({ theme }) => theme.spacing(1)};
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
justify-content: center;
|
||||||
|
padding: ${({ theme }) => theme.spacing(1)};
|
||||||
padding-bottom: 12px;
|
|
||||||
padding-top: 6px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledStepNodeType = styled.div`
|
|
||||||
background-color: ${({ theme }) => theme.background.tertiary};
|
|
||||||
border-radius: ${({ theme }) => theme.border.radius.sm}
|
|
||||||
${({ theme }) => theme.border.radius.sm} 0 0;
|
|
||||||
|
|
||||||
color: ${({ theme }) => theme.color.gray50};
|
|
||||||
font-size: ${({ theme }) => theme.font.size.xs};
|
|
||||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
|
||||||
|
|
||||||
padding: ${({ theme }) => theme.spacing(1)} ${({ theme }) => theme.spacing(2)};
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
transform: translateY(-100%);
|
|
||||||
|
|
||||||
.selectable.selected &,
|
|
||||||
.selectable:focus &,
|
|
||||||
.selectable:focus-visible & {
|
|
||||||
background-color: ${({ theme }) => theme.color.blue};
|
|
||||||
color: ${({ theme }) => theme.font.color.inverted};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledStepNodeInnerContainer = styled.div`
|
|
||||||
background-color: ${({ theme }) => theme.background.secondary};
|
|
||||||
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
|
||||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
|
||||||
display: flex;
|
|
||||||
gap: ${({ theme }) => theme.spacing(2)};
|
|
||||||
padding: ${({ theme }) => theme.spacing(2)};
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
box-shadow: ${({ theme }) => theme.boxShadow.superHeavy};
|
|
||||||
|
|
||||||
.selectable.selected &,
|
|
||||||
.selectable:focus &,
|
|
||||||
.selectable:focus-visible & {
|
|
||||||
background-color: ${({ theme }) => theme.color.blue10};
|
|
||||||
border-color: ${({ theme }) => theme.color.blue};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledStepNodeLabel = styled.div`
|
|
||||||
font-size: ${({ theme }) => theme.font.size.md};
|
|
||||||
font-weight: ${({ theme }) => theme.font.weight.medium};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledSourceHandle = styled(Handle)`
|
|
||||||
background-color: ${({ theme }) => theme.color.gray50};
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const StyledTargetHandle = styled(Handle)`
|
|
||||||
visibility: hidden;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const WorkflowDiagramStepNode = ({
|
export const WorkflowDiagramStepNode = ({
|
||||||
@ -69,19 +18,37 @@ export const WorkflowDiagramStepNode = ({
|
|||||||
}: {
|
}: {
|
||||||
data: WorkflowDiagramStepNodeData;
|
data: WorkflowDiagramStepNodeData;
|
||||||
}) => {
|
}) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const renderStepIcon = () => {
|
||||||
|
switch (data.nodeType) {
|
||||||
|
case 'trigger': {
|
||||||
|
return (
|
||||||
|
<StyledStepNodeLabelIconContainer>
|
||||||
|
<IconPlaylistAdd
|
||||||
|
size={theme.icon.size.sm}
|
||||||
|
color={theme.font.color.tertiary}
|
||||||
|
/>
|
||||||
|
</StyledStepNodeLabelIconContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case 'action': {
|
||||||
|
return (
|
||||||
|
<StyledStepNodeLabelIconContainer>
|
||||||
|
<IconCode size={theme.icon.size.sm} color={theme.color.orange} />
|
||||||
|
</StyledStepNodeLabelIconContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledStepNodeContainer>
|
<WorkflowDiagramBaseStepNode
|
||||||
{data.nodeType !== 'trigger' ? (
|
nodeType={data.nodeType}
|
||||||
<StyledTargetHandle type="target" position={Position.Top} />
|
label={data.label}
|
||||||
) : null}
|
Icon={renderStepIcon()}
|
||||||
|
/>
|
||||||
<StyledStepNodeInnerContainer>
|
|
||||||
<StyledStepNodeType>{data.nodeType}</StyledStepNodeType>
|
|
||||||
|
|
||||||
<StyledStepNodeLabel>{data.label}</StyledStepNodeLabel>
|
|
||||||
</StyledStepNodeInnerContainer>
|
|
||||||
|
|
||||||
<StyledSourceHandle type="source" position={Position.Bottom} />
|
|
||||||
</StyledStepNodeContainer>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -45,10 +45,10 @@ const StyledTriggerSettings = styled.div`
|
|||||||
|
|
||||||
export const WorkflowEditActionForm = ({
|
export const WorkflowEditActionForm = ({
|
||||||
action,
|
action,
|
||||||
onUpdateAction,
|
onActionUpdate,
|
||||||
}: {
|
}: {
|
||||||
action: WorkflowAction;
|
action: WorkflowAction;
|
||||||
onUpdateAction: (trigger: WorkflowAction) => void;
|
onActionUpdate: (trigger: WorkflowAction) => void;
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ export const WorkflowEditActionForm = ({
|
|||||||
value={action.settings.serverlessFunctionId}
|
value={action.settings.serverlessFunctionId}
|
||||||
options={availableFunctions}
|
options={availableFunctions}
|
||||||
onChange={(updatedFunction) => {
|
onChange={(updatedFunction) => {
|
||||||
onUpdateAction({
|
onActionUpdate({
|
||||||
...action,
|
...action,
|
||||||
settings: {
|
settings: {
|
||||||
...action.settings,
|
...action.settings,
|
||||||
|
|||||||
@ -47,39 +47,35 @@ const StyledTriggerSettings = styled.div`
|
|||||||
|
|
||||||
export const WorkflowEditTriggerForm = ({
|
export const WorkflowEditTriggerForm = ({
|
||||||
trigger,
|
trigger,
|
||||||
onUpdateTrigger,
|
onTriggerUpdate,
|
||||||
}: {
|
}: {
|
||||||
trigger: WorkflowTrigger;
|
trigger: WorkflowTrigger | undefined;
|
||||||
onUpdateTrigger: (trigger: WorkflowTrigger) => void;
|
onTriggerUpdate: (trigger: WorkflowTrigger) => void;
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const { activeObjectMetadataItems } = useFilteredObjectMetadataItems();
|
const { activeObjectMetadataItems } = useFilteredObjectMetadataItems();
|
||||||
|
|
||||||
const triggerEvent = splitWorkflowTriggerEventName(
|
const triggerEvent = isDefined(trigger)
|
||||||
trigger.settings.eventName,
|
? splitWorkflowTriggerEventName(trigger.settings.eventName)
|
||||||
);
|
: undefined;
|
||||||
|
|
||||||
const availableMetadata: Array<SelectOption<string>> =
|
const availableMetadata: Array<SelectOption<string>> =
|
||||||
activeObjectMetadataItems.map((item) => ({
|
activeObjectMetadataItems.map((item) => ({
|
||||||
label: item.labelPlural,
|
label: item.labelPlural,
|
||||||
value: item.nameSingular,
|
value: item.nameSingular,
|
||||||
}));
|
}));
|
||||||
const recordTypeMetadata = activeObjectMetadataItems.find(
|
const recordTypeMetadata = isDefined(triggerEvent)
|
||||||
(item) => item.nameSingular === triggerEvent.objectType,
|
? activeObjectMetadataItems.find(
|
||||||
);
|
(item) => item.nameSingular === triggerEvent.objectType,
|
||||||
if (!isDefined(recordTypeMetadata)) {
|
)
|
||||||
throw new Error(
|
: undefined;
|
||||||
'Expected to find the metadata configuration for the currently selected record type of the trigger.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedEvent = OBJECT_EVENT_TRIGGERS.find(
|
const selectedEvent = isDefined(triggerEvent)
|
||||||
(availableEvent) => availableEvent.value === triggerEvent.event,
|
? OBJECT_EVENT_TRIGGERS.find(
|
||||||
);
|
(availableEvent) => availableEvent.value === triggerEvent.event,
|
||||||
if (!isDefined(selectedEvent)) {
|
)
|
||||||
throw new Error('Expected to find the currently selected event type.');
|
: undefined;
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -89,11 +85,15 @@ export const WorkflowEditTriggerForm = ({
|
|||||||
</StyledTriggerHeaderIconContainer>
|
</StyledTriggerHeaderIconContainer>
|
||||||
|
|
||||||
<StyledTriggerHeaderTitle>
|
<StyledTriggerHeaderTitle>
|
||||||
When a {recordTypeMetadata.labelSingular} is {selectedEvent.label}
|
{isDefined(recordTypeMetadata) && isDefined(selectedEvent)
|
||||||
|
? `When a ${recordTypeMetadata.labelSingular} is ${selectedEvent.label}`
|
||||||
|
: '-'}
|
||||||
</StyledTriggerHeaderTitle>
|
</StyledTriggerHeaderTitle>
|
||||||
|
|
||||||
<StyledTriggerHeaderType>
|
<StyledTriggerHeaderType>
|
||||||
Trigger . Record is {selectedEvent.label}
|
{isDefined(selectedEvent)
|
||||||
|
? `Trigger . Record is ${selectedEvent.label}`
|
||||||
|
: '-'}
|
||||||
</StyledTriggerHeaderType>
|
</StyledTriggerHeaderType>
|
||||||
</StyledTriggerHeader>
|
</StyledTriggerHeader>
|
||||||
|
|
||||||
@ -102,32 +102,50 @@ export const WorkflowEditTriggerForm = ({
|
|||||||
dropdownId="workflow-edit-trigger-record-type"
|
dropdownId="workflow-edit-trigger-record-type"
|
||||||
label="Record Type"
|
label="Record Type"
|
||||||
fullWidth
|
fullWidth
|
||||||
value={triggerEvent.objectType}
|
value={triggerEvent?.objectType}
|
||||||
options={availableMetadata}
|
options={availableMetadata}
|
||||||
onChange={(updatedRecordType) => {
|
onChange={(updatedRecordType) => {
|
||||||
onUpdateTrigger({
|
onTriggerUpdate(
|
||||||
...trigger,
|
isDefined(trigger) && isDefined(triggerEvent)
|
||||||
settings: {
|
? {
|
||||||
...trigger.settings,
|
...trigger,
|
||||||
eventName: `${updatedRecordType}.${triggerEvent.event}`,
|
settings: {
|
||||||
},
|
...trigger.settings,
|
||||||
});
|
eventName: `${updatedRecordType}.${triggerEvent.event}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
type: 'DATABASE_EVENT',
|
||||||
|
settings: {
|
||||||
|
eventName: `${updatedRecordType}.${OBJECT_EVENT_TRIGGERS[0].value}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Select
|
<Select
|
||||||
dropdownId="workflow-edit-trigger-event-type"
|
dropdownId="workflow-edit-trigger-event-type"
|
||||||
label="Event type"
|
label="Event type"
|
||||||
fullWidth
|
fullWidth
|
||||||
value={triggerEvent.event}
|
value={triggerEvent?.event}
|
||||||
options={OBJECT_EVENT_TRIGGERS}
|
options={OBJECT_EVENT_TRIGGERS}
|
||||||
onChange={(updatedEvent) => {
|
onChange={(updatedEvent) => {
|
||||||
onUpdateTrigger({
|
onTriggerUpdate(
|
||||||
...trigger,
|
isDefined(trigger) && isDefined(triggerEvent)
|
||||||
settings: {
|
? {
|
||||||
...trigger.settings,
|
...trigger,
|
||||||
eventName: `${triggerEvent.objectType}.${updatedEvent}`,
|
settings: {
|
||||||
},
|
...trigger.settings,
|
||||||
});
|
eventName: `${triggerEvent.objectType}.${updatedEvent}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
type: 'DATABASE_EVENT',
|
||||||
|
settings: {
|
||||||
|
eventName: `${availableMetadata[0].value}.${updatedEvent}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</StyledTriggerSettings>
|
</StyledTriggerSettings>
|
||||||
|
|||||||
@ -7,13 +7,11 @@ import { useEffect } from 'react';
|
|||||||
import { useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
import { isDefined } from 'twenty-ui';
|
import { isDefined } from 'twenty-ui';
|
||||||
|
|
||||||
type WorkflowShowPageEffectProps = {
|
type WorkflowEffectProps = {
|
||||||
workflowId: string;
|
workflowId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WorkflowShowPageEffect = ({
|
export const WorkflowEffect = ({ workflowId }: WorkflowEffectProps) => {
|
||||||
workflowId,
|
|
||||||
}: WorkflowShowPageEffectProps) => {
|
|
||||||
const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(workflowId);
|
const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(workflowId);
|
||||||
|
|
||||||
const setWorkflowId = useSetRecoilState(workflowIdState);
|
const setWorkflowId = useSetRecoilState(workflowIdState);
|
||||||
@ -1,30 +0,0 @@
|
|||||||
import { PageHeader } from '@/ui/layout/page/PageHeader';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import { IconComponent } from 'twenty-ui';
|
|
||||||
|
|
||||||
export const WorkflowShowPageHeader = ({
|
|
||||||
workflowName,
|
|
||||||
headerIcon,
|
|
||||||
children,
|
|
||||||
}: {
|
|
||||||
workflowName: string;
|
|
||||||
headerIcon: IconComponent;
|
|
||||||
children?: React.ReactNode;
|
|
||||||
}) => {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PageHeader
|
|
||||||
hasClosePageButton
|
|
||||||
onClosePage={() => {
|
|
||||||
navigate({
|
|
||||||
pathname: '/objects/workflows',
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
title={workflowName}
|
|
||||||
Icon={headerIcon}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</PageHeader>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -6,6 +6,7 @@ import {
|
|||||||
WorkflowVersion,
|
WorkflowVersion,
|
||||||
WorkflowWithCurrentVersion,
|
WorkflowWithCurrentVersion,
|
||||||
} from '@/workflow/types/Workflow';
|
} from '@/workflow/types/Workflow';
|
||||||
|
import { useMemo } from 'react';
|
||||||
import { isDefined } from 'twenty-ui';
|
import { isDefined } from 'twenty-ui';
|
||||||
|
|
||||||
export const useWorkflowWithCurrentVersion = (
|
export const useWorkflowWithCurrentVersion = (
|
||||||
@ -22,34 +23,37 @@ export const useWorkflowWithCurrentVersion = (
|
|||||||
skip: !isDefined(workflowId),
|
skip: !isDefined(workflowId),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { records: mostRecentWorkflowVersions } =
|
const {
|
||||||
useFindManyRecords<WorkflowVersion>({
|
records: mostRecentWorkflowVersions,
|
||||||
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
|
loading: loadingMostRecentWorkflowVersions,
|
||||||
filter: {
|
} = useFindManyRecords<WorkflowVersion>({
|
||||||
workflowId: {
|
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
|
||||||
eq: workflowId,
|
filter: {
|
||||||
},
|
workflowId: {
|
||||||
|
eq: workflowId,
|
||||||
},
|
},
|
||||||
orderBy: [
|
},
|
||||||
{
|
orderBy: [
|
||||||
createdAt: 'DescNullsLast',
|
{
|
||||||
},
|
createdAt: 'DescNullsLast',
|
||||||
],
|
},
|
||||||
limit: 1,
|
],
|
||||||
skip: !isDefined(workflowId),
|
limit: 1,
|
||||||
});
|
skip: !isDefined(workflowId),
|
||||||
|
});
|
||||||
|
|
||||||
if (!isDefined(workflow)) {
|
const workflowWithCurrentVersion = useMemo(() => {
|
||||||
return undefined;
|
if (!isDefined(workflow) || loadingMostRecentWorkflowVersions) {
|
||||||
}
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
const currentVersion = mostRecentWorkflowVersions?.[0];
|
const currentVersion = mostRecentWorkflowVersions?.[0];
|
||||||
if (!isDefined(currentVersion)) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...workflow,
|
...workflow,
|
||||||
currentVersion,
|
currentVersion,
|
||||||
};
|
};
|
||||||
|
}, [loadingMostRecentWorkflowVersions, mostRecentWorkflowVersions, workflow]);
|
||||||
|
|
||||||
|
return workflowWithCurrentVersion;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,7 +7,7 @@ describe('getWorkflowVersionDiagram', () => {
|
|||||||
expect(result).toEqual({ nodes: [], edges: [] });
|
expect(result).toEqual({ nodes: [], edges: [] });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns an empty diagram if the provided workflow version has no trigger', () => {
|
it('returns a diagram with an empty-trigger node if the provided workflow version has no trigger', () => {
|
||||||
const result = getWorkflowVersionDiagram({
|
const result = getWorkflowVersionDiagram({
|
||||||
__typename: 'WorkflowVersion',
|
__typename: 'WorkflowVersion',
|
||||||
status: 'ACTIVE',
|
status: 'ACTIVE',
|
||||||
@ -20,10 +20,20 @@ describe('getWorkflowVersionDiagram', () => {
|
|||||||
workflowId: '',
|
workflowId: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result).toEqual({ nodes: [], edges: [] });
|
expect(result).toEqual({
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
id: 'trigger',
|
||||||
|
position: { x: 0, y: 0 },
|
||||||
|
type: 'empty-trigger',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
edges: [],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns an empty diagram if the provided workflow version has no steps', () => {
|
it('returns a diagram with an empty-trigger node if the provided workflow version has no steps', () => {
|
||||||
const result = getWorkflowVersionDiagram({
|
const result = getWorkflowVersionDiagram({
|
||||||
__typename: 'WorkflowVersion',
|
__typename: 'WorkflowVersion',
|
||||||
status: 'ACTIVE',
|
status: 'ACTIVE',
|
||||||
@ -39,7 +49,19 @@ describe('getWorkflowVersionDiagram', () => {
|
|||||||
workflowId: '',
|
workflowId: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result).toEqual({ nodes: [], edges: [] });
|
expect(result).toEqual({
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
data: {
|
||||||
|
label: 'Company is Created',
|
||||||
|
nodeType: 'trigger',
|
||||||
|
},
|
||||||
|
id: 'trigger',
|
||||||
|
position: { x: 0, y: 0 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
edges: [],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the diagram for the last version', () => {
|
it('returns the diagram for the last version', () => {
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
} from '@/workflow/types/WorkflowDiagram';
|
} from '@/workflow/types/WorkflowDiagram';
|
||||||
import { splitWorkflowTriggerEventName } from '@/workflow/utils/splitWorkflowTriggerEventName';
|
import { splitWorkflowTriggerEventName } from '@/workflow/utils/splitWorkflowTriggerEventName';
|
||||||
import { MarkerType } from '@xyflow/react';
|
import { MarkerType } from '@xyflow/react';
|
||||||
|
import { isDefined } from 'twenty-ui';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
import { capitalize } from '~/utils/string/capitalize';
|
import { capitalize } from '~/utils/string/capitalize';
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ export const generateWorkflowDiagram = ({
|
|||||||
trigger,
|
trigger,
|
||||||
steps,
|
steps,
|
||||||
}: {
|
}: {
|
||||||
trigger: WorkflowTrigger;
|
trigger: WorkflowTrigger | undefined;
|
||||||
steps: Array<WorkflowStep>;
|
steps: Array<WorkflowStep>;
|
||||||
}): WorkflowDiagram => {
|
}): WorkflowDiagram => {
|
||||||
const nodes: Array<WorkflowDiagramNode> = [];
|
const nodes: Array<WorkflowDiagramNode> = [];
|
||||||
@ -55,20 +56,34 @@ export const generateWorkflowDiagram = ({
|
|||||||
|
|
||||||
// Start with the trigger node
|
// Start with the trigger node
|
||||||
const triggerNodeId = TRIGGER_STEP_ID;
|
const triggerNodeId = TRIGGER_STEP_ID;
|
||||||
const triggerEvent = splitWorkflowTriggerEventName(
|
|
||||||
trigger.settings.eventName,
|
if (isDefined(trigger)) {
|
||||||
);
|
const triggerEvent = splitWorkflowTriggerEventName(
|
||||||
nodes.push({
|
trigger.settings.eventName,
|
||||||
id: triggerNodeId,
|
);
|
||||||
data: {
|
|
||||||
nodeType: 'trigger',
|
nodes.push({
|
||||||
label: `${capitalize(triggerEvent.objectType)} is ${capitalize(triggerEvent.event)}`,
|
id: triggerNodeId,
|
||||||
},
|
data: {
|
||||||
position: {
|
nodeType: 'trigger',
|
||||||
x: 0,
|
label: `${capitalize(triggerEvent.objectType)} is ${capitalize(triggerEvent.event)}`,
|
||||||
y: 0,
|
},
|
||||||
},
|
position: {
|
||||||
});
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
nodes.push({
|
||||||
|
id: triggerNodeId,
|
||||||
|
type: 'empty-trigger',
|
||||||
|
data: {} as any,
|
||||||
|
position: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let lastStepId = triggerNodeId;
|
let lastStepId = triggerNodeId;
|
||||||
|
|
||||||
|
|||||||
@ -11,18 +11,12 @@ const EMPTY_DIAGRAM: WorkflowDiagram = {
|
|||||||
export const getWorkflowVersionDiagram = (
|
export const getWorkflowVersionDiagram = (
|
||||||
workflowVersion: WorkflowVersion | undefined,
|
workflowVersion: WorkflowVersion | undefined,
|
||||||
): WorkflowDiagram => {
|
): WorkflowDiagram => {
|
||||||
if (
|
if (!isDefined(workflowVersion)) {
|
||||||
!(
|
|
||||||
isDefined(workflowVersion) &&
|
|
||||||
isDefined(workflowVersion.trigger) &&
|
|
||||||
isDefined(workflowVersion.steps)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return EMPTY_DIAGRAM;
|
return EMPTY_DIAGRAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
return generateWorkflowDiagram({
|
return generateWorkflowDiagram({
|
||||||
trigger: workflowVersion.trigger,
|
trigger: workflowVersion.trigger ?? undefined,
|
||||||
steps: workflowVersion.steps,
|
steps: workflowVersion.steps ?? [],
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -9,3 +9,11 @@ export interface WorkspaceQueryHookInstance {
|
|||||||
payload: ResolverArgs,
|
payload: ResolverArgs,
|
||||||
): Promise<ResolverArgs>;
|
): Promise<ResolverArgs>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WorkspaceQueryPostHookInstance {
|
||||||
|
execute(
|
||||||
|
authContext: AuthContext,
|
||||||
|
objectName: string,
|
||||||
|
payload: unknown[],
|
||||||
|
): Promise<void>;
|
||||||
|
}
|
||||||
|
|||||||
@ -66,4 +66,25 @@ export class WorkspaceQueryHookStorage {
|
|||||||
|
|
||||||
this.postHookInstances.get(key)?.push(data);
|
this.postHookInstances.get(key)?.push(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getWorkspaceQueryPostHookInstances(
|
||||||
|
key: WorkspaceQueryHookKey,
|
||||||
|
): WorkspaceQueryHookData<WorkspaceQueryHookInstance>[] {
|
||||||
|
const methodName = key.split('.')?.[1] as
|
||||||
|
| WorkspaceResolverBuilderMethodNames
|
||||||
|
| undefined;
|
||||||
|
let wildcardInstances: WorkspaceQueryHookData<WorkspaceQueryHookInstance>[] =
|
||||||
|
[];
|
||||||
|
|
||||||
|
if (!methodName) {
|
||||||
|
throw new Error(`Can't split workspace query hook key: ${key}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrive wildcard post-hook instances
|
||||||
|
if (this.postHookInstances.has(`*.${methodName}`)) {
|
||||||
|
wildcardInstances = this.postHookInstances.get(`*.${methodName}`)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...wildcardInstances, ...(this.postHookInstances.get(key) ?? [])];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,12 +2,13 @@ import { Injectable } from '@nestjs/common';
|
|||||||
|
|
||||||
import merge from 'lodash.merge';
|
import merge from 'lodash.merge';
|
||||||
|
|
||||||
|
import { Record as IRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface';
|
||||||
import { WorkspaceResolverBuilderMethodNames } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
import { WorkspaceResolverBuilderMethodNames } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
||||||
|
|
||||||
import { WorkspaceQueryHookStorage } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/storage/workspace-query-hook.storage';
|
|
||||||
import { WorkspaceQueryHookKey } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
import { WorkspaceQueryHookKey } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||||
import { WorkspaceQueryHookExplorer } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.explorer';
|
import { WorkspaceQueryHookStorage } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/storage/workspace-query-hook.storage';
|
||||||
import { WorkspacePreQueryHookPayload } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type';
|
import { WorkspacePreQueryHookPayload } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type';
|
||||||
|
import { WorkspaceQueryHookExplorer } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.explorer';
|
||||||
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
|
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -49,4 +50,32 @@ export class WorkspaceQueryHookService {
|
|||||||
|
|
||||||
return payload;
|
return payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async executePostQueryHooks<
|
||||||
|
T extends WorkspaceResolverBuilderMethodNames,
|
||||||
|
Record extends IRecord = IRecord,
|
||||||
|
>(
|
||||||
|
authContext: AuthContext,
|
||||||
|
// TODO: We should allow wildcard for object name
|
||||||
|
objectName: string,
|
||||||
|
methodName: T,
|
||||||
|
payload: Record[],
|
||||||
|
): Promise<void> {
|
||||||
|
const key: WorkspaceQueryHookKey = `${objectName}.${methodName}`;
|
||||||
|
const postHookInstances =
|
||||||
|
this.workspaceQueryHookStorage.getWorkspaceQueryPostHookInstances(key);
|
||||||
|
|
||||||
|
if (!postHookInstances) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const postHookInstance of postHookInstances) {
|
||||||
|
await this.workspaceQueryHookExplorer.handleHook(
|
||||||
|
[authContext, objectName, payload],
|
||||||
|
postHookInstance.instance,
|
||||||
|
postHookInstance.host,
|
||||||
|
postHookInstance.isRequestScoped,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -325,6 +325,13 @@ export class WorkspaceQueryRunnerService {
|
|||||||
)
|
)
|
||||||
)?.records;
|
)?.records;
|
||||||
|
|
||||||
|
await this.workspaceQueryHookService.executePostQueryHooks(
|
||||||
|
authContext,
|
||||||
|
objectMetadataItem.nameSingular,
|
||||||
|
'createMany',
|
||||||
|
parsedResults,
|
||||||
|
);
|
||||||
|
|
||||||
await this.triggerWebhooks<Record>(
|
await this.triggerWebhooks<Record>(
|
||||||
parsedResults,
|
parsedResults,
|
||||||
CallWebhookJobsJobOperation.create,
|
CallWebhookJobsJobOperation.create,
|
||||||
|
|||||||
@ -0,0 +1,42 @@
|
|||||||
|
import { WorkspaceQueryPostHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||||
|
|
||||||
|
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||||
|
import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type';
|
||||||
|
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||||
|
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
||||||
|
import {
|
||||||
|
WorkflowVersionStatus,
|
||||||
|
WorkflowVersionWorkspaceEntity,
|
||||||
|
} from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
|
||||||
|
import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
|
||||||
|
|
||||||
|
@WorkspaceQueryHook({
|
||||||
|
key: `workflow.createMany`,
|
||||||
|
type: WorkspaceQueryHookType.PostHook,
|
||||||
|
})
|
||||||
|
export class WorkflowCreateManyPostQueryHook
|
||||||
|
implements WorkspaceQueryPostHookInstance
|
||||||
|
{
|
||||||
|
constructor(private readonly twentyORMManager: TwentyORMManager) {}
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
_authContext: AuthContext,
|
||||||
|
_objectName: string,
|
||||||
|
payload: WorkflowWorkspaceEntity[],
|
||||||
|
): Promise<void> {
|
||||||
|
const workflowVersionRepository =
|
||||||
|
await this.twentyORMManager.getRepository<WorkflowVersionWorkspaceEntity>(
|
||||||
|
'workflowVersion',
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
payload.map((workflow) => {
|
||||||
|
return workflowVersionRepository.insert({
|
||||||
|
workflowId: workflow.id,
|
||||||
|
status: WorkflowVersionStatus.DRAFT,
|
||||||
|
name: 'v1',
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
import { WorkspaceQueryPostHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||||
|
|
||||||
|
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||||
|
import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type';
|
||||||
|
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||||
|
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
||||||
|
import {
|
||||||
|
WorkflowVersionStatus,
|
||||||
|
WorkflowVersionWorkspaceEntity,
|
||||||
|
} from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
|
||||||
|
import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
|
||||||
|
|
||||||
|
@WorkspaceQueryHook({
|
||||||
|
key: `workflow.createOne`,
|
||||||
|
type: WorkspaceQueryHookType.PostHook,
|
||||||
|
})
|
||||||
|
export class WorkflowCreateOnePostQueryHook
|
||||||
|
implements WorkspaceQueryPostHookInstance
|
||||||
|
{
|
||||||
|
constructor(private readonly twentyORMManager: TwentyORMManager) {}
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
_authContext: AuthContext,
|
||||||
|
_objectName: string,
|
||||||
|
payload: WorkflowWorkspaceEntity[],
|
||||||
|
): Promise<void> {
|
||||||
|
const workflow = payload[0];
|
||||||
|
|
||||||
|
const workflowVersionRepository =
|
||||||
|
await this.twentyORMManager.getRepository<WorkflowVersionWorkspaceEntity>(
|
||||||
|
'workflowVersion',
|
||||||
|
);
|
||||||
|
|
||||||
|
await workflowVersionRepository.insert({
|
||||||
|
workflowId: workflow.id,
|
||||||
|
status: WorkflowVersionStatus.DRAFT,
|
||||||
|
name: 'v1',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,19 +1,20 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { WorkflowCreateManyPostQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-create-many.post-query.hook';
|
||||||
|
import { WorkflowCreateManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-create-many.pre-query.hook';
|
||||||
|
import { WorkflowCreateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-create-one.pre-query.hook';
|
||||||
import { WorkflowRunCreateManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-run-create-many.pre-query.hook';
|
import { WorkflowRunCreateManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-run-create-many.pre-query.hook';
|
||||||
import { WorkflowRunCreateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-run-create-one.pre-query.hook';
|
import { WorkflowRunCreateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-run-create-one.pre-query.hook';
|
||||||
import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-version-validation.workspace-service';
|
import { WorkflowUpdateManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-update-many.pre-query.hook';
|
||||||
|
import { WorkflowUpdateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-update-one.pre-query.hook';
|
||||||
import { WorkflowVersionCreateManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version-create-many.pre-query.hook';
|
import { WorkflowVersionCreateManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version-create-many.pre-query.hook';
|
||||||
import { WorkflowVersionCreateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version-create-one.pre-query.hook';
|
import { WorkflowVersionCreateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version-create-one.pre-query.hook';
|
||||||
import { WorkflowVersionDeleteManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version-delete-many.pre-query.hook';
|
import { WorkflowVersionDeleteManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version-delete-many.pre-query.hook';
|
||||||
import { WorkflowVersionDeleteOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version-delete-one.pre-query.hook';
|
import { WorkflowVersionDeleteOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version-delete-one.pre-query.hook';
|
||||||
import { WorkflowVersionUpdateManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version-update-many.pre-query.hook';
|
import { WorkflowVersionUpdateManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version-update-many.pre-query.hook';
|
||||||
import { WorkflowVersionUpdateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version-update-one.pre-query.hook';
|
import { WorkflowVersionUpdateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version-update-one.pre-query.hook';
|
||||||
import { WorkflowCreateManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-create-many.pre-query.hook';
|
|
||||||
import { WorkflowCreateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-create-one.pre-query.hook';
|
|
||||||
import { WorkflowUpdateManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-update-many.pre-query.hook';
|
|
||||||
import { WorkflowUpdateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-update-one.pre-query.hook';
|
|
||||||
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||||
|
import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-version-validation.workspace-service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [
|
providers: [
|
||||||
@ -29,6 +30,7 @@ import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/work
|
|||||||
WorkflowVersionUpdateManyPreQueryHook,
|
WorkflowVersionUpdateManyPreQueryHook,
|
||||||
WorkflowVersionDeleteOnePreQueryHook,
|
WorkflowVersionDeleteOnePreQueryHook,
|
||||||
WorkflowVersionDeleteManyPreQueryHook,
|
WorkflowVersionDeleteManyPreQueryHook,
|
||||||
|
WorkflowCreateManyPostQueryHook,
|
||||||
WorkflowVersionValidationWorkspaceService,
|
WorkflowVersionValidationWorkspaceService,
|
||||||
WorkflowCommonWorkspaceService,
|
WorkflowCommonWorkspaceService,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -6,12 +6,9 @@ import {
|
|||||||
WorkflowVersionStatus,
|
WorkflowVersionStatus,
|
||||||
WorkflowVersionWorkspaceEntity,
|
WorkflowVersionWorkspaceEntity,
|
||||||
} from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
|
} from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
|
||||||
import { WorkflowTrigger } from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type';
|
|
||||||
|
|
||||||
export const assertWorkflowVersionIsDraft = (
|
export const assertWorkflowVersionIsDraft = (
|
||||||
workflowVersion: Omit<WorkflowVersionWorkspaceEntity, 'trigger'> & {
|
workflowVersion: WorkflowVersionWorkspaceEntity,
|
||||||
trigger: WorkflowTrigger;
|
|
||||||
},
|
|
||||||
) => {
|
) => {
|
||||||
if (workflowVersion.status !== WorkflowVersionStatus.DRAFT) {
|
if (workflowVersion.status !== WorkflowVersionStatus.DRAFT) {
|
||||||
throw new WorkflowQueryValidationException(
|
throw new WorkflowQueryValidationException(
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
import { WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
|
||||||
|
import {
|
||||||
|
WorkflowTriggerException,
|
||||||
|
WorkflowTriggerExceptionCode,
|
||||||
|
} from 'src/modules/workflow/workflow-trigger/exceptions/workflow-trigger.exception';
|
||||||
|
import { WorkflowTrigger } from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type';
|
||||||
|
|
||||||
|
export function assertWorkflowVersionTriggerIsDefined(
|
||||||
|
workflowVersion: WorkflowVersionWorkspaceEntity,
|
||||||
|
): asserts workflowVersion is Omit<
|
||||||
|
WorkflowVersionWorkspaceEntity,
|
||||||
|
'trigger'
|
||||||
|
> & {
|
||||||
|
trigger: WorkflowTrigger;
|
||||||
|
} {
|
||||||
|
if (!workflowVersion.trigger) {
|
||||||
|
throw new WorkflowTriggerException(
|
||||||
|
'Workflow version does not contain trigger',
|
||||||
|
WorkflowTriggerExceptionCode.INVALID_WORKFLOW_VERSION,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,7 +2,6 @@ import { Injectable } from '@nestjs/common';
|
|||||||
|
|
||||||
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
||||||
import { WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
|
import { WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
|
||||||
import { WorkflowTrigger } from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type';
|
|
||||||
import {
|
import {
|
||||||
WorkflowTriggerException,
|
WorkflowTriggerException,
|
||||||
WorkflowTriggerExceptionCode,
|
WorkflowTriggerExceptionCode,
|
||||||
@ -12,11 +11,9 @@ import {
|
|||||||
export class WorkflowCommonWorkspaceService {
|
export class WorkflowCommonWorkspaceService {
|
||||||
constructor(private readonly twentyORMManager: TwentyORMManager) {}
|
constructor(private readonly twentyORMManager: TwentyORMManager) {}
|
||||||
|
|
||||||
async getWorkflowVersionOrFail(workflowVersionId: string): Promise<
|
async getWorkflowVersionOrFail(
|
||||||
Omit<WorkflowVersionWorkspaceEntity, 'trigger'> & {
|
workflowVersionId: string,
|
||||||
trigger: WorkflowTrigger;
|
): Promise<WorkflowVersionWorkspaceEntity> {
|
||||||
}
|
|
||||||
> {
|
|
||||||
if (!workflowVersionId) {
|
if (!workflowVersionId) {
|
||||||
throw new WorkflowTriggerException(
|
throw new WorkflowTriggerException(
|
||||||
'Workflow version ID is required',
|
'Workflow version ID is required',
|
||||||
@ -40,11 +37,7 @@ export class WorkflowCommonWorkspaceService {
|
|||||||
|
|
||||||
async getValidWorkflowVersionOrFail(
|
async getValidWorkflowVersionOrFail(
|
||||||
workflowVersion: WorkflowVersionWorkspaceEntity | null,
|
workflowVersion: WorkflowVersionWorkspaceEntity | null,
|
||||||
): Promise<
|
): Promise<WorkflowVersionWorkspaceEntity> {
|
||||||
Omit<WorkflowVersionWorkspaceEntity, 'trigger'> & {
|
|
||||||
trigger: WorkflowTrigger;
|
|
||||||
}
|
|
||||||
> {
|
|
||||||
if (!workflowVersion) {
|
if (!workflowVersion) {
|
||||||
throw new WorkflowTriggerException(
|
throw new WorkflowTriggerException(
|
||||||
'Workflow version not found',
|
'Workflow version not found',
|
||||||
@ -52,12 +45,13 @@ export class WorkflowCommonWorkspaceService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!workflowVersion.trigger) {
|
// FIXME: For now we will make the trigger optional. Later, we'll have to ensure the trigger is defined when publishing the flow.
|
||||||
throw new WorkflowTriggerException(
|
// if (!workflowVersion.trigger) {
|
||||||
'Workflow version does not contains trigger',
|
// throw new WorkflowTriggerException(
|
||||||
WorkflowTriggerExceptionCode.INVALID_WORKFLOW_VERSION,
|
// 'Workflow version does not contains trigger',
|
||||||
);
|
// WorkflowTriggerExceptionCode.INVALID_WORKFLOW_VERSION,
|
||||||
}
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
return { ...workflowVersion, trigger: workflowVersion.trigger };
|
return { ...workflowVersion, trigger: workflowVersion.trigger };
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,19 +3,14 @@ import {
|
|||||||
WorkflowVersionWorkspaceEntity,
|
WorkflowVersionWorkspaceEntity,
|
||||||
} from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
|
} from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
|
||||||
import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
|
import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
|
||||||
import {
|
|
||||||
WorkflowTrigger,
|
|
||||||
WorkflowTriggerType,
|
|
||||||
} from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type';
|
|
||||||
import {
|
import {
|
||||||
WorkflowTriggerException,
|
WorkflowTriggerException,
|
||||||
WorkflowTriggerExceptionCode,
|
WorkflowTriggerExceptionCode,
|
||||||
} from 'src/modules/workflow/workflow-trigger/exceptions/workflow-trigger.exception';
|
} from 'src/modules/workflow/workflow-trigger/exceptions/workflow-trigger.exception';
|
||||||
|
import { WorkflowTriggerType } from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type';
|
||||||
|
|
||||||
export function assertVersionCanBeActivated(
|
export function assertVersionCanBeActivated(
|
||||||
workflowVersion: Omit<WorkflowVersionWorkspaceEntity, 'trigger'> & {
|
workflowVersion: WorkflowVersionWorkspaceEntity,
|
||||||
trigger: WorkflowTrigger;
|
|
||||||
},
|
|
||||||
workflow: WorkflowWorkspaceEntity,
|
workflow: WorkflowWorkspaceEntity,
|
||||||
) {
|
) {
|
||||||
assertVersionIsValid(workflowVersion);
|
assertVersionIsValid(workflowVersion);
|
||||||
@ -37,11 +32,7 @@ export function assertVersionCanBeActivated(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function assertVersionIsValid(
|
function assertVersionIsValid(workflowVersion: WorkflowVersionWorkspaceEntity) {
|
||||||
workflowVersion: Omit<WorkflowVersionWorkspaceEntity, 'trigger'> & {
|
|
||||||
trigger: WorkflowTrigger;
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
if (!workflowVersion.trigger) {
|
if (!workflowVersion.trigger) {
|
||||||
throw new WorkflowTriggerException(
|
throw new WorkflowTriggerException(
|
||||||
'Workflow version does not contain trigger',
|
'Workflow version does not contain trigger',
|
||||||
|
|||||||
@ -8,24 +8,22 @@ import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/s
|
|||||||
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
||||||
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
||||||
import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter';
|
import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter';
|
||||||
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
|
||||||
import {
|
import {
|
||||||
WorkflowVersionStatus,
|
WorkflowVersionStatus,
|
||||||
WorkflowVersionWorkspaceEntity,
|
WorkflowVersionWorkspaceEntity,
|
||||||
} from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
|
} from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
|
||||||
import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
|
import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
|
||||||
import {
|
import { assertWorkflowVersionTriggerIsDefined } from 'src/modules/workflow/common/utils/assert-workflow-version-trigger-is-defined.util';
|
||||||
WorkflowTrigger,
|
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||||
WorkflowTriggerType,
|
|
||||||
} from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type';
|
|
||||||
import { WorkflowRunnerWorkspaceService } from 'src/modules/workflow/workflow-runner/workspace-services/workflow-runner.workspace-service';
|
import { WorkflowRunnerWorkspaceService } from 'src/modules/workflow/workflow-runner/workspace-services/workflow-runner.workspace-service';
|
||||||
import { WorkflowVersionStatusUpdate } from 'src/modules/workflow/workflow-status/jobs/workflow-statuses-update.job';
|
import { WorkflowVersionStatusUpdate } from 'src/modules/workflow/workflow-status/jobs/workflow-statuses-update.job';
|
||||||
import { DatabaseEventTriggerService } from 'src/modules/workflow/workflow-trigger/database-event-trigger/database-event-trigger.service';
|
import { DatabaseEventTriggerService } from 'src/modules/workflow/workflow-trigger/database-event-trigger/database-event-trigger.service';
|
||||||
import { assertVersionCanBeActivated } from 'src/modules/workflow/workflow-trigger/utils/assert-version-can-be-activated.util';
|
|
||||||
import {
|
import {
|
||||||
WorkflowTriggerException,
|
WorkflowTriggerException,
|
||||||
WorkflowTriggerExceptionCode,
|
WorkflowTriggerExceptionCode,
|
||||||
} from 'src/modules/workflow/workflow-trigger/exceptions/workflow-trigger.exception';
|
} from 'src/modules/workflow/workflow-trigger/exceptions/workflow-trigger.exception';
|
||||||
|
import { WorkflowTriggerType } from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type';
|
||||||
|
import { assertVersionCanBeActivated } from 'src/modules/workflow/workflow-trigger/utils/assert-version-can-be-activated.util';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WorkflowTriggerWorkspaceService {
|
export class WorkflowTriggerWorkspaceService {
|
||||||
@ -158,9 +156,7 @@ export class WorkflowTriggerWorkspaceService {
|
|||||||
|
|
||||||
private async performActivationSteps(
|
private async performActivationSteps(
|
||||||
workflow: WorkflowWorkspaceEntity,
|
workflow: WorkflowWorkspaceEntity,
|
||||||
workflowVersion: Omit<WorkflowVersionWorkspaceEntity, 'trigger'> & {
|
workflowVersion: WorkflowVersionWorkspaceEntity,
|
||||||
trigger: WorkflowTrigger;
|
|
||||||
},
|
|
||||||
workflowRepository: WorkspaceRepository<WorkflowWorkspaceEntity>,
|
workflowRepository: WorkspaceRepository<WorkflowWorkspaceEntity>,
|
||||||
workflowVersionRepository: WorkspaceRepository<WorkflowVersionWorkspaceEntity>,
|
workflowVersionRepository: WorkspaceRepository<WorkflowVersionWorkspaceEntity>,
|
||||||
manager: EntityManager,
|
manager: EntityManager,
|
||||||
@ -217,9 +213,7 @@ export class WorkflowTriggerWorkspaceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async setActiveVersionStatus(
|
private async setActiveVersionStatus(
|
||||||
workflowVersion: Omit<WorkflowVersionWorkspaceEntity, 'trigger'> & {
|
workflowVersion: WorkflowVersionWorkspaceEntity,
|
||||||
trigger: WorkflowTrigger;
|
|
||||||
},
|
|
||||||
workflowVersionRepository: WorkspaceRepository<WorkflowVersionWorkspaceEntity>,
|
workflowVersionRepository: WorkspaceRepository<WorkflowVersionWorkspaceEntity>,
|
||||||
manager: EntityManager,
|
manager: EntityManager,
|
||||||
) {
|
) {
|
||||||
@ -254,9 +248,7 @@ export class WorkflowTriggerWorkspaceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async setDeactivatedVersionStatus(
|
private async setDeactivatedVersionStatus(
|
||||||
workflowVersion: Omit<WorkflowVersionWorkspaceEntity, 'trigger'> & {
|
workflowVersion: WorkflowVersionWorkspaceEntity,
|
||||||
trigger: WorkflowTrigger;
|
|
||||||
},
|
|
||||||
workflowVersionRepository: WorkspaceRepository<WorkflowVersionWorkspaceEntity>,
|
workflowVersionRepository: WorkspaceRepository<WorkflowVersionWorkspaceEntity>,
|
||||||
manager: EntityManager,
|
manager: EntityManager,
|
||||||
) {
|
) {
|
||||||
@ -307,11 +299,11 @@ export class WorkflowTriggerWorkspaceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async enableTrigger(
|
private async enableTrigger(
|
||||||
workflowVersion: Omit<WorkflowVersionWorkspaceEntity, 'trigger'> & {
|
workflowVersion: WorkflowVersionWorkspaceEntity,
|
||||||
trigger: WorkflowTrigger;
|
|
||||||
},
|
|
||||||
manager: EntityManager,
|
manager: EntityManager,
|
||||||
) {
|
) {
|
||||||
|
assertWorkflowVersionTriggerIsDefined(workflowVersion);
|
||||||
|
|
||||||
switch (workflowVersion.trigger.type) {
|
switch (workflowVersion.trigger.type) {
|
||||||
case WorkflowTriggerType.DATABASE_EVENT:
|
case WorkflowTriggerType.DATABASE_EVENT:
|
||||||
await this.databaseEventTriggerService.createEventListener(
|
await this.databaseEventTriggerService.createEventListener(
|
||||||
@ -326,11 +318,11 @@ export class WorkflowTriggerWorkspaceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async disableTrigger(
|
private async disableTrigger(
|
||||||
workflowVersion: Omit<WorkflowVersionWorkspaceEntity, 'trigger'> & {
|
workflowVersion: WorkflowVersionWorkspaceEntity,
|
||||||
trigger: WorkflowTrigger;
|
|
||||||
},
|
|
||||||
manager: EntityManager,
|
manager: EntityManager,
|
||||||
) {
|
) {
|
||||||
|
assertWorkflowVersionTriggerIsDefined(workflowVersion);
|
||||||
|
|
||||||
switch (workflowVersion.trigger.type) {
|
switch (workflowVersion.trigger.type) {
|
||||||
case WorkflowTriggerType.DATABASE_EVENT:
|
case WorkflowTriggerType.DATABASE_EVENT:
|
||||||
await this.databaseEventTriggerService.deleteEventListener(
|
await this.databaseEventTriggerService.deleteEventListener(
|
||||||
|
|||||||
Reference in New Issue
Block a user