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:
poduck
2025-12-18 22:59:37 -05:00
parent 9848268d34
commit 3aa7199503
16292 changed files with 1284892 additions and 4708 deletions

View File

@@ -0,0 +1,76 @@
---
title: 'Overview'
description: ''
---
This tutorial explains three techniques for creating triggers:
- `Polling`: Periodically call endpoints to check for changes.
- `Webhooks`: Listen to user events through a single URL.
- `App Webhooks (Subscriptions)`: Use a developer app (using OAuth2) to receive all authorized user events at a single URL (Not Supported).
to create new trigger run following command,
```bash
npm run cli triggers create
```
1. `Piece Folder Name`: This is the name associated with the folder where the trigger resides. It helps organize and categorize triggers within the piece.
2. `Trigger Display Name`: The name users see in the interface, conveying the trigger's purpose clearly.
3. `Trigger Description`: A brief, informative text in the UI, guiding users about the trigger's function and purpose.
4. `Trigger Technique`: Specifies the trigger type - either polling or webhook.
# Trigger Structure
```typescript
export const createNewIssue = createTrigger({
auth: PieceAuth | undefined
name: string, // Unique name across the piece.
displayName: string, // Display name on the interface.
description: string, // Description for the action
sampleData: null,
type: TriggerStrategy.WEBHOOK | TriggerStrategy.POLLING | TriggerStrategy.APP_WEBHOOK,
props: {}; // Required properties from the user.
// Run when the user enable or publish the flow.
onEnable: (ctx) => {},
// Run when the user disable the flow or
// the old flow is deleted after new one is published.
onDisable: (ctx) => {},
// Trigger implementation, It takes context as parameter.
// should returns an array of payload, each payload considered
run: async run(ctx): unknown[] => {}
})
```
<Tip>
It's important to note that the `run` method returns an array. The reason for
this is that a single polling can contain multiple triggers, so each item in
the array will trigger the flow to run.
</Tip>
## Context Object
The Context object contains multiple helpful pieces of information and tools that can be useful while developing.
```typescript
// Store: A simple, lightweight key-value store that is helpful when you are developing triggers that persist between runs, used to store information like the last polling date.
await context.store.put('_lastFetchedDate', new Date());
const lastFetchedData = await context.store.get('_lastFetchedDate', new Date());
// Webhook URL: A unique, auto-generated URL that will trigger the flow. Useful when you need to develop a trigger based on webhooks.
context.webhookUrl;
// Payload: Contains information about the HTTP request sent by the third party. It has three properties: status, headers, and body.
context.payload;
// PropsValue: Contains the information filled by the user in defined properties.
context.propsValue;
```
**App Webhooks (Not Supported)**
Certain services, such as `Slack` and `Square`, only support webhooks at the developer app level.
This means that all authorized users for the app will be sent to the same endpoint. While this technique will be supported soon, for now, a workaround is to perform polling on the endpoint.

View File

@@ -0,0 +1,111 @@
---
title: "Polling Trigger"
description: "Periodically call endpoints to check for changes"
---
The way polling triggers usually work is as follows:
**On Enable:**
Store the last timestamp or most recent item id using the context store property.
**Run:**
This method runs every **5 minutes**, fetches the endpoint between a certain timestamp or traverses until it finds the last item id, and returns the new items as an array.
**Testing:**
You can implement a test function which should return some of the most recent items. It's recommended to limit this to five.
**Examples:**
- [New Record Airtable](https://github.com/activepieces/activepieces/blob/main/packages/pieces/community/airtable/src/lib/trigger/new-record.trigger.ts)
- [New Updated Item Salesforce](https://github.com/activepieces/activepieces/blob/main/packages/pieces/community/salesforce/src/lib/trigger/new-updated-record.ts)
# Polling library
There multiple strategy to implement polling triggers, and we have created a library to help you with that.
## Strategies
**Timebased:**
This strategy fetches new items using a timestamp. You need to implement the items method, which should return the most recent items.
The library will detect new items based on the timestamp.
The polling object's generic type consists of the props value and the object type.
```typescript
const polling: Polling<Polling<AppConnectionValueForAuthProperty<typeof auth>> = {
strategy: DedupeStrategy.TIMEBASED,
items: async ({ propsValue, lastFetchEpochMS }) => {
// Todo implement the logic to fetch the items
const items = [ {id: 1, created_date: '2021-01-01T00:00:00Z'}, {id: 2, created_date: '2021-01-01T00:00:00Z'}];
return items.map((item) => ({
epochMilliSeconds: dayjs(item.created_date).valueOf(),
data: item,
}));
}
}
```
**Last ID Strategy:**
This strategy fetches new items based on the last item ID. To use this strategy, you need to implement the items method, which should return the most recent items.
The library will detect new items after the last item ID.
The polling object's generic type consists of the props value and the object type
```typescript
const polling: Polling<AppConnectionValueForAuthProperty<typeof auth>, Record<string,any>> = {
strategy: DedupeStrategy.LAST_ITEM,
items: async ({ propsValue }) => {
// Implement the logic to fetch the items
const items = [{ id: 1 }, { id: 2 }];
return items.map((item) => ({
id: item.id,
data: item,
}));
}
}
```
## Trigger Implementation
After implementing the polling object, you can use the polling helper to implement the trigger.
```typescript
export const newTicketInView = createTrigger({
name: 'new_ticket_in_view',
displayName: 'New ticket in view',
description: 'Triggers when a new ticket is created in a view',
type: TriggerStrategy.POLLING,
props: {
authentication: Property.SecretText({
displayName: 'Authentication',
description: markdownProperty,
required: true,
}),
},
sampleData: {},
onEnable: async (context) => {
await pollingHelper.onEnable(polling, {
store: context.store,
propsValue: context.propsValue,
auth: context.auth
})
},
onDisable: async (context) => {
await pollingHelper.onDisable(polling, {
store: context.store,
propsValue: context.propsValue,
auth: context.auth
})
},
run: async (context) => {
return await pollingHelper.poll(polling, context);
},
test: async (context) => {
return await pollingHelper.test(polling, context);
}
});
```

View File

@@ -0,0 +1,38 @@
---
title: 'Webhook Trigger'
description: 'Listen to user events through a single URL'
---
The way webhook triggers usually work is as follows:
**On Enable:**
Use `context.webhookUrl` to perform an HTTP request to register the webhook in a third-party app, and store the webhook Id in the `store`.
**On Handshake:**
Some services require a successful handshake request usually consisting of some challenge. It works similar to a normal run except that you return the correct challenge response. This is optional and in order to enable the handshake you need to configure one of the available handshake strategies in the `handshakeConfiguration` option.
**Run:**
You can find the HTTP body inside `context.payload.body`. If needed, alter the body; otherwise, return an array with a single item `context.payload.body`.
**Disable:**
Using the `context.store`, fetch the webhook ID from the enable step and delete the webhook on the third-party app.
**Testing:**
You cannot test it with Test Flow, as it uses static sample data provided in the piece.
To test the trigger, publish the flow, perform the event. Then check the flow runs from the main dashboard.
**Examples:**
- [New Form Submission on Typeform](https://github.com/activepieces/activepieces/blob/main/packages/pieces/community/typeform/src/lib/trigger/new-submission.ts)
<Warning>
To make your webhook accessible from the internet, you need to configure the backend URL. Follow these steps:
1. Install ngrok.
2. Run the command `ngrok http 4200`.
3. Replace the `AP_FRONTEND_URL` environment variable in `packages/server/api/.env` with the ngrok URL.
4. Go to /packages/react-ui/vite.config.ts, uncomment allowedHosts and set the value to what ngrok gives you.
Once you have completed these configurations, you are good to go!
</Warning>