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:
@@ -0,0 +1,54 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { common } from '../common';
|
||||
import { googlePubsubAuth } from '../..';
|
||||
|
||||
export const publishToTopic = createAction({
|
||||
name: 'publish_to_topic',
|
||||
auth: googlePubsubAuth,
|
||||
displayName: 'Publish to topic',
|
||||
description: 'Publish message to topic',
|
||||
props: {
|
||||
message: Property.Object({
|
||||
displayName: 'Message',
|
||||
required: true,
|
||||
}),
|
||||
topic: Property.Dropdown({
|
||||
displayName: 'Topic',
|
||||
required: true,
|
||||
refreshers: ['auth'],
|
||||
auth: googlePubsubAuth,
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please authenticate first',
|
||||
};
|
||||
}
|
||||
const json = auth.props.json;
|
||||
return common.getTopics(json);
|
||||
},
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const client = common.getClient(context.auth.props.json);
|
||||
const topic = context.propsValue.topic;
|
||||
|
||||
const url = `https://pubsub.googleapis.com/v1/${topic}:publish`;
|
||||
const json = JSON.stringify(context.propsValue.message);
|
||||
const body = JSON.stringify({
|
||||
messages: [{ data: Buffer.from(json).toString('base64') }],
|
||||
});
|
||||
|
||||
const { data } = await client.request<{ messageIds: string[] }>({
|
||||
url,
|
||||
method: 'POST',
|
||||
body,
|
||||
});
|
||||
|
||||
console.debug(
|
||||
`Message sended to topic[${topic}]: ${json}, ack: ${data.messageIds[0]}`
|
||||
);
|
||||
return json;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,71 @@
|
||||
import { JWT } from 'google-auth-library';
|
||||
|
||||
export const common = {
|
||||
getClient(authJson: string) {
|
||||
const email = common.getEmail(authJson);
|
||||
const privateKey = common.getPrivateKey(authJson);
|
||||
|
||||
const gaxios = new JWT({
|
||||
email,
|
||||
key: privateKey.replace(/\\n/g, '\n'), // remove duplicate '\' from client side
|
||||
scopes: ['https://www.googleapis.com/auth/pubsub'],
|
||||
});
|
||||
return gaxios;
|
||||
},
|
||||
|
||||
getProjectId(json: string) {
|
||||
return JSON.parse(json).project_id;
|
||||
},
|
||||
getPrivateKey(json: string) {
|
||||
return JSON.parse(json).private_key;
|
||||
},
|
||||
getEmail(json: string) {
|
||||
return JSON.parse(json).client_email;
|
||||
},
|
||||
/**
|
||||
* @returns options topics, topic value contain project name: projects/{pname}/topics/{tname}
|
||||
*/
|
||||
async getTopics(json: string) {
|
||||
const client = common.getClient(json);
|
||||
|
||||
const topics = {
|
||||
disabled: true,
|
||||
options: [] as { label: string; value: string }[],
|
||||
placeholder: 'Need authentication' as string | undefined,
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await client.request<ITopicsInfo>({
|
||||
url: `https://pubsub.googleapis.com/v1/projects/${this.getProjectId(
|
||||
json
|
||||
)}/topics`,
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
topics.options = response.data.topics.map((topic) => {
|
||||
const topicName = topic.name.split('topics/')[1];
|
||||
return { label: `${topicName}`, value: topic.name };
|
||||
});
|
||||
|
||||
delete topics.placeholder;
|
||||
topics.disabled = false;
|
||||
} catch (e: any) {
|
||||
if ('response' in e) {
|
||||
topics.placeholder = `Get topics error: ${e.response.data.error}`;
|
||||
console.debug(e.response.data.error);
|
||||
}
|
||||
}
|
||||
|
||||
return topics;
|
||||
},
|
||||
};
|
||||
|
||||
export interface IAuth {
|
||||
email: string;
|
||||
privateKey: string;
|
||||
projectId: string;
|
||||
}
|
||||
|
||||
export interface ITopicsInfo {
|
||||
topics: { name: string }[];
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
import { Property, createTrigger } from '@activepieces/pieces-framework';
|
||||
import { TriggerStrategy } from '@activepieces/pieces-framework';
|
||||
|
||||
import { googlePubsubAuth } from '../..';
|
||||
import { common } from '../common';
|
||||
|
||||
export const newMessageInTopic = createTrigger({
|
||||
auth: googlePubsubAuth,
|
||||
name: 'new_message_in_topic',
|
||||
displayName: 'New Message',
|
||||
description: 'Trigger when a new message is sended.',
|
||||
props: {
|
||||
subscription: Property.ShortText({
|
||||
displayName: 'Subscription name',
|
||||
required: true,
|
||||
}),
|
||||
topic: Property.Dropdown({
|
||||
displayName: 'Topic',
|
||||
required: true,
|
||||
auth: googlePubsubAuth,
|
||||
refreshers: ['auth'],
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please authenticate first',
|
||||
};
|
||||
}
|
||||
const json = auth.props.json;
|
||||
return common.getTopics(json);
|
||||
},
|
||||
}),
|
||||
ackDeadlineSeconds: Property.Number({
|
||||
displayName: 'Ack Deadline Seconds',
|
||||
required: true,
|
||||
defaultValue: 100,
|
||||
}),
|
||||
},
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
onEnable: async (context) => {
|
||||
const json = context.auth.props.json;
|
||||
const client = common.getClient(json);
|
||||
|
||||
const { topic, subscription } = context.propsValue;
|
||||
const project = common.getProjectId(context.auth.props.json);
|
||||
|
||||
const url = `https://pubsub.googleapis.com/v1/projects/${project}/subscriptions/${subscription}`;
|
||||
const body = {
|
||||
topic,
|
||||
pushConfig: {
|
||||
pushEndpoint: context.webhookUrl,
|
||||
attributes: {},
|
||||
},
|
||||
ackDeadlineSeconds: context.propsValue.ackDeadlineSeconds,
|
||||
};
|
||||
|
||||
await client.request({
|
||||
url,
|
||||
method: 'PUT',
|
||||
data: JSON.stringify(body),
|
||||
});
|
||||
|
||||
await context.store.put<ISubscriptionInfo>('_trigger', {
|
||||
project,
|
||||
subscription,
|
||||
});
|
||||
},
|
||||
onDisable: async (context) => {
|
||||
const response = await context.store.get<ISubscriptionInfo>('_trigger');
|
||||
|
||||
if (response !== null && response !== undefined) {
|
||||
const json = context.auth.props.json;
|
||||
const client = common.getClient(json);
|
||||
const { project, subscription } = response;
|
||||
const url = `https://pubsub.googleapis.com/v1/projects/${project}/subscriptions/${subscription}`;
|
||||
|
||||
await client.request({
|
||||
url,
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
},
|
||||
async run(context) {
|
||||
console.debug('payload received', context.payload.body);
|
||||
const payloadBody = context.payload.body as PayloadBody;
|
||||
const { data } = payloadBody.message;
|
||||
const object = data
|
||||
? JSON.parse(Buffer.from(data, 'base64').toString())
|
||||
: {};
|
||||
|
||||
return [object];
|
||||
},
|
||||
sampleData: {
|
||||
x: 1.0,
|
||||
y: -1.0,
|
||||
text: 'Just text sample',
|
||||
},
|
||||
});
|
||||
|
||||
interface ISubscriptionInfo {
|
||||
project: string;
|
||||
subscription: string;
|
||||
}
|
||||
|
||||
type PayloadBody = {
|
||||
message: {
|
||||
data: string;
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user