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,63 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { BumpupsAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const generateCreatorDescription = createAction({
auth: BumpupsAuth,
name: 'generateCreatorDescription',
displayName: 'Generate Creator Description',
description: 'Generates a compelling description for a YouTube video based on its content.',
props: {
videoUrl: Property.ShortText({
displayName: 'Video URL',
description: 'The YouTube video URL.',
required: true,
}),
model: Property.StaticDropdown({
displayName: 'Model',
required: true,
defaultValue: 'bump-1.0',
options: {
disabled: false,
options: [
{ label: 'bump-1.0', value: 'bump-1.0' },
],
},
}),
language: Property.StaticDropdown({
displayName: 'Language',
required: false,
defaultValue: 'en',
options: {
disabled: false,
options: [
{ label: 'English (en)', value: 'en' },
{ label: 'Hindi (hi)', value: 'hi' },
{ label: 'Spanish (es)', value: 'es' },
{ label: 'Portuguese (pt)', value: 'pt' },
{ label: 'Russian (ru)', value: 'ru' },
{ label: 'German (de)', value: 'de' },
{ label: 'French (fr)', value: 'fr' },
{ label: 'Japanese (ja)', value: 'ja' },
{ label: 'Korean (ko)', value: 'ko' },
{ label: 'Arabic (ar)', value: 'ar' },
],
},
}),
},
async run({auth, propsValue}) {
const body = {
url: propsValue.videoUrl,
model: propsValue.model,
languaege: propsValue.language || 'en',
};
const response = await makeRequest(
auth.secret_text,
HttpMethod.POST,
'/creator/description',
body
);
return response;
},
});

View File

@@ -0,0 +1,77 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { BumpupsAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const generateCreatorHashtags = createAction({
auth: BumpupsAuth,
name: 'generateCreatorHashtags',
displayName: 'Generate Creator Hashtags',
description:
'Generates relevant hashtags for a YouTube video based on its content.',
props: {
videoUrl: Property.ShortText({
displayName: 'Video URL',
description: 'The YouTube video URL.',
required: true,
}),
model: Property.StaticDropdown({
displayName: 'Model',
required: true,
defaultValue: 'bump-1.0',
options: {
disabled: false,
options: [{ label: 'bump-1.0', value: 'bump-1.0' }],
},
}),
language: Property.StaticDropdown({
displayName: 'Language',
required: false,
defaultValue: 'en',
options: {
disabled: false,
options: [
{ label: 'English (en)', value: 'en' },
{ label: 'Hindi (hi)', value: 'hi' },
{ label: 'Spanish (es)', value: 'es' },
{ label: 'Portuguese (pt)', value: 'pt' },
{ label: 'Russian (ru)', value: 'ru' },
{ label: 'German (de)', value: 'de' },
{ label: 'French (fr)', value: 'fr' },
{ label: 'Japanese (ja)', value: 'ja' },
{ label: 'Korean (ko)', value: 'ko' },
{ label: 'Arabic (ar)', value: 'ar' },
],
},
}),
output_format: Property.StaticDropdown({
displayName: 'Output Format',
required: false,
defaultValue: 'text',
options: {
disabled: false,
options: [
{ label: 'Hashtags', value: 'hashtags' },
{ label: 'Keywords', value: 'keywords' },
],
},
}),
},
async run({ auth, propsValue }) {
const body = {
url: propsValue.videoUrl,
model: propsValue.model,
language: propsValue.language || 'en',
output_format: propsValue.output_format || 'hashtags',
};
const response = await makeRequest(
auth.secret_text,
HttpMethod.POST,
'/creator/hashtags',
body
);
return response;
},
});

View File

@@ -0,0 +1,70 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { BumpupsAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const generateCreatorTakeaways = createAction({
auth: BumpupsAuth,
name: 'generateCreatorTakeaways',
displayName: 'Generate Creator Takeaways',
description:
'Generates key takeaways for a YouTube video based on its content.',
props: {
videoUrl: Property.ShortText({
displayName: 'Video URL',
description: 'The YouTube video URL.',
required: true,
}),
model: Property.StaticDropdown({
displayName: 'Model',
required: true,
defaultValue: 'bump-1.0',
options: {
disabled: false,
options: [{ label: 'bump-1.0', value: 'bump-1.0' }],
},
}),
language: Property.StaticDropdown({
displayName: 'Language',
required: false,
defaultValue: 'en',
options: {
disabled: false,
options: [
{ label: 'English (en)', value: 'en' },
{ label: 'Hindi (hi)', value: 'hi' },
{ label: 'Spanish (es)', value: 'es' },
{ label: 'Portuguese (pt)', value: 'pt' },
{ label: 'Russian (ru)', value: 'ru' },
{ label: 'German (de)', value: 'de' },
{ label: 'French (fr)', value: 'fr' },
{ label: 'Japanese (ja)', value: 'ja' },
{ label: 'Korean (ko)', value: 'ko' },
{ label: 'Arabic (ar)', value: 'ar' },
],
},
}),
emojis_enabled: Property.Checkbox({
displayName: 'Include Emojis',
description: 'Whether to include emojis in the generated takeaways.',
required: false,
defaultValue: false,
}),
},
async run({ auth, propsValue }) {
const body: any = {
url: propsValue.videoUrl,
model: propsValue.model,
language: propsValue.language || 'en',
emojis_enabled: propsValue.emojis_enabled || false,
};
const response = await makeRequest(
auth.secret_text,
HttpMethod.POST,
'/creator/takeaways',
body
);
return response;
},
});

View File

@@ -0,0 +1,65 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { BumpupsAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const generateCreatorTitles = createAction({
auth: BumpupsAuth,
name: 'generateCreatorTitles',
displayName: 'Generate Creator Titles',
description: 'Generates engaging titles for a YouTube video based on its content.',
props: {
videoUrl: Property.ShortText({
displayName: 'Video URL',
description: 'The YouTube video URL.',
required: true,
}),
model: Property.StaticDropdown({
displayName: 'Model',
required: true,
defaultValue: 'bump-1.0',
options: {
disabled: false,
options: [
{ label: 'bump-1.0', value: 'bump-1.0' },
],
},
}),
language: Property.StaticDropdown({
displayName: 'Language',
required: false,
defaultValue: 'en',
options: {
disabled: false,
options: [
{ label: 'English (en)', value: 'en' },
{ label: 'Hindi (hi)', value: 'hi' },
{ label: 'Spanish (es)', value: 'es' },
{ label: 'Portuguese (pt)', value: 'pt' },
{ label: 'Russian (ru)', value: 'ru' },
{ label: 'German (de)', value: 'de' },
{ label: 'French (fr)', value: 'fr' },
{ label: 'Japanese (ja)', value: 'ja' },
{ label: 'Korean (ko)', value: 'ko' },
{ label: 'Arabic (ar)', value: 'ar' },
],
},
}),
},
async run({ auth, propsValue }) {
const body = {
url: propsValue.videoUrl,
model: propsValue.model,
language: propsValue.language || 'en',
};
const response = await makeRequest(
auth.secret_text,
HttpMethod.POST,
'/creator/titles',
body
);
return response;
},
});

View File

@@ -0,0 +1,79 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { BumpupsAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const generateTimestamps = createAction({
auth: BumpupsAuth,
name: 'generateTimestamps',
displayName: 'Generate Timestamps',
description: 'Generates detailed timestamps for a YouTube video based on its content.',
props: {
videoUrl: Property.ShortText({
displayName: 'Video URL',
description: 'The YouTube video URL.',
required: true,
}),
model: Property.StaticDropdown({
displayName: 'Model',
required: true,
defaultValue: 'bump-1.0',
options: {
disabled: false,
options: [
{ label: 'bump-1.0', value: 'bump-1.0' },
],
},
}),
language: Property.StaticDropdown({
displayName: 'Language',
required: false,
defaultValue: 'en',
options: {
disabled: false,
options: [
{ label: 'English (en)', value: 'en' },
{ label: 'Hindi (hi)', value: 'hi' },
{ label: 'Spanish (es)', value: 'es' },
{ label: 'Portuguese (pt)', value: 'pt' },
{ label: 'Russian (ru)', value: 'ru' },
{ label: 'German (de)', value: 'de' },
{ label: 'French (fr)', value: 'fr' },
{ label: 'Japanese (ja)', value: 'ja' },
{ label: 'Korean (ko)', value: 'ko' },
{ label: 'Arabic (ar)', value: 'ar' },
],
},
}),
timestamps_style: Property.StaticDropdown({
displayName: 'Timestamps Style',
description: 'Preferred length of each timestamp.',
required: false,
defaultValue: 'long',
options: {
disabled: false,
options: [
{ label: 'Long', value: 'long' },
{ label: 'Short', value: 'short' },
],
},
}),
},
async run({ auth, propsValue }) {
const body = {
url: propsValue.videoUrl,
model: propsValue.model,
language: propsValue.language || 'en',
timestamps_style: propsValue.timestamps_style || 'long',
};
const response = await makeRequest(
auth.secret_text,
HttpMethod.POST,
'/general/timestamps',
body
);
return response;
},
});

View File

@@ -0,0 +1,86 @@
import { createAction, Property } from "@activepieces/pieces-framework";
import { BumpupsAuth } from "../common/auth";
import { makeRequest } from "../common/client";
import { HttpMethod } from "@activepieces/pieces-common";
export const sendChat = createAction({
name: 'send_chat',
displayName: 'Send Chat',
description:
'Creates an interactive chat response for a given YouTube video using the bump-1.0 model. Provide the video URL and an optional prompt.',
auth: BumpupsAuth,
props: {
videoUrl: Property.ShortText({
displayName: 'Video URL',
description: 'The YouTube video URL.',
required: true,
}),
model: Property.StaticDropdown({
displayName: 'Model',
required: true,
defaultValue: 'bump-1.0',
options: {
disabled: false,
options: [
{ label: 'bump-1.0', value: 'bump-1.0' },
],
},
}),
prompt: Property.LongText({
displayName: 'Prompt',
description:
'Message or query about the video (max 500 chars). If empty, defaults to "summary".',
required: false,
}),
language: Property.StaticDropdown({
displayName: 'Language',
required: false,
defaultValue: 'en',
options: {
disabled: false,
options: [
{ label: 'English (en)', value: 'en' },
{ label: 'Hindi (hi)', value: 'hi' },
{ label: 'Spanish (es)', value: 'es' },
{ label: 'Portuguese (pt)', value: 'pt' },
{ label: 'Russian (ru)', value: 'ru' },
{ label: 'German (de)', value: 'de' },
{ label: 'French (fr)', value: 'fr' },
{ label: 'Japanese (ja)', value: 'ja' },
{ label: 'Korean (ko)', value: 'ko' },
{ label: 'Arabic (ar)', value: 'ar' },
],
},
}),
output_format: Property.StaticDropdown({
displayName: 'Output Format',
required: false,
defaultValue: 'text',
options: {
disabled: false,
options: [
{ label: 'Text', value: 'text' },
{ label: 'Markdown', value: 'markdown' },
],
},
}),
},
async run({ auth, propsValue }) {
const body = {
url: propsValue.videoUrl,
model: propsValue.model,
prompt: propsValue.prompt || 'summary',
language: propsValue.language || 'en',
output_format: propsValue.output_format || 'text',
};
const response = await makeRequest(
auth.secret_text,
HttpMethod.POST,
'/chat',
body
);
return response;
},
});

View File

@@ -0,0 +1,17 @@
import { PieceAuth } from "@activepieces/pieces-framework";
import { makeRequest } from "./client";
import { HttpMethod } from "@activepieces/pieces-common";
export const BumpupsAuth = PieceAuth.SecretText({
displayName: 'Bumpups API Key',
description: `**Enter your Bumpups API Key.**
---
### How to obtain your API key
1. Sign up or log in at [bumpups.com](https://bumpups.com).
2. Go to **Settings** → **API**.
3. Enable API access and generate a key.
4. Copy and paste it here.
`,
required: true,
});

View File

@@ -0,0 +1,25 @@
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
export const BASE_URL = `https://api.bumpups.com`;
export async function makeRequest(
apiKey: string,
method: HttpMethod,
path: string,
body?: unknown
) {
try {
const response = await httpClient.sendRequest({
method,
url: `${BASE_URL}${path}`,
headers: {
'X-Api-Key': apiKey,
'Content-Type': 'application/json',
},
body,
});
return response.body;
} catch (error: any) {
throw new Error(`Unexpected error: ${error.message || String(error)}`);
}
}