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:
257
activepieces-fork/docs/embedding/predefined-connection.mdx
Normal file
257
activepieces-fork/docs/embedding/predefined-connection.mdx
Normal file
@@ -0,0 +1,257 @@
|
||||
---
|
||||
title: "Predefined Connection"
|
||||
icon: "Link"
|
||||
---
|
||||
|
||||
Use predefined connections to allow users to access your piece in the embedded app without re-entering authentication credentials.
|
||||
|
||||
The high-level steps are:
|
||||
- Create a global connection for a project using the API in the platform admin. Only platform admins can edit or delete global connections.
|
||||
- (Optional) Hide the connections dropdown in the piece settings.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- [Run the Enterprise Edition](/handbook/engineering/playbooks/run-ee)
|
||||
- [Create your piece](/build-pieces/building-pieces/overview). Later we will customize the piece logic to use predefined connections.
|
||||
|
||||
### Create a Predefined Connection
|
||||
|
||||
<Steps>
|
||||
<Step title="Create an API Key">
|
||||
Go to **Platform Admin → Security → API Keys** and create an API key. Save it for use in the next step.
|
||||

|
||||
</Step>
|
||||
<Step title="Create a Global Connection via API">
|
||||
Add the following snippet to your backend to create a global connection each time you generate the <b>JWT token</b>.
|
||||
|
||||
The snippet does the following:
|
||||
- Create Project If it doesn't exist.
|
||||
- Create a global connection for the project with certain naming convention.
|
||||
```js
|
||||
const apiKey = 'YOUR_API_KEY';
|
||||
const instanceUrl = 'https://cloud.activepieces.com';
|
||||
|
||||
// The name of the user / organization in your SAAS
|
||||
const externalProjectId = 'org_1234';
|
||||
const pieceName = '@activepieces/piece-gelato';
|
||||
// This will depend on what your piece auth type is, can be one of this ['PLATFORM_OAUTH2','SECRET_TEXT','BASIC_AUTH','CUSTOM_AUTH']
|
||||
const pieceAuthType = "CUSTOM_AUTH"
|
||||
const connectionProps = {
|
||||
// Fill in the props required by your piece's auth
|
||||
}
|
||||
const { id: projectId, externalId } = await getOrCreateProject({
|
||||
projectExternalId: externalProjectId,
|
||||
apiKey,
|
||||
instanceUrl,
|
||||
});
|
||||
|
||||
await createGlobalConnection({
|
||||
projectId,
|
||||
externalProjectId,
|
||||
apiKey,
|
||||
instanceUrl,
|
||||
pieceName,
|
||||
props,
|
||||
pieceAuthType
|
||||
});
|
||||
|
||||
```
|
||||
Implementation:
|
||||
|
||||
```js
|
||||
async function getOrCreateProject({
|
||||
projectExternalId,
|
||||
apiKey,
|
||||
instanceUrl,
|
||||
}: {
|
||||
projectExternalId: string,
|
||||
apiKey: string,
|
||||
instanceUrl: string
|
||||
}): Promise<{ id: string, externalId: string }> {
|
||||
|
||||
const projects = await fetch(`${instanceUrl}/api/v1/projects?externalId=${projectExternalId}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${apiKey}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => data.data)
|
||||
.catch(err => {
|
||||
console.error('Error fetching projects:', err);
|
||||
return [];
|
||||
});
|
||||
|
||||
if (projects.length > 0) {
|
||||
return {
|
||||
id: projects[0].id,
|
||||
externalId: projects[0].externalId
|
||||
};
|
||||
}
|
||||
|
||||
const newProject = await fetch(`${instanceUrl}/api/v1/projects`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${apiKey}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
displayName: projectExternalId,
|
||||
metadata: {},
|
||||
externalId: projectExternalId
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.catch(err => {
|
||||
console.error('Error creating project:', err);
|
||||
throw err;
|
||||
});
|
||||
|
||||
return {
|
||||
id: newProject.id,
|
||||
externalId: newProject.externalId
|
||||
};
|
||||
}
|
||||
|
||||
async function createGlobalConnection({
|
||||
projectId,
|
||||
externalProjectId,
|
||||
apiKey,
|
||||
instanceUrl,
|
||||
pieceName,
|
||||
props,
|
||||
pieceAuthType
|
||||
}: {
|
||||
projectId: string,
|
||||
externalProjectId: string,
|
||||
apiKey: string,
|
||||
instanceUrl: string,
|
||||
pieceName: string,
|
||||
props: Record<string, any>,
|
||||
pieceAuthType
|
||||
}) {
|
||||
|
||||
const displayName = 'Gelato Connection';
|
||||
const connectionExternalId = 'gelato_' + externalProjectId;
|
||||
|
||||
return fetch(`${instanceUrl}/api/v1/global-connections`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${apiKey}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
displayName,
|
||||
pieceName,
|
||||
metadata: {},
|
||||
type: pieceAuthType,
|
||||
value: {
|
||||
type: pieceAuthType,
|
||||
props
|
||||
},
|
||||
scope: 'PLATFORM',
|
||||
projectIds: [projectId],
|
||||
externalId: connectionExternalId
|
||||
})
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
### Hide the Connections Dropdown (Optional)
|
||||
|
||||
<Steps>
|
||||
<Step title="Modify Trigger / Action Definition">
|
||||
Wherever you call `createTrigger` or `createAction` set `requireAuth` to `false`, this will hide the connections dropdown in the piece settings in the builder,
|
||||
next we need to fetch it based on a naming convention.
|
||||
</Step>
|
||||
<Step title="Fetch the connection">
|
||||
Here is example how you can fetch the connection value based on naming convention, make sure this naming convention is followed when creating a global connection.
|
||||
|
||||
```js
|
||||
import {
|
||||
ConnectionsManager,
|
||||
Property,
|
||||
TriggerStrategy
|
||||
} from "@activepieces/pieces-framework";
|
||||
import {
|
||||
createTrigger
|
||||
} from "@activepieces/pieces-framework";
|
||||
import {
|
||||
isNil
|
||||
} from "@activepieces/shared";
|
||||
// Add this import from the index.ts file, where it contains the definition of the auth object.
|
||||
import { auth } from '../..';
|
||||
|
||||
const fetchConnection = async (
|
||||
connections: ConnectionsManager,
|
||||
projectExternalId: string | undefined,
|
||||
): Promise<PiecePropValueSchema<typeof auth>> => {
|
||||
if (isNil(projectExternalId)) {
|
||||
throw new Error('This project is missing an external id');
|
||||
}
|
||||
// the naming convention here is gelato_projectExternalId
|
||||
const connection = await connections.get(`gelato_${projectExternalId}`);
|
||||
if (isNil(connection)) {
|
||||
throw new Error(`Connection not found for project ${projectExternalId}`);
|
||||
}
|
||||
|
||||
return connection as PiecePropValueSchema<typeof auth>;
|
||||
};
|
||||
|
||||
|
||||
export const newFlavorCreated = createTrigger({
|
||||
requireAuth: false,
|
||||
name: 'newFlavorCreated',
|
||||
displayName: 'new flavor created',
|
||||
description: 'triggers when a new icecream flavor is created.',
|
||||
props: {
|
||||
dropdown: Property.Dropdown({
|
||||
displayName: 'Dropdown',
|
||||
required: true,
|
||||
refreshers: [],
|
||||
options: async (_, {
|
||||
connections,
|
||||
project
|
||||
}) => {
|
||||
const connection = await fetchConnection(connections, (await project.externalId()));
|
||||
// your logic
|
||||
return {
|
||||
options: [{
|
||||
label: 'test',
|
||||
value: 'test'
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
sampleData: {},
|
||||
type: TriggerStrategy.POLLING,
|
||||
async test({connections,project}) {
|
||||
const connection = await fetchConnection(connections, (await project.externalId()));
|
||||
// use the connection with your own logic
|
||||
return []
|
||||
},
|
||||
async onEnable({connections,project}) {
|
||||
const connection = await fetchConnection(connections, (await project.externalId()));
|
||||
// use the connection with your own logic
|
||||
},
|
||||
|
||||
async onDisable({connections,project}) {
|
||||
const connection = await fetchConnection(connections, (await project.externalId()));
|
||||
// use the connection with your own logic
|
||||
},
|
||||
|
||||
async run({connections,project}) {
|
||||
const connection = await fetchConnection(connections, (await project.externalId()));
|
||||
// use the connection with your own logic
|
||||
return []
|
||||
},
|
||||
});
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
Reference in New Issue
Block a user