Add Activepieces integration for workflow automation
- Add Activepieces fork with SmoothSchedule custom piece - Create integrations app with Activepieces service layer - Add embed token endpoint for iframe integration - Create Automations page with embedded workflow builder - Add sidebar visibility fix for embed mode - Add list inactive customers endpoint to Public API - Include SmoothSchedule triggers: event created/updated/cancelled - Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": ["../../../../.eslintrc.base.json"],
|
||||
"ignorePatterns": ["!**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# pieces-subflows
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Building
|
||||
|
||||
Run `nx build pieces-subflows` to build the library.
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "@activepieces/piece-subflows",
|
||||
"version": "0.4.7"
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"name": "pieces-subflows",
|
||||
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "packages/pieces/community/subflows/src",
|
||||
"projectType": "library",
|
||||
"release": {
|
||||
"version": {
|
||||
"currentVersionResolver": "git-tag",
|
||||
"preserveLocalDependencyProtocols": false,
|
||||
"manifestRootsToUpdate": [
|
||||
"dist/{projectRoot}"
|
||||
]
|
||||
}
|
||||
},
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/js:tsc",
|
||||
"outputs": [
|
||||
"{options.outputPath}"
|
||||
],
|
||||
"options": {
|
||||
"outputPath": "dist/packages/pieces/community/subflows",
|
||||
"tsConfig": "packages/pieces/community/subflows/tsconfig.lib.json",
|
||||
"packageJson": "packages/pieces/community/subflows/package.json",
|
||||
"main": "packages/pieces/community/subflows/src/index.ts",
|
||||
"assets": [
|
||||
"packages/pieces/community/subflows/*.md",
|
||||
{
|
||||
"input": "packages/pieces/community/subflows/src/i18n",
|
||||
"output": "./src/i18n",
|
||||
"glob": "**/!(i18n.json)"
|
||||
}
|
||||
],
|
||||
"buildableProjectDepsInPackageJsonType": "dependencies",
|
||||
"updateBuildableProjectDepsInPackageJson": true
|
||||
},
|
||||
"dependsOn": [
|
||||
"^build",
|
||||
"prebuild"
|
||||
]
|
||||
},
|
||||
"nx-release-publish": {
|
||||
"options": {
|
||||
"packageRoot": "dist/{projectRoot}"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint",
|
||||
"outputs": [
|
||||
"{options.outputFile}"
|
||||
]
|
||||
},
|
||||
"prebuild": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"cwd": "packages/pieces/community/subflows",
|
||||
"command": "bun install --no-save --silent"
|
||||
},
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"Sub Flows": "Sub Flows",
|
||||
"Trigger and call another sub flow.": "Trigger and call another sub flow.",
|
||||
"Call Flow": "Call Flow",
|
||||
"Return Response": "Return Response",
|
||||
"Call a flow that has \"Callable Flow\" trigger": "Call a flow that has \"Callable Flow\" trigger",
|
||||
"Return response to the original flow": "Return response to the original flow",
|
||||
"Flow": "Flow",
|
||||
"Mode": "Mode",
|
||||
"Wait for Response": "Wait for Response",
|
||||
"Response": "Response",
|
||||
"The flow to execute": "The flow to execute",
|
||||
"Choose Simple for key-value or Advanced for JSON.": "Choose Simple for key-value or Advanced for JSON.",
|
||||
"Simple": "Simple",
|
||||
"Advanced": "Advanced",
|
||||
"Callable Flow": "Callable Flow",
|
||||
"Waiting to be triggered from another flow": "Waiting to be triggered from another flow",
|
||||
"Sample Data": "Sample Data",
|
||||
"The schema to be passed to the flow": "The schema to be passed to the flow"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"Trigger and call another sub flow.": "Trigger und rufen Sie einen anderen Subfluss.",
|
||||
"Call Flow": "Anruffluss",
|
||||
"Return Response": "Rückgabeantwort",
|
||||
"Call a flow that has \"Callable Flow\" trigger": "Rufe einen Fluss auf, der \"Callable Flow\" auslöst",
|
||||
"Return response to the original flow": "Zurück zur Antwort auf den ursprünglichen Fluss",
|
||||
"Flow": "Ablauf",
|
||||
"Mode": "Modus",
|
||||
"Wait for Response": "Warte auf Antwort",
|
||||
"Response": "Antwort",
|
||||
"The flow to execute": "Der auszuführende Flow",
|
||||
"Choose Simple for key-value or Advanced for JSON.": "Wählen Sie Einfache für den Schlüsselwert oder Erweitert für JSON.",
|
||||
"Simple": "Einfach",
|
||||
"Advanced": "Erweitert",
|
||||
"Callable Flow": "Anrufbarer Flow",
|
||||
"Waiting to be triggered from another flow": "Warte auf Auslösung von einem anderen Fluss",
|
||||
"Sample Data": "Beispieldaten",
|
||||
"The schema to be passed to the flow": "Das Schema, das an den Fluss übergeben werden soll"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"Trigger and call another sub flow.": "Activa y llama a otro sub-flujo.",
|
||||
"Call Flow": "Llamada Flow",
|
||||
"Return Response": "Respuesta de retorno",
|
||||
"Call a flow that has \"Callable Flow\" trigger": "Llamar a un flujo que tiene activado \"flujo llamable\"",
|
||||
"Return response to the original flow": "Devuelve la respuesta al flujo original",
|
||||
"Flow": "Flujo",
|
||||
"Mode": "Modo",
|
||||
"Wait for Response": "Espere a la respuesta",
|
||||
"Response": "Respuesta",
|
||||
"The flow to execute": "El flujo a ejecutar",
|
||||
"Choose Simple for key-value or Advanced for JSON.": "Elija Simple para el valor de clave o avanzado para JSON.",
|
||||
"Simple": "Simple",
|
||||
"Advanced": "Avanzado",
|
||||
"Callable Flow": "Flujo Llamable",
|
||||
"Waiting to be triggered from another flow": "Esperando a ser activado desde otro flujo",
|
||||
"Sample Data": "Datos de ejemplo",
|
||||
"The schema to be passed to the flow": "El esquema a pasar al flujo"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"Trigger and call another sub flow.": "Déclenchez et appelez un autre sous-flux.",
|
||||
"Call Flow": "Flux d'appel",
|
||||
"Return Response": "Réponse de retour",
|
||||
"Call a flow that has \"Callable Flow\" trigger": "Appeler un flux qui a le déclencheur \"Callable Flow\"",
|
||||
"Return response to the original flow": "Renvoyer la réponse au flux d'origine",
|
||||
"Flow": "Flow",
|
||||
"Mode": "Mode",
|
||||
"Wait for Response": "Attendre la réponse",
|
||||
"Response": "Réponse",
|
||||
"The flow to execute": "Le flux à exécuter",
|
||||
"Choose Simple for key-value or Advanced for JSON.": "Choisissez Simple pour la valeur de la clé ou Advanced pour JSON.",
|
||||
"Simple": "Simple",
|
||||
"Advanced": "Avancé",
|
||||
"Callable Flow": "Flux appelable",
|
||||
"Waiting to be triggered from another flow": "En attente d'être déclenchée à partir d'un autre flux",
|
||||
"Sample Data": "Données d'échantillonnage",
|
||||
"The schema to be passed to the flow": "Le schéma à passer au flux"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"Sub Flows": "Sub Flows",
|
||||
"Trigger and call another sub flow.": "Trigger and call another sub flow.",
|
||||
"Call Flow": "Call Flow",
|
||||
"Return Response": "Return Response",
|
||||
"Call a flow that has \"Callable Flow\" trigger": "Call a flow that has \"Callable Flow\" trigger",
|
||||
"Return response to the original flow": "Return response to the original flow",
|
||||
"Flow": "Flow",
|
||||
"Mode": "Mode",
|
||||
"Wait for Response": "Wait for Response",
|
||||
"Response": "Response",
|
||||
"The flow to execute": "The flow to execute",
|
||||
"Choose Simple for key-value or Advanced for JSON.": "Choose Simple for key-value or Advanced for JSON.",
|
||||
"Simple": "Simple",
|
||||
"Advanced": "Advanced",
|
||||
"Callable Flow": "Callable Flow",
|
||||
"Waiting to be triggered from another flow": "Waiting to be triggered from another flow",
|
||||
"Sample Data": "Sample Data",
|
||||
"The schema to be passed to the flow": "The schema to be passed to the flow"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"Sub Flows": "Sub Flows",
|
||||
"Trigger and call another sub flow.": "Trigger and call another sub flow.",
|
||||
"Call Flow": "Call Flow",
|
||||
"Return Response": "Return Response",
|
||||
"Call a flow that has \"Callable Flow\" trigger": "Call a flow that has \"Callable Flow\" trigger",
|
||||
"Return response to the original flow": "Return response to the original flow",
|
||||
"Flow": "Flow",
|
||||
"Mode": "Mode",
|
||||
"Wait for Response": "Wait for Response",
|
||||
"Response": "Response",
|
||||
"The flow to execute": "The flow to execute",
|
||||
"Choose Simple for key-value or Advanced for JSON.": "Choose Simple for key-value or Advanced for JSON.",
|
||||
"Simple": "Simple",
|
||||
"Advanced": "Advanced",
|
||||
"Callable Flow": "Callable Flow",
|
||||
"Waiting to be triggered from another flow": "Waiting to be triggered from another flow",
|
||||
"Sample Data": "Sample Data",
|
||||
"The schema to be passed to the flow": "The schema to be passed to the flow"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"Trigger and call another sub flow.": "別のサブフローをトリガーして呼び出します。",
|
||||
"Call Flow": "コールフロー",
|
||||
"Return Response": "返品対応",
|
||||
"Call a flow that has \"Callable Flow\" trigger": "\"Callable Flow\" トリガーがあるフローを呼び出します。",
|
||||
"Return response to the original flow": "元のフローに返信する",
|
||||
"Flow": "Flow",
|
||||
"Mode": "モード",
|
||||
"Wait for Response": "応答待ち",
|
||||
"Response": "回答",
|
||||
"The flow to execute": "実行するフロー",
|
||||
"Choose Simple for key-value or Advanced for JSON.": "JSONの場合は「単純」、または「高度」を選択します。",
|
||||
"Simple": "単純な",
|
||||
"Advanced": "高度な設定",
|
||||
"Callable Flow": "呼び出し可能なフロー",
|
||||
"Waiting to be triggered from another flow": "別のフローからのトリガーを待機しています",
|
||||
"Sample Data": "サンプルデータ",
|
||||
"The schema to be passed to the flow": "フローに渡されるスキーマ"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"Trigger and call another sub flow.": "Trigger en bel een andere sub-stroom.",
|
||||
"Call Flow": "Bel Flow",
|
||||
"Return Response": "Antwoord retour",
|
||||
"Call a flow that has \"Callable Flow\" trigger": "Bel een stroom aan die \"Callable Flow\" trigger heeft",
|
||||
"Return response to the original flow": "Retourneer reactie op de originele stroom",
|
||||
"Flow": "Stroom",
|
||||
"Mode": "Modus",
|
||||
"Wait for Response": "Wacht op reactie",
|
||||
"Response": "Antwoord",
|
||||
"The flow to execute": "De stroom om uit te voeren",
|
||||
"Choose Simple for key-value or Advanced for JSON.": "Kies Simpel voor sleutelwaarde of Geavanceerd voor JSON.",
|
||||
"Simple": "Eenvoudig",
|
||||
"Advanced": "Geavanceerd",
|
||||
"Callable Flow": "Kalmerbare Stroom",
|
||||
"Waiting to be triggered from another flow": "Wachten om geactiveerd te worden via een andere stroom",
|
||||
"Sample Data": "Voorbeeld gegevens",
|
||||
"The schema to be passed to the flow": "Het schema dat aan de stroom moet worden doorgegeven"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"Trigger and call another sub flow.": "Disparar e chamar outro sub fluxo.",
|
||||
"Call Flow": "Ligar para Flow",
|
||||
"Return Response": "Retornar Resposta",
|
||||
"Call a flow that has \"Callable Flow\" trigger": "Chamar um fluxo com o gatilho \"Flow Callable\"",
|
||||
"Return response to the original flow": "Retornar a resposta ao fluxo original",
|
||||
"Flow": "Fluxo",
|
||||
"Mode": "Modo",
|
||||
"Wait for Response": "Aguarda Resposta",
|
||||
"Response": "Resposta",
|
||||
"The flow to execute": "Fluxo para executar",
|
||||
"Choose Simple for key-value or Advanced for JSON.": "Escolha Simples para o valor-chave ou Avançado para JSON.",
|
||||
"Simple": "Simples",
|
||||
"Advanced": "Avançado",
|
||||
"Callable Flow": "Fluxo de chamada",
|
||||
"Waiting to be triggered from another flow": "Esperando para ser acionado de outro fluxo",
|
||||
"Sample Data": "Conteúdo de Exemplo",
|
||||
"The schema to be passed to the flow": "O esquema a ser passado ao fluxo"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"Sub Flows": "Под-потоки",
|
||||
"Trigger and call another sub flow.": "Запустите и вызовите другой подпоток.",
|
||||
"Call Flow": "Вызов по тесту",
|
||||
"Return Response": "Ответ на возврат",
|
||||
"Call a flow that has \"Callable Flow\" trigger": "Вызов потока, который имеет триггер \"Callable Flow\"",
|
||||
"Return response to the original flow": "Возврат ответа на исходный поток",
|
||||
"Flow": "Поток",
|
||||
"Mode": "Режим",
|
||||
"Wait for Response": "Ожидание ответа",
|
||||
"Response": "Замечание",
|
||||
"The flow to execute": "Выполняемый поток",
|
||||
"Choose Simple for key-value or Advanced for JSON.": "Выберите простую для ключевого значения или Расширенные для JSON.",
|
||||
"Simple": "Простой",
|
||||
"Advanced": "Расширенные",
|
||||
"Callable Flow": "Вызываемый поток",
|
||||
"Waiting to be triggered from another flow": "Ожидание срабатывания из другого потока",
|
||||
"Sample Data": "Образцы данных",
|
||||
"The schema to be passed to the flow": "Схема передается потоку"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"Trigger and call another sub flow.": "Trigger and call another sub flow.",
|
||||
"Call Flow": "Call Flow",
|
||||
"Return Response": "Return Response",
|
||||
"Call a flow that has \"Callable Flow\" trigger": "Call a flow that has \"Callable Flow\" trigger",
|
||||
"Return response to the original flow": "Return response to the original flow",
|
||||
"Flow": "Flow",
|
||||
"Mode": "Mode",
|
||||
"Wait for Response": "Wait for Response",
|
||||
"Response": "Response",
|
||||
"The flow to execute": "The flow to execute",
|
||||
"Choose Simple for key-value or Advanced for JSON.": "Choose Simple for key-value or Advanced for JSON.",
|
||||
"Simple": "Simple",
|
||||
"Advanced": "Advanced",
|
||||
"Callable Flow": "Callable Flow",
|
||||
"Waiting to be triggered from another flow": "Waiting to be triggered from another flow",
|
||||
"Sample Data": "Sample Data",
|
||||
"The schema to be passed to the flow": "The schema to be passed to the flow"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"Sub Flows": "Sub Flows",
|
||||
"Trigger and call another sub flow.": "Trigger and call another sub flow.",
|
||||
"Call Flow": "Call Flow",
|
||||
"Return Response": "Return Response",
|
||||
"Call a flow that has \"Callable Flow\" trigger": "Call a flow that has \"Callable Flow\" trigger",
|
||||
"Return response to the original flow": "Return response to the original flow",
|
||||
"Flow": "Flow",
|
||||
"Mode": "Mode",
|
||||
"Wait for Response": "Wait for Response",
|
||||
"Response": "Response",
|
||||
"The flow to execute": "The flow to execute",
|
||||
"Choose Simple for key-value or Advanced for JSON.": "Choose Simple for key-value or Advanced for JSON.",
|
||||
"Simple": "Simple",
|
||||
"Advanced": "Advanced",
|
||||
"Callable Flow": "Callable Flow",
|
||||
"Waiting to be triggered from another flow": "Waiting to be triggered from another flow",
|
||||
"Sample Data": "Sample Data",
|
||||
"The schema to be passed to the flow": "The schema to be passed to the flow"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"Trigger and call another sub flow.": "Trigger and call another sub flow.",
|
||||
"Call Flow": "Call Flow",
|
||||
"Return Response": "退货回复",
|
||||
"Call a flow that has \"Callable Flow\" trigger": "Call a flow that has \"Callable Flow\" trigger",
|
||||
"Return response to the original flow": "Return response to the original flow",
|
||||
"Flow": "流",
|
||||
"Mode": "Mode",
|
||||
"Wait for Response": "Wait for Response",
|
||||
"Response": "答复",
|
||||
"The flow to execute": "The flow to execute",
|
||||
"Choose Simple for key-value or Advanced for JSON.": "Choose Simple for key-value or Advanced for JSON.",
|
||||
"Simple": "Simple",
|
||||
"Advanced": "Advanced",
|
||||
"Callable Flow": "Callable Flow",
|
||||
"Waiting to be triggered from another flow": "Waiting to be triggered from another flow",
|
||||
"Sample Data": "Sample Data",
|
||||
"The schema to be passed to the flow": "The schema to be passed to the flow"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { createPiece, PieceAuth } from '@activepieces/pieces-framework';
|
||||
import { callFlow } from './lib/actions/call-flow';
|
||||
import { callableFlow } from './lib/triggers/callable-flow';
|
||||
import { response } from './lib/actions/respond';
|
||||
import { PieceCategory } from '@activepieces/shared';
|
||||
|
||||
export const flows = createPiece({
|
||||
displayName: 'Sub Flows',
|
||||
description: 'Trigger and call another sub flow.',
|
||||
auth: PieceAuth.None(),
|
||||
minimumSupportedRelease: '0.67.1',
|
||||
categories: [PieceCategory.CORE, PieceCategory.FLOW_CONTROL],
|
||||
logoUrl: 'https://cdn.activepieces.com/pieces/flows.svg',
|
||||
authors: ['hazemadelkhalel'],
|
||||
actions: [callFlow, response],
|
||||
triggers: [callableFlow],
|
||||
});
|
||||
@@ -0,0 +1,153 @@
|
||||
import {
|
||||
createAction,
|
||||
DynamicPropsValue,
|
||||
PieceAuth,
|
||||
Property,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
import { ExecutionType, FAIL_PARENT_ON_FAILURE_HEADER, isNil, PauseType, PARENT_RUN_ID_HEADER } from '@activepieces/shared';
|
||||
import { CallableFlowRequest, CallableFlowResponse, findFlowByExternalIdOrThrow, listEnabledFlowsWithSubflowTrigger } from '../common';
|
||||
|
||||
type FlowValue = {
|
||||
externalId: string;
|
||||
exampleData: unknown;
|
||||
};
|
||||
|
||||
export const callFlow = createAction({
|
||||
name: 'callFlow',
|
||||
displayName: 'Call Flow',
|
||||
description: 'Call a flow that has "Callable Flow" trigger',
|
||||
props: {
|
||||
flow: Property.Dropdown<FlowValue>({
|
||||
auth: PieceAuth.None(),
|
||||
displayName: 'Flow',
|
||||
description: 'The flow to execute',
|
||||
required: true,
|
||||
options: async (_, context) => {
|
||||
const flows = await listEnabledFlowsWithSubflowTrigger({
|
||||
flowsContext: context.flows,
|
||||
});
|
||||
return {
|
||||
options: flows.map((flow) => ({
|
||||
value: {
|
||||
externalId: flow.externalId ?? flow.id,
|
||||
exampleData: flow.version.trigger.settings.input.exampleData,
|
||||
},
|
||||
label: flow.version.displayName,
|
||||
})),
|
||||
};
|
||||
},
|
||||
refreshers: [],
|
||||
}),
|
||||
mode: Property.StaticDropdown({
|
||||
displayName: 'Mode',
|
||||
required: true,
|
||||
description: 'Choose Simple for key-value or Advanced for JSON.',
|
||||
defaultValue: 'simple',
|
||||
options: {
|
||||
disabled: false,
|
||||
options: [
|
||||
{
|
||||
label: 'Simple',
|
||||
value: 'simple',
|
||||
},
|
||||
{
|
||||
label: 'Advanced',
|
||||
value: 'advanced',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
flowProps: Property.DynamicProperties({
|
||||
auth: PieceAuth.None(),
|
||||
description: '',
|
||||
displayName: '',
|
||||
required: true,
|
||||
refreshers: ['flow', 'mode'],
|
||||
props: async (propsValue) => {
|
||||
const castedFlowValue = propsValue['flow'] as unknown as FlowValue;
|
||||
const mode = propsValue['mode'] as unknown as string;
|
||||
const fields: DynamicPropsValue = {};
|
||||
|
||||
|
||||
if (!isNil(castedFlowValue)) {
|
||||
if (mode === 'simple') {
|
||||
fields['payload'] = Property.Object({
|
||||
displayName: 'Payload',
|
||||
required: true,
|
||||
defaultValue: (castedFlowValue.exampleData as unknown as { sampleData: object }).sampleData,
|
||||
});
|
||||
}
|
||||
else{
|
||||
fields['payload'] = Property.Json({
|
||||
displayName: 'Payload',
|
||||
description:
|
||||
'Provide the data to be passed to the flow',
|
||||
required: true,
|
||||
defaultValue: (castedFlowValue.exampleData as unknown as { sampleData: object }).sampleData,
|
||||
});
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
},
|
||||
}),
|
||||
waitForResponse: Property.Checkbox({
|
||||
displayName: 'Wait for Response',
|
||||
required: false,
|
||||
defaultValue: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
if (context.executionType === ExecutionType.RESUME) {
|
||||
const response = context.resumePayload.body as CallableFlowResponse;
|
||||
const shouldFailParentRun = response.status === 'error' && context.propsValue.waitForResponse
|
||||
if (shouldFailParentRun) {
|
||||
throw new Error(JSON.stringify(response.data, null, 2))
|
||||
}
|
||||
return {
|
||||
status: response.status,
|
||||
data: response.data
|
||||
}
|
||||
}
|
||||
const payload = context.propsValue.flowProps['payload'];
|
||||
const flow = await findFlowByExternalIdOrThrow({
|
||||
flowsContext: context.flows,
|
||||
externalId: context.propsValue.flow?.externalId,
|
||||
});
|
||||
|
||||
const response = await httpClient.sendRequest<CallableFlowRequest>({
|
||||
method: HttpMethod.POST,
|
||||
url: `${context.server.apiUrl}v1/webhooks/${flow?.id}`,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
[PARENT_RUN_ID_HEADER]: context.run.id,
|
||||
[FAIL_PARENT_ON_FAILURE_HEADER]: context.propsValue.waitForResponse ? 'true' : 'false',
|
||||
},
|
||||
body: {
|
||||
data: payload,
|
||||
callbackUrl: context.propsValue.waitForResponse ? context.generateResumeUrl({
|
||||
queryParams: {}
|
||||
}) : undefined,
|
||||
},
|
||||
});
|
||||
if (context.propsValue.waitForResponse) {
|
||||
context.run.pause({
|
||||
pauseMetadata: {
|
||||
type: PauseType.WEBHOOK,
|
||||
response: {},
|
||||
}
|
||||
})
|
||||
}
|
||||
return response.body;
|
||||
},
|
||||
errorHandlingOptions: {
|
||||
continueOnFailure: {
|
||||
defaultValue:false,
|
||||
hide:false,
|
||||
},
|
||||
retryOnFailure: {
|
||||
defaultValue:false,
|
||||
hide:false,
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,74 @@
|
||||
import { DynamicPropsValue, PieceAuth, Property, StoreScope, createAction } from '@activepieces/pieces-framework';
|
||||
import { callableFlowKey, CallableFlowResponse, MOCK_CALLBACK_IN_TEST_FLOW_URL } from '../common';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
import { isNil } from '@activepieces/shared';
|
||||
|
||||
export const response = createAction({
|
||||
name: 'returnResponse',
|
||||
displayName: 'Return Response',
|
||||
description: 'Return response to the original flow',
|
||||
props: {
|
||||
mode: Property.StaticDropdown({
|
||||
displayName: 'Mode',
|
||||
description: 'Choose Simple for key-value or Advanced for JSON.',
|
||||
required: true,
|
||||
defaultValue: 'simple',
|
||||
options: {
|
||||
disabled: false,
|
||||
options: [
|
||||
{
|
||||
label: 'Simple',
|
||||
value: 'simple',
|
||||
},
|
||||
{
|
||||
|
||||
label: 'Advanced',
|
||||
value: 'advanced',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
response: Property.DynamicProperties({
|
||||
auth: PieceAuth.None(),
|
||||
displayName: 'Response',
|
||||
required: true,
|
||||
refreshers: ['mode'],
|
||||
props: async (propsValue) => {
|
||||
const mode = propsValue['mode'] as unknown as string;
|
||||
const fields: DynamicPropsValue = {};
|
||||
if (mode === 'simple') {
|
||||
fields['response'] = Property.Object({
|
||||
displayName: 'Response',
|
||||
required: true,
|
||||
});
|
||||
} else {
|
||||
fields['response'] = Property.Json({
|
||||
displayName: 'Response',
|
||||
required: true,
|
||||
});
|
||||
}
|
||||
return fields;
|
||||
},
|
||||
}),
|
||||
},
|
||||
async test(context) {
|
||||
return context.propsValue.response['response'];
|
||||
},
|
||||
async run(context) {
|
||||
const response = context.propsValue.response['response'];
|
||||
const callbackUrl = await context.store.get<string>(callableFlowKey(context.run.id), StoreScope.FLOW);
|
||||
const isNotTestFlow = callbackUrl !== MOCK_CALLBACK_IN_TEST_FLOW_URL;
|
||||
if (isNotTestFlow && !isNil(callbackUrl)) {
|
||||
await httpClient.sendRequest<CallableFlowResponse>({
|
||||
method: HttpMethod.POST,
|
||||
url: callbackUrl,
|
||||
body: {
|
||||
status: 'success',
|
||||
data: response
|
||||
},
|
||||
retries: 10,
|
||||
});
|
||||
}
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
import { FlowStatus, FlowTriggerType, isNil, PopulatedFlow } from "@activepieces/shared";
|
||||
import { FlowsContext, ListFlowsContextParams } from "@activepieces/pieces-framework";
|
||||
|
||||
|
||||
export const callableFlowKey = (runId: string) => `callableFlow_${runId}`;
|
||||
|
||||
export type CallableFlowRequest = {
|
||||
data: unknown;
|
||||
callbackUrl: string;
|
||||
}
|
||||
export type CallableFlowResponse = {
|
||||
status: 'success' | 'error';
|
||||
data: unknown;
|
||||
}
|
||||
|
||||
export const MOCK_CALLBACK_IN_TEST_FLOW_URL = 'MOCK';
|
||||
|
||||
export async function listEnabledFlowsWithSubflowTrigger({
|
||||
flowsContext,
|
||||
params,
|
||||
}: ListParams) {
|
||||
const allFlows = (await flowsContext.list(params)).data;
|
||||
const flows = allFlows.filter(
|
||||
(flow) =>
|
||||
flow.status === FlowStatus.ENABLED &&
|
||||
flow.version.trigger.type === FlowTriggerType.PIECE &&
|
||||
flow.version.trigger.settings.pieceName ==
|
||||
'@activepieces/piece-subflows'
|
||||
);
|
||||
return flows;
|
||||
}
|
||||
|
||||
export async function findFlowByExternalIdOrThrow({
|
||||
flowsContext,
|
||||
externalId,
|
||||
}: {
|
||||
flowsContext: FlowsContext;
|
||||
externalId: string | undefined;
|
||||
}): Promise<PopulatedFlow> {
|
||||
if (isNil(externalId)) {
|
||||
throw new Error(JSON.stringify({
|
||||
message: 'Please select a flow',
|
||||
}));
|
||||
}
|
||||
const externalIds = [externalId];
|
||||
const allFlows = await listEnabledFlowsWithSubflowTrigger({
|
||||
flowsContext,
|
||||
params: {
|
||||
externalIds
|
||||
}
|
||||
});
|
||||
if (allFlows.length === 0) {
|
||||
throw new Error(JSON.stringify({
|
||||
message: 'Flow not found',
|
||||
externalId,
|
||||
}));
|
||||
}
|
||||
return allFlows[0];
|
||||
}
|
||||
|
||||
type ListParams = {
|
||||
flowsContext: FlowsContext,
|
||||
params?: ListFlowsContextParams
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import {
|
||||
createTrigger,
|
||||
DynamicPropsValue,
|
||||
PieceAuth,
|
||||
Property,
|
||||
StoreScope,
|
||||
TriggerStrategy,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { callableFlowKey, CallableFlowRequest, MOCK_CALLBACK_IN_TEST_FLOW_URL } from '../common';
|
||||
|
||||
export const callableFlow = createTrigger({
|
||||
name: 'callableFlow',
|
||||
displayName: 'Callable Flow',
|
||||
description: 'Waiting to be triggered from another flow',
|
||||
props: {
|
||||
mode: Property.StaticDropdown({
|
||||
displayName: 'Mode',
|
||||
required: true,
|
||||
description: 'Choose Simple for key-value or Advanced for JSON.',
|
||||
defaultValue: 'simple',
|
||||
options: {
|
||||
disabled: false,
|
||||
options: [
|
||||
{
|
||||
label: 'Simple',
|
||||
value: 'simple',
|
||||
},
|
||||
{
|
||||
label: 'Advanced',
|
||||
value: 'advanced',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
exampleData: Property.DynamicProperties({
|
||||
auth: PieceAuth.None(),
|
||||
displayName: 'Sample Data',
|
||||
description: 'The schema to be passed to the flow',
|
||||
required: true,
|
||||
refreshers: ['mode'],
|
||||
props: async (propsValue) => {
|
||||
const mode = propsValue['mode'] as unknown as string;
|
||||
const fields: DynamicPropsValue = {};
|
||||
if (mode === 'simple') {
|
||||
fields['sampleData'] = Property.Object({
|
||||
displayName: 'Sample Data',
|
||||
required: true,
|
||||
});
|
||||
} else {
|
||||
fields['sampleData'] = Property.Json({
|
||||
displayName: 'Sample Data',
|
||||
required: true,
|
||||
});
|
||||
}
|
||||
return fields;
|
||||
},
|
||||
}),
|
||||
},
|
||||
sampleData: null,
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
async onEnable() {
|
||||
// ignore
|
||||
},
|
||||
async onDisable() {
|
||||
// ignore
|
||||
},
|
||||
async test(context) {
|
||||
const request: CallableFlowRequest = {
|
||||
data: context.propsValue.exampleData['sampleData'],
|
||||
callbackUrl: MOCK_CALLBACK_IN_TEST_FLOW_URL
|
||||
}
|
||||
return [request];
|
||||
},
|
||||
async run(context) {
|
||||
return [context.payload.body];
|
||||
},
|
||||
async onStart(context) {
|
||||
const request = context.payload as CallableFlowRequest;
|
||||
if (request.callbackUrl) {
|
||||
await context.store.put(callableFlowKey(context.run.id), request.callbackUrl, StoreScope.FLOW);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"outDir": "../../../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user