701 workflow improve webhook triggers (#11455)
as title Nota bene: I did not filter execution by http method. A POST webhook trigger can be triggered by a GET request for more flexibility. Tell me if you think it is a mistake https://github.com/user-attachments/assets/1833cbea-51a8-4772-bcd8-088d6a087e79
This commit is contained in:
@ -8,11 +8,14 @@ import { InputLabel } from '@/ui/input/components/InputLabel';
|
|||||||
import { useId } from 'react';
|
import { useId } from 'react';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly';
|
import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly';
|
||||||
|
import { InputErrorHelper } from '@/ui/input/components/InputErrorHelper';
|
||||||
|
|
||||||
type FormRawJsonFieldInputProps = {
|
type FormRawJsonFieldInputProps = {
|
||||||
label?: string;
|
label?: string;
|
||||||
|
error?: string;
|
||||||
defaultValue: string | null | undefined;
|
defaultValue: string | null | undefined;
|
||||||
onChange: (value: string | null) => void;
|
onChange: (value: string | null) => void;
|
||||||
|
onBlur?: () => void;
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
VariablePicker?: VariablePickerComponent;
|
VariablePicker?: VariablePickerComponent;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
@ -20,9 +23,11 @@ type FormRawJsonFieldInputProps = {
|
|||||||
|
|
||||||
export const FormRawJsonFieldInput = ({
|
export const FormRawJsonFieldInput = ({
|
||||||
label,
|
label,
|
||||||
|
error,
|
||||||
defaultValue,
|
defaultValue,
|
||||||
placeholder,
|
placeholder,
|
||||||
onChange,
|
onChange,
|
||||||
|
onBlur,
|
||||||
readonly,
|
readonly,
|
||||||
VariablePicker,
|
VariablePicker,
|
||||||
}: FormRawJsonFieldInputProps) => {
|
}: FormRawJsonFieldInputProps) => {
|
||||||
@ -68,6 +73,7 @@ export const FormRawJsonFieldInput = ({
|
|||||||
<FormFieldInputInputContainer
|
<FormFieldInputInputContainer
|
||||||
hasRightElement={isDefined(VariablePicker) && !readonly}
|
hasRightElement={isDefined(VariablePicker) && !readonly}
|
||||||
multiline
|
multiline
|
||||||
|
onBlur={onBlur}
|
||||||
>
|
>
|
||||||
<TextVariableEditor editor={editor} multiline readonly={readonly} />
|
<TextVariableEditor editor={editor} multiline readonly={readonly} />
|
||||||
</FormFieldInputInputContainer>
|
</FormFieldInputInputContainer>
|
||||||
@ -80,6 +86,7 @@ export const FormRawJsonFieldInput = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</FormFieldInputRowContainer>
|
</FormFieldInputRowContainer>
|
||||||
|
<InputErrorHelper>{error}</InputErrorHelper>
|
||||||
</FormFieldInputContainer>
|
</FormFieldInputContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,7 +5,7 @@ const StyledInputErrorHelper = styled.div`
|
|||||||
color: ${({ theme }) => theme.color.red};
|
color: ${({ theme }) => theme.color.red};
|
||||||
font-size: ${({ theme }) => theme.font.size.xs};
|
font-size: ${({ theme }) => theme.font.size.xs};
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc(100% + ${({ theme }) => theme.spacing(0.25)});
|
margin-top: ${({ theme }) => theme.spacing(0.25)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const InputErrorHelper = ({
|
export const InputErrorHelper = ({
|
||||||
|
|||||||
@ -209,9 +209,19 @@ export const workflowCronTriggerSchema = baseTriggerSchema.extend({
|
|||||||
|
|
||||||
export const workflowWebhookTriggerSchema = baseTriggerSchema.extend({
|
export const workflowWebhookTriggerSchema = baseTriggerSchema.extend({
|
||||||
type: z.literal('WEBHOOK'),
|
type: z.literal('WEBHOOK'),
|
||||||
settings: z.object({
|
settings: z.discriminatedUnion('httpMethod', [
|
||||||
outputSchema: z.object({}).passthrough(),
|
z.object({
|
||||||
}),
|
outputSchema: z.object({}).passthrough(),
|
||||||
|
httpMethod: z.literal('GET'),
|
||||||
|
authentication: z.literal('API_KEY').nullable(),
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
outputSchema: z.object({}).passthrough(),
|
||||||
|
httpMethod: z.literal('POST'),
|
||||||
|
expectedBody: z.object({}).passthrough(),
|
||||||
|
authentication: z.literal('API_KEY').nullable(),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Combined trigger schema
|
// Combined trigger schema
|
||||||
|
|||||||
@ -14,6 +14,13 @@ import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
|||||||
import { REACT_APP_SERVER_BASE_URL } from '~/config';
|
import { REACT_APP_SERVER_BASE_URL } from '~/config';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { useIcons, IconCopy } from 'twenty-ui/display';
|
import { useIcons, IconCopy } from 'twenty-ui/display';
|
||||||
|
import { Select } from '@/ui/input/components/Select';
|
||||||
|
import { WEBHOOK_TRIGGER_HTTP_METHOD_OPTIONS } from '@/workflow/workflow-trigger/constants/WebhookTriggerHttpMethodOptions';
|
||||||
|
import { getWebhookTriggerDefaultSettings } from '@/workflow/workflow-trigger/utils/getWebhookTriggerDefaultSettings';
|
||||||
|
import { WEBHOOK_TRIGGER_AUTHENTICATION_OPTIONS } from '@/workflow/workflow-trigger/constants/WebhookTriggerAuthenticationOptions';
|
||||||
|
import { FormRawJsonFieldInput } from '@/object-record/record-field/form-types/components/FormRawJsonFieldInput';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { getFunctionOutputSchema } from '@/serverless-functions/utils/getFunctionOutputSchema';
|
||||||
|
|
||||||
type WorkflowEditTriggerWebhookFormProps = {
|
type WorkflowEditTriggerWebhookFormProps = {
|
||||||
trigger: WorkflowWebhookTrigger;
|
trigger: WorkflowWebhookTrigger;
|
||||||
@ -24,9 +31,17 @@ type WorkflowEditTriggerWebhookFormProps = {
|
|||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
readonly?: false;
|
readonly?: false;
|
||||||
onTriggerUpdate: (trigger: WorkflowWebhookTrigger) => void;
|
onTriggerUpdate: (
|
||||||
|
trigger: WorkflowWebhookTrigger,
|
||||||
|
options?: { computeOutputSchema: boolean },
|
||||||
|
) => void;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type FormErrorMessages = {
|
||||||
|
expectedBody?: string | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
export const WorkflowEditTriggerWebhookForm = ({
|
export const WorkflowEditTriggerWebhookForm = ({
|
||||||
trigger,
|
trigger,
|
||||||
triggerOptions,
|
triggerOptions,
|
||||||
@ -34,10 +49,16 @@ export const WorkflowEditTriggerWebhookForm = ({
|
|||||||
const { enqueueSnackBar } = useSnackBar();
|
const { enqueueSnackBar } = useSnackBar();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
|
const [errorMessages, setErrorMessages] = useState<FormErrorMessages>({});
|
||||||
|
const [errorMessagesVisible, setErrorMessagesVisible] = useState(false);
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
const workflowId = useRecoilValue(workflowIdState);
|
const workflowId = useRecoilValue(workflowIdState);
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||||
|
|
||||||
|
const onBlur = () => {
|
||||||
|
setErrorMessagesVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
const headerTitle = isDefined(trigger.name) ? trigger.name : 'Webhook';
|
const headerTitle = isDefined(trigger.name) ? trigger.name : 'Webhook';
|
||||||
|
|
||||||
const headerIcon = getTriggerIcon({
|
const headerIcon = getTriggerIcon({
|
||||||
@ -93,6 +114,97 @@ export const WorkflowEditTriggerWebhookForm = ({
|
|||||||
onRightIconClick={copyToClipboardDebounced}
|
onRightIconClick={copyToClipboardDebounced}
|
||||||
readOnly
|
readOnly
|
||||||
/>
|
/>
|
||||||
|
<Select
|
||||||
|
dropdownId="workflow-edit-webhook-trigger-http-method"
|
||||||
|
label="HTTP method"
|
||||||
|
fullWidth
|
||||||
|
disabled={triggerOptions.readonly}
|
||||||
|
value={trigger.settings.httpMethod}
|
||||||
|
options={WEBHOOK_TRIGGER_HTTP_METHOD_OPTIONS}
|
||||||
|
onChange={(newTriggerType) => {
|
||||||
|
if (triggerOptions.readonly === true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerOptions.onTriggerUpdate(
|
||||||
|
{
|
||||||
|
...trigger,
|
||||||
|
settings: getWebhookTriggerDefaultSettings(newTriggerType),
|
||||||
|
},
|
||||||
|
{ computeOutputSchema: false },
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{trigger.settings.httpMethod === 'POST' && (
|
||||||
|
<FormRawJsonFieldInput
|
||||||
|
label="Expected Body"
|
||||||
|
placeholder="Enter a JSON object"
|
||||||
|
error={
|
||||||
|
errorMessagesVisible ? errorMessages.expectedBody : undefined
|
||||||
|
}
|
||||||
|
onBlur={onBlur}
|
||||||
|
readonly={triggerOptions.readonly}
|
||||||
|
defaultValue={JSON.stringify(trigger.settings.expectedBody)}
|
||||||
|
onChange={(newExpectedBody) => {
|
||||||
|
if (triggerOptions.readonly === true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let formattedExpectedBody = {};
|
||||||
|
try {
|
||||||
|
formattedExpectedBody = JSON.parse(newExpectedBody || '{}');
|
||||||
|
} catch (e) {
|
||||||
|
setErrorMessages((prev) => ({
|
||||||
|
...prev,
|
||||||
|
expectedBody: String(e),
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setErrorMessages((prev) => ({
|
||||||
|
...prev,
|
||||||
|
expectedBody: undefined,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const outputSchema = getFunctionOutputSchema(
|
||||||
|
formattedExpectedBody,
|
||||||
|
);
|
||||||
|
|
||||||
|
triggerOptions.onTriggerUpdate(
|
||||||
|
{
|
||||||
|
...trigger,
|
||||||
|
settings: {
|
||||||
|
...trigger.settings,
|
||||||
|
expectedBody: formattedExpectedBody,
|
||||||
|
outputSchema,
|
||||||
|
} as WorkflowWebhookTrigger['settings'],
|
||||||
|
},
|
||||||
|
{ computeOutputSchema: false },
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Select
|
||||||
|
dropdownId="workflow-edit-webhook-trigger-auth"
|
||||||
|
label="Auth"
|
||||||
|
fullWidth
|
||||||
|
disabled
|
||||||
|
value={trigger.settings.authentication}
|
||||||
|
options={WEBHOOK_TRIGGER_AUTHENTICATION_OPTIONS}
|
||||||
|
onChange={(newAuthenticationType) => {
|
||||||
|
if (triggerOptions.readonly === true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerOptions.onTriggerUpdate({
|
||||||
|
...trigger,
|
||||||
|
settings: {
|
||||||
|
...trigger.settings,
|
||||||
|
authentication: newAuthenticationType,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</WorkflowStepBody>
|
</WorkflowStepBody>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -0,0 +1,19 @@
|
|||||||
|
import { IconComponent, IconLockOpen, IconFlag } from 'twenty-ui/display';
|
||||||
|
export type AuthenticationMethods = 'API_KEY' | null;
|
||||||
|
|
||||||
|
export const WEBHOOK_TRIGGER_AUTHENTICATION_OPTIONS: Array<{
|
||||||
|
label: string;
|
||||||
|
value: AuthenticationMethods;
|
||||||
|
Icon: IconComponent;
|
||||||
|
}> = [
|
||||||
|
{
|
||||||
|
label: 'None',
|
||||||
|
value: null,
|
||||||
|
Icon: IconLockOpen,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'API key',
|
||||||
|
value: 'API_KEY',
|
||||||
|
Icon: IconFlag,
|
||||||
|
},
|
||||||
|
];
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
import { IconComponent, IconHttpPost, IconHttpGet } from 'twenty-ui/display';
|
||||||
|
export type WebhookHttpMethods = 'GET' | 'POST';
|
||||||
|
|
||||||
|
export const WEBHOOK_TRIGGER_HTTP_METHOD_OPTIONS: Array<{
|
||||||
|
label: string;
|
||||||
|
value: WebhookHttpMethods;
|
||||||
|
Icon: IconComponent;
|
||||||
|
}> = [
|
||||||
|
{
|
||||||
|
label: 'Get',
|
||||||
|
value: 'GET',
|
||||||
|
Icon: IconHttpGet,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Post',
|
||||||
|
value: 'POST',
|
||||||
|
Icon: IconHttpPost,
|
||||||
|
},
|
||||||
|
];
|
||||||
@ -23,23 +23,28 @@ export const useUpdateWorkflowVersionTrigger = ({
|
|||||||
|
|
||||||
const { computeStepOutputSchema } = useComputeStepOutputSchema();
|
const { computeStepOutputSchema } = useComputeStepOutputSchema();
|
||||||
|
|
||||||
const updateTrigger = async (updatedTrigger: WorkflowTrigger) => {
|
const updateTrigger = async (
|
||||||
|
updatedTrigger: WorkflowTrigger,
|
||||||
|
options: { computeOutputSchema: boolean } = { computeOutputSchema: true },
|
||||||
|
) => {
|
||||||
if (!isDefined(workflow.currentVersion)) {
|
if (!isDefined(workflow.currentVersion)) {
|
||||||
throw new Error('Can not update an undefined workflow version.');
|
throw new Error('Can not update an undefined workflow version.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const workflowVersionId = await getUpdatableWorkflowVersion(workflow);
|
const workflowVersionId = await getUpdatableWorkflowVersion(workflow);
|
||||||
|
|
||||||
const outputSchema = (
|
if (options.computeOutputSchema) {
|
||||||
await computeStepOutputSchema({
|
const outputSchema = (
|
||||||
step: updatedTrigger,
|
await computeStepOutputSchema({
|
||||||
})
|
step: updatedTrigger,
|
||||||
)?.data?.computeStepOutputSchema;
|
})
|
||||||
|
)?.data?.computeStepOutputSchema;
|
||||||
|
|
||||||
updatedTrigger.settings = {
|
updatedTrigger.settings = {
|
||||||
...updatedTrigger.settings,
|
...updatedTrigger.settings,
|
||||||
outputSchema: outputSchema || {},
|
outputSchema: outputSchema || {},
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
await updateOneWorkflowVersion({
|
await updateOneWorkflowVersion({
|
||||||
idToUpdate: workflowVersionId,
|
idToUpdate: workflowVersionId,
|
||||||
|
|||||||
@ -0,0 +1,39 @@
|
|||||||
|
import { getWebhookTriggerDefaultSettings } from '@/workflow/workflow-trigger/utils/getWebhookTriggerDefaultSettings';
|
||||||
|
|
||||||
|
describe('getWebhookTriggerDefaultSettings', () => {
|
||||||
|
it('returns correct settings for GET http method', () => {
|
||||||
|
const result = getWebhookTriggerDefaultSettings('GET');
|
||||||
|
expect(result).toEqual({
|
||||||
|
authentication: null,
|
||||||
|
httpMethod: 'GET',
|
||||||
|
outputSchema: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns correct settings for POST http method', () => {
|
||||||
|
const result = getWebhookTriggerDefaultSettings('POST');
|
||||||
|
expect(result).toEqual({
|
||||||
|
authentication: null,
|
||||||
|
httpMethod: 'POST',
|
||||||
|
expectedBody: {
|
||||||
|
message: 'Workflow was started',
|
||||||
|
},
|
||||||
|
outputSchema: {
|
||||||
|
message: {
|
||||||
|
icon: 'IconVariable',
|
||||||
|
isLeaf: true,
|
||||||
|
label: 'message',
|
||||||
|
type: 'string',
|
||||||
|
value: 'Workflow was started',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error for an invalid http method', () => {
|
||||||
|
// @ts-expect-error Testing invalid input
|
||||||
|
expect(() => getWebhookTriggerDefaultSettings('INVALID')).toThrowError(
|
||||||
|
'Invalid webhook http method',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -64,6 +64,8 @@ export const getTriggerDefaultDefinition = ({
|
|||||||
name: defaultLabel,
|
name: defaultLabel,
|
||||||
settings: {
|
settings: {
|
||||||
outputSchema: {},
|
outputSchema: {},
|
||||||
|
httpMethod: 'GET',
|
||||||
|
authentication: null,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,34 @@
|
|||||||
|
import { WorkflowWebhookTrigger } from '@/workflow/types/Workflow';
|
||||||
|
import { assertUnreachable } from '@/workflow/utils/assertUnreachable';
|
||||||
|
import { WebhookHttpMethods } from '@/workflow/workflow-trigger/constants/WebhookTriggerHttpMethodOptions';
|
||||||
|
|
||||||
|
export const getWebhookTriggerDefaultSettings = (
|
||||||
|
webhookHttpMethods: WebhookHttpMethods,
|
||||||
|
): WorkflowWebhookTrigger['settings'] => {
|
||||||
|
switch (webhookHttpMethods) {
|
||||||
|
case 'GET':
|
||||||
|
return {
|
||||||
|
outputSchema: {},
|
||||||
|
httpMethod: webhookHttpMethods,
|
||||||
|
authentication: null,
|
||||||
|
};
|
||||||
|
case 'POST':
|
||||||
|
return {
|
||||||
|
outputSchema: {
|
||||||
|
message: {
|
||||||
|
icon: 'IconVariable',
|
||||||
|
type: 'string',
|
||||||
|
label: 'message',
|
||||||
|
value: 'Workflow was started',
|
||||||
|
isLeaf: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
httpMethod: webhookHttpMethods,
|
||||||
|
expectedBody: {
|
||||||
|
message: 'Workflow was started',
|
||||||
|
},
|
||||||
|
authentication: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return assertUnreachable(webhookHttpMethods, 'Invalid webhook http method');
|
||||||
|
};
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import { Controller, Get, Param, UseFilters } from '@nestjs/common';
|
import { Controller, Get, Param, Post, Req, UseFilters } from '@nestjs/common';
|
||||||
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
import { Request } from 'express';
|
||||||
|
|
||||||
import { WorkflowTriggerWorkspaceService } from 'src/modules/workflow/workflow-trigger/workspace-services/workflow-trigger.workspace-service';
|
import { WorkflowTriggerWorkspaceService } from 'src/modules/workflow/workflow-trigger/workspace-services/workflow-trigger.workspace-service';
|
||||||
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
||||||
@ -22,11 +23,26 @@ export class WorkflowTriggerController {
|
|||||||
private readonly workflowTriggerWorkspaceService: WorkflowTriggerWorkspaceService,
|
private readonly workflowTriggerWorkspaceService: WorkflowTriggerWorkspaceService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Get('workflows/:workspaceId/:workflowId')
|
@Post('workflows/:workspaceId/:workflowId')
|
||||||
async runWorkflow(
|
async runWorkflowByPostRequest(
|
||||||
@Param('workspaceId') workspaceId: string,
|
|
||||||
@Param('workflowId') workflowId: string,
|
@Param('workflowId') workflowId: string,
|
||||||
|
@Req() request: Request,
|
||||||
) {
|
) {
|
||||||
|
return await this.runWorkflow({ workflowId, payload: request.body || {} });
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('workflows/:workspaceId/:workflowId')
|
||||||
|
async runWorkflowByGetRequest(@Param('workflowId') workflowId: string) {
|
||||||
|
return await this.runWorkflow({ workflowId });
|
||||||
|
}
|
||||||
|
|
||||||
|
private async runWorkflow({
|
||||||
|
workflowId,
|
||||||
|
payload,
|
||||||
|
}: {
|
||||||
|
workflowId: string;
|
||||||
|
payload?: object;
|
||||||
|
}) {
|
||||||
const workflowRepository =
|
const workflowRepository =
|
||||||
await this.twentyORMManager.getRepository<WorkflowWorkspaceEntity>(
|
await this.twentyORMManager.getRepository<WorkflowWorkspaceEntity>(
|
||||||
'workflow',
|
'workflow',
|
||||||
@ -78,7 +94,7 @@ export class WorkflowTriggerController {
|
|||||||
const { workflowRunId } =
|
const { workflowRunId } =
|
||||||
await this.workflowTriggerWorkspaceService.runWorkflowVersion({
|
await this.workflowTriggerWorkspaceService.runWorkflowVersion({
|
||||||
workflowVersionId: workflow.lastPublishedVersionId,
|
workflowVersionId: workflow.lastPublishedVersionId,
|
||||||
payload: {},
|
payload: payload || {},
|
||||||
createdBy: {
|
createdBy: {
|
||||||
source: FieldActorSource.WEBHOOK,
|
source: FieldActorSource.WEBHOOK,
|
||||||
workspaceMemberId: null,
|
workspaceMemberId: null,
|
||||||
|
|||||||
@ -61,6 +61,16 @@ export type WorkflowCronTrigger = BaseTrigger & {
|
|||||||
|
|
||||||
export type WorkflowWebhookTrigger = BaseTrigger & {
|
export type WorkflowWebhookTrigger = BaseTrigger & {
|
||||||
type: WorkflowTriggerType.WEBHOOK;
|
type: WorkflowTriggerType.WEBHOOK;
|
||||||
|
settings:
|
||||||
|
| {
|
||||||
|
httpMethod: 'GET';
|
||||||
|
authentication: 'API_KEY' | null;
|
||||||
|
}
|
||||||
|
| ({
|
||||||
|
httpMethod: 'POST';
|
||||||
|
authentication: 'API_KEY' | null;
|
||||||
|
expectedBody: object;
|
||||||
|
} & { outputSchema: object });
|
||||||
};
|
};
|
||||||
|
|
||||||
export type WorkflowManualTriggerSettings = WorkflowManualTrigger['settings'];
|
export type WorkflowManualTriggerSettings = WorkflowManualTrigger['settings'];
|
||||||
|
|||||||
@ -169,6 +169,8 @@ export {
|
|||||||
IconHistoryToggle,
|
IconHistoryToggle,
|
||||||
IconHome,
|
IconHome,
|
||||||
IconHours24,
|
IconHours24,
|
||||||
|
IconHttpGet,
|
||||||
|
IconHttpPost,
|
||||||
IconId,
|
IconId,
|
||||||
IconInbox,
|
IconInbox,
|
||||||
IconInfoCircle,
|
IconInfoCircle,
|
||||||
|
|||||||
@ -230,6 +230,8 @@ export {
|
|||||||
IconHistoryToggle,
|
IconHistoryToggle,
|
||||||
IconHome,
|
IconHome,
|
||||||
IconHours24,
|
IconHours24,
|
||||||
|
IconHttpGet,
|
||||||
|
IconHttpPost,
|
||||||
IconId,
|
IconId,
|
||||||
IconInbox,
|
IconInbox,
|
||||||
IconInfoCircle,
|
IconInfoCircle,
|
||||||
|
|||||||
Reference in New Issue
Block a user