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,54 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { krispcallAuth } from '../..';
export const addContact = createAction({
name: 'addContact',
displayName: 'Add Contact',
auth: krispcallAuth,
description: 'Add contact in Krispcall',
props: {
name: Property.ShortText({
displayName: 'Name',
description: 'Enter your name',
required: false,
}),
number: Property.ShortText({
displayName: 'Contact number',
description: 'Enter contact number',
required: true,
}),
address: Property.ShortText({
displayName: 'Address',
description: 'Enter your address',
required: false,
}),
company: Property.ShortText({
displayName: 'Company',
description: 'Enter your company',
required: false,
}),
email: Property.ShortText({
displayName: 'Email',
description: 'Enter your email',
required: false,
}),
},
async run({ auth, propsValue }) {
const res = await httpClient.sendRequest<string[]>({
method: HttpMethod.POST,
url: 'https://app.krispcall.com/api/v3/platform/activepiece/add-contact',
headers: {
'X-API-KEY': auth.props.apiKey,
},
body: {
name: propsValue.name,
number: propsValue.number,
company: propsValue.company,
email: propsValue.email,
address: propsValue.address,
},
});
return res.body;
},
});

View File

@@ -0,0 +1,30 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { krispcallAuth } from '../..';
export const deleteContacts = createAction({
name: 'deleteContacts',
displayName: 'Delete Contacts',
auth: krispcallAuth,
description: 'Delete contacts from krispcall.',
props: {
contacts: Property.Array({
displayName: 'Contacts',
description: 'Enter contact which you want to delete.',
required: false,
}),
},
async run({ auth, propsValue }) {
const res = await httpClient.sendRequest<string[]>({
method: HttpMethod.DELETE,
url: 'https://app.krispcall.com/api/v3/platform/activepiece/delete-contacts',
headers: {
'X-API-KEY': auth.props.apiKey,
},
body: {
contacts: propsValue.contacts,
},
});
return res.body;
},
});

View File

@@ -0,0 +1,93 @@
import { createAction } from '@activepieces/pieces-framework';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { krispcallAuth } from '../..';
import { Property, PiecePropValueSchema } from '@activepieces/pieces-framework';
interface Item {
name: string;
id: string;
number: string;
}
export const sendMms = createAction({
name: 'sendMms',
displayName: 'Send MMS',
auth: krispcallAuth,
description: 'Send mms in krispcall.',
props: {
from_number: Property.Dropdown({
auth: krispcallAuth,
displayName: 'from number',
description: 'Select an number',
required: true,
refreshers: ['auth'],
refreshOnSearch: false,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first',
};
}
try {
const authVaue = auth.props;
const res = await httpClient.sendRequest<Item[]>({
method: HttpMethod.GET,
url: 'https://app.krispcall.com/api/v3/platform/activepiece/get-numbers',
headers: {
'X-API-KEY': authVaue.apiKey,
},
});
const mappedOptions = res?.body?.map((item) => {
return {
label: item.name,
value: item.number,
};
});
return {
disabled: false,
options: mappedOptions,
};
} catch (error) {
// Handle error
console.error(error);
return { disabled: true, options: [] }; // Return empty options array or handle error accordingly
}
},
}),
to_number: Property.ShortText({
displayName: 'To Number',
description: 'Enter the number to which you want to send sms.',
required: true,
}),
content: Property.ShortText({
displayName: 'content',
description: 'Enter your message here.',
required: false,
}),
medias: Property.Array({
displayName: 'Medias url',
description: 'Enter medias urls',
required: true,
}),
},
async run({ auth, propsValue }) {
const res = await httpClient.sendRequest<string[]>({
method: HttpMethod.POST,
url: 'https://app.krispcall.com/api/v3/platform/activepiece/send-mms',
headers: {
'X-API-KEY': auth.props.apiKey,
},
body: {
from_number: propsValue.from_number,
to_number: propsValue.to_number,
content: propsValue.content,
medias: propsValue.medias,
},
});
return res.body;
},
});

View File

@@ -0,0 +1,87 @@
import { createAction } from '@activepieces/pieces-framework';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { krispcallAuth } from '../..';
import { Property, PiecePropValueSchema } from '@activepieces/pieces-framework';
interface Item {
name: string;
id: string;
number: string;
}
export const sendSms = createAction({
name: 'sendSms',
displayName: 'Send SMS',
auth: krispcallAuth,
description: 'Send sms in Krispcall.',
props: {
from_number: Property.Dropdown({
displayName: 'From Number',
description: 'Select an Number',
required: true,
refreshers: ['auth'],
refreshOnSearch: false,
auth: krispcallAuth,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first',
};
}
try {
const authVaue = auth.props;
const res = await httpClient.sendRequest<Item[]>({
method: HttpMethod.GET,
url: 'https://app.krispcall.com/api/v3/platform/activepiece/get-numbers',
headers: {
'X-API-KEY': authVaue.apiKey,
},
});
const mappedOptions = res?.body?.map((item) => {
return {
label: item.name,
value: item.number,
};
});
return {
disabled: false,
options: mappedOptions,
};
} catch (error) {
// Handle error
console.error(error);
return { disabled: true, options: [] }; // Return empty options array or handle error accordingly
}
},
}),
to_number: Property.ShortText({
displayName: 'To Number',
description: 'Enter the number to which you want to send sms.',
required: true,
}),
content: Property.ShortText({
displayName: 'content',
description: 'Enter your message here.',
required: true,
}),
},
async run({ auth, propsValue }) {
const res = await httpClient.sendRequest<string[]>({
method: HttpMethod.POST,
url: 'https://app.krispcall.com/api/v3/platform/activepiece/send-sms',
headers: {
'X-API-KEY': auth.props.apiKey,
},
body: {
from_number: propsValue.from_number,
to_number: propsValue.to_number,
content: propsValue.content,
},
});
return res.body;
},
});

View File

@@ -0,0 +1,114 @@
import { krispcallAuth } from '../../index';
import { HttpMethod, httpClient } from "@activepieces/pieces-common";
import { TriggerStrategy, createTrigger } from "@activepieces/pieces-framework"
export const triggers = [
{
name: 'newVoicemail',
displayName: 'New Voicemail',
description: 'Trigger when a new voicemail is received.',
action: 'new_voicemail',
sampleData: {
id: '',
from: '+9779821110987',
duration: '5 seconds',
call_time: '2000-10-31T01:30:00.000-05:00',
voicemail_audio: 'voicemail.mp4',
},
},
{
name: 'newMms',
displayName: 'New MMS/SMS',
description: 'Trigger when a new MMS/SMS is received.',
action: 'new_sms_or_mms',
sampleData: {
"id": "YiW2nyxqtJPYqkRKbrcJQ7",
"from_number": "+16466813538",
"to_number": "+12517327005",
"content": "Last testing",
"media_link": "https://api.twilio.com/2010-04-01/Accounts/LINK/Media/SOMETHING"
},
},
{
name: 'newContact',
displayName: 'New Contact',
description: 'Trigger when a new contact is added.',
action: 'new_contact',
sampleData: {
id: '1',
email: 'john@example.com',
company: 'KrispCall',
address: 'Singapore',
name: 'John Smith',
contactNumber: '+9779834509123',
},
},
{
name: 'newCallLog',
displayName: 'New Call Log',
description: 'Trigger when a new call log is recorded.',
action: 'new_call_log',
sampleData: {
id: '101',
callFrom: "+11234567890",
callTo: "+11234567891",
direction: "Outgoing",
duration : "0hr 01min 30sec",
outcome:"Completed",
callRecording: "http://example.com/recording.mp3",
},
},
{
name: 'OutboundSMS/MMS',
displayName: 'Outbound MMS/SMS',
description: 'Trigger when a new MMS/SMS is sent.',
action: 'outbound_sms_or_mms',
sampleData: {
"id": "YiW2nyxqtJPYqkRKbrcJQ7",
"from_number": "+16466813538",
"to_number": "+12517327005",
"content": "Last testing",
"media_link": "https://api.twilio.com/2010-04-01/Accounts/LINK/Media/SOMETHING"
},
},
].map(trigger => {
return createTrigger({
name: trigger.name,
displayName: trigger.displayName,
auth: krispcallAuth,
description: trigger.description,
props: {},
sampleData: trigger.sampleData,
type: TriggerStrategy.WEBHOOK,
async onEnable(context) {
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: 'https://app.krispcall.com/api/v3/platform/activepiece/subscribe',
body: {
hookUrl: context.webhookUrl,
action: trigger.action,
},
headers: {
'X-API-KEY': context.auth.props.apiKey,
},
});
await context.store.put('_webhook_id', response.body.id);
},
async onDisable(context) {
const webhookId = await context.store.get<string>('_webhook_id');
await httpClient.sendRequest({
method: HttpMethod.DELETE,
url: 'https://app.krispcall.com/api/v3/platform/activepiece/unsubscribe',
body: {
hookUrl: webhookId,
},
headers: {
'X-API-KEY': context.auth.props.apiKey,
},
});
},
async run(context) {
return [context.payload.body];
},
})
})