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,49 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
import { wonderchatAuth } from '../..';
export const addPage = createAction({
name: 'addPage',
displayName: 'Add Page',
description: 'Add new pages to your chatbots knowledge base.',
auth: wonderchatAuth,
props: {
chatbotId: Property.ShortText({
displayName: 'Chatbot Id',
description: 'The ID of your chatbot (can be found in the URL when viewing your bot: /bot/YOUR_BOT_ID)',
required: true,
}),
urls: Property.Array({
displayName: 'URLs',
description: 'List of webpage URLs to add to your chatbot\'s knowledge base (e.g., "https://wonderchat.io")',
required: false,
}),
sessionCookie: Property.LongText({
displayName: 'Session cookie',
description: 'Session cookie for crawling sites behind login',
required: false,
}),
},
async run({ auth, propsValue }) {
const apiKey = auth.secret_text;
const { chatbotId, urls, sessionCookie } = propsValue;
const requestbody: any = {
apiKey,
chatbotId,
};
if (sessionCookie) {
requestbody.sessionCookie = sessionCookie;
}
if (urls) {
requestbody.urls = urls;
}
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: 'https://app.wonderchat.io/api/v1/add-pages',
headers: { 'Content-Type': 'application/json'},
body: requestbody,
});
return response.body;
},
});

View File

@@ -0,0 +1,40 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
import { wonderchatAuth } from '../..';
export const addTag = createAction({
name: 'addTag',
displayName: 'Add Tag',
description: 'Add custom tags to a specific chatlog.',
auth: wonderchatAuth,
props: {
chatlogId: Property.ShortText({
displayName: 'Chatlog Id',
description:
'The ID of your chat session (can be found under Chatlog Details section, labeled as "ID")',
required: true,
}),
tags: Property.Array({
displayName: 'Tags',
description: 'List of URLs to add to your chatbot',
required: true,
}),
},
async run({ auth, propsValue }) {
const apiKey = auth.secret_text;
const { chatlogId, tags } = propsValue;
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: 'https://app.wonderchat.io/api/v1/add-tags-to-chatlog',
headers: { 'Content-Type': 'application/json' },
body: {
apiKey,
chatlogId,
tags,
},
});
return response.body;
},
});

View File

@@ -0,0 +1,65 @@
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { createAction, Property } from '@activepieces/pieces-framework';
import { wonderchatAuth } from '../..';
export const askQuestion = createAction({
name: 'askQuestion',
displayName: 'Ask Question',
description:
'Sends a question to a Wonderchat bot; returns the bots answer.',
auth: wonderchatAuth,
props: {
chatbotId: Property.ShortText({
displayName: 'Chatbot Id',
description: 'The ID of your chatbot (can be found in the URL when viewing your bot: /bot/YOUR_BOT_ID)',
required: true,
}),
question: Property.LongText({
displayName: 'Question',
description: 'The question you wish to ask your chatbot',
required: true,
}),
chatlogId: Property.ShortText({
displayName: 'Chatlog Id',
description:
'The ID of your chat session (can be found under Chatlog Details section, labeled as "ID")',
required: false,
}),
context: Property.LongText({
displayName: 'Custom context',
description: 'Additional custom context about the chat session (e.g., user information)',
required: false,
}),
contextUrl: Property.LongText({
displayName: 'Context URL',
description: 'URL of the page the user is on to provide additional context',
required: false,
}),
},
async run({propsValue}) {
const { chatbotId, question, chatlogId, context, contextUrl } = propsValue;
const requestbody: any = {
chatbotId,
question,
};
if (chatlogId) {
requestbody.chatlogId = chatlogId;
}
if (context) {
requestbody.context = context;
}
if (contextUrl) {
requestbody.contextUrl = contextUrl;
}
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: 'https://app.wonderchat.io/api/v1/chat',
headers: { 'Content-Type': 'application/json' },
body: requestbody,
});
return response.body;
},
});

View File

@@ -0,0 +1,40 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
import { wonderchatAuth } from '../..';
export const removeTag = createAction({
name: 'removeTag',
displayName: 'Remove Tag',
description: 'Remove specific tags from a chatlog.',
auth: wonderchatAuth,
props: {
chatlogId: Property.ShortText({
displayName: 'Chatlog Id',
description:
'The ID of your chat session (can be found under Chatlog Details section, labeled as "ID")',
required: true,
}),
tags: Property.Array({
displayName: 'Tags',
description: 'List of tags to remove',
required: true,
}),
},
async run({ auth, propsValue }) {
const apiKey = auth.secret_text;
const { chatlogId, tags } = propsValue;
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: 'https://app.wonderchat.io/api/v1/delete-tags-from-chatlog',
headers: { 'Content-Type': 'application/json' },
body: {
apiKey,
chatlogId,
tags,
},
});
return response.body;
},
});

View File

@@ -0,0 +1,91 @@
import {
PiecePropValueSchema,
createTrigger,
TriggerStrategy,
Property,
AppConnectionValueForAuthProperty
} from '@activepieces/pieces-framework';
import {
Polling,
pollingHelper,
DedupeStrategy,
httpClient,
HttpMethod
} from '@activepieces/pieces-common';
import { wonderchatAuth } from '../..';
interface Message {
content: string;
type: 'user' | 'bot';
createdAt: string;
}
const polling: Polling<
AppConnectionValueForAuthProperty<typeof wonderchatAuth>,
{ chatlogId: string }
> = {
strategy: DedupeStrategy.TIMEBASED,
items: async ({ auth, propsValue, lastFetchEpochMS }) => {
const response = await httpClient.sendRequest<{ messages: Message[] }>({
method: HttpMethod.POST,
url: 'https://app.wonderchat.io/api/v1/messages',
headers: { 'Content-Type': 'application/json' },
body: {
apiKey: auth.secret_text,
chatlogId: propsValue.chatlogId
}
});
const messages = response.body.messages;
const newMessages = messages
.filter((message) => message.type === 'user')
.filter(
(message) => new Date(message.createdAt).getTime() > lastFetchEpochMS
);
return newMessages.map((message) => ({
epochMilliSeconds: new Date(message.createdAt).getTime(),
data: message
}));
}
};
export const newUserMessage = createTrigger({
auth: wonderchatAuth,
name: 'newUserMessage',
displayName: 'New User Message',
description:
'Triggers when a new message is sent by a user in a specific chatlog.',
props: {
chatlogId: Property.ShortText({
displayName: 'Chatlog ID',
description:
'The ID of your chat session (can be found under Chatlog Details section, labeled as "ID")',
required: true,
}),
},
sampleData: {
content: 'I would want to now more about the products pricing strategy',
type: 'user',
createdAt: '2023-12-01T06:35:15.456Z'
},
type: TriggerStrategy.POLLING,
async test(context) {
return await pollingHelper.poll(polling, context);
},
async onEnable(context) {
const { store, auth, propsValue } = context;
await pollingHelper.onEnable(polling, { store, auth, propsValue });
},
async onDisable(context) {
const { store, auth, propsValue } = context;
await pollingHelper.onEnable(polling, { store, auth, propsValue });
},
async run(context) {
return await pollingHelper.poll(polling, context);
}
});