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,35 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { backBlazeS3Auth } from '../..';
|
||||
import { createBackBlazeS3 } from '../common';
|
||||
|
||||
export const readBackBlazeFileAction = createAction({
|
||||
auth: backBlazeS3Auth,
|
||||
name: 'read-backblaze-file',
|
||||
displayName: 'Read File',
|
||||
description: 'Read a file from Backblaze bucket to use it in other steps.',
|
||||
props: {
|
||||
key: Property.ShortText({
|
||||
displayName: 'Key',
|
||||
description: 'The key of the file to read. include extension if file has any extension.',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { bucket } = context.auth.props;
|
||||
const { key } = context.propsValue;
|
||||
const s3 = createBackBlazeS3(context.auth.props);
|
||||
|
||||
const file = await s3.getObject({
|
||||
Bucket: bucket,
|
||||
Key: key,
|
||||
});
|
||||
const base64 = await file.Body?.transformToString('base64');
|
||||
if (!base64) {
|
||||
throw new Error(`Could not read file ${key} from bucket`);
|
||||
}
|
||||
return await context.files.write({
|
||||
fileName: key,
|
||||
data: Buffer.from(base64, 'base64'),
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,137 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { backBlazeS3Auth } from '../..';
|
||||
import { createBackBlazeS3 } from '../common';
|
||||
import { ObjectCannedACL } from '@aws-sdk/client-s3';
|
||||
|
||||
export const backBlazes3UploadFileAction = createAction({
|
||||
auth: backBlazeS3Auth,
|
||||
name: 'upload-backblaze-file',
|
||||
displayName: 'Upload File',
|
||||
description: 'Upload an File to bucket.',
|
||||
props: {
|
||||
file: Property.File({
|
||||
displayName: 'File',
|
||||
required: true,
|
||||
}),
|
||||
fileName: Property.ShortText({
|
||||
displayName: 'File Name',
|
||||
required: false,
|
||||
description: 'my-file-name (no extension). write full path if you want to store in the directories or sub-directories.',
|
||||
}),
|
||||
acl: Property.StaticDropdown({
|
||||
displayName: 'ACL',
|
||||
required: false,
|
||||
options: {
|
||||
options: [
|
||||
{
|
||||
label: 'private',
|
||||
value: 'private',
|
||||
},
|
||||
{
|
||||
label: 'public-read',
|
||||
value: 'public-read',
|
||||
},
|
||||
{
|
||||
label: 'public-read-write',
|
||||
value: 'public-read-write',
|
||||
},
|
||||
{
|
||||
label: 'authenticated-read',
|
||||
value: 'authenticated-read',
|
||||
},
|
||||
{
|
||||
label: 'aws-exec-read',
|
||||
value: 'aws-exec-read',
|
||||
},
|
||||
{
|
||||
label: 'bucket-owner-read',
|
||||
value: 'bucket-owner-read',
|
||||
},
|
||||
{
|
||||
label: 'bucket-owner-full-control',
|
||||
value: 'bucket-owner-full-control',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
type: Property.StaticDropdown({
|
||||
displayName: 'Type',
|
||||
required: true,
|
||||
options: {
|
||||
options: [
|
||||
{
|
||||
label: 'image/png',
|
||||
value: 'image/png',
|
||||
},
|
||||
{
|
||||
label: 'image/jpeg',
|
||||
value: 'image/jpeg',
|
||||
},
|
||||
{
|
||||
label: 'image/gif',
|
||||
value: 'image/gif',
|
||||
},
|
||||
{
|
||||
label: 'audio/mpeg',
|
||||
value: 'audio/mpeg',
|
||||
},
|
||||
{
|
||||
label: 'audio/wav',
|
||||
value: 'audio/wav',
|
||||
},
|
||||
{
|
||||
label: 'video/mp4',
|
||||
value: 'video/mp4',
|
||||
},
|
||||
{
|
||||
label: 'application/pdf',
|
||||
value: 'application/pdf',
|
||||
},
|
||||
{
|
||||
label: 'application/msword',
|
||||
value: 'application/msword',
|
||||
},
|
||||
{
|
||||
label: 'text/plain',
|
||||
value: 'text/plain',
|
||||
},
|
||||
{
|
||||
label: 'application/json',
|
||||
value: 'application/json',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { bucket } = context.auth.props;
|
||||
const { file, fileName, acl, type } = context.propsValue;
|
||||
|
||||
const s3 = createBackBlazeS3(context.auth.props);
|
||||
|
||||
const contentType = type;
|
||||
const [_, ext] = contentType.split('/');
|
||||
const extension = '.' + ext;
|
||||
|
||||
const generatedName = new Date().toISOString() + Date.now() + extension;
|
||||
|
||||
const finalFileName = fileName ? fileName + extension : generatedName;
|
||||
|
||||
const uploadResponse = await s3.putObject({
|
||||
Bucket: bucket,
|
||||
Key: finalFileName,
|
||||
ACL: acl as ObjectCannedACL | undefined,
|
||||
ContentType: contentType,
|
||||
Body: file.data,
|
||||
});
|
||||
|
||||
const endpoint = context.auth.props.endpoint ? context.auth.props.endpoint :"";
|
||||
const cleanEndpoint = endpoint.replace("https://","")
|
||||
const url = `https://${bucket}.${cleanEndpoint}/${finalFileName}`
|
||||
return {
|
||||
fileName: finalFileName,
|
||||
etag: uploadResponse.ETag,
|
||||
url: url,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
import { isNil } from '@activepieces/shared';
|
||||
import { S3 } from '@aws-sdk/client-s3';
|
||||
|
||||
export function createBackBlazeS3(auth: {
|
||||
accessKeyId: string;
|
||||
secretAccessKey: string;
|
||||
region: string | undefined;
|
||||
endpoint: string | undefined;
|
||||
}) {
|
||||
const s3 = new S3({
|
||||
credentials: {
|
||||
accessKeyId: auth.accessKeyId,
|
||||
secretAccessKey: auth.secretAccessKey,
|
||||
},
|
||||
forcePathStyle: auth.endpoint ? true : undefined,
|
||||
region: auth.region,
|
||||
endpoint:
|
||||
auth.endpoint === '' || isNil(auth.endpoint) ? undefined : auth.endpoint,
|
||||
});
|
||||
return s3;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import {
|
||||
AppConnectionValueForAuthProperty,
|
||||
PiecePropValueSchema,
|
||||
Property,
|
||||
createTrigger,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { TriggerStrategy } from '@activepieces/pieces-framework';
|
||||
import {
|
||||
DedupeStrategy,
|
||||
Polling,
|
||||
pollingHelper,
|
||||
} from '@activepieces/pieces-common';
|
||||
|
||||
import { backBlazeS3Auth } from '../..';
|
||||
import { createBackBlazeS3 } from '../common';
|
||||
|
||||
const polling: Polling<
|
||||
AppConnectionValueForAuthProperty<typeof backBlazeS3Auth>,
|
||||
{ folderPath?: string }
|
||||
> = {
|
||||
strategy: DedupeStrategy.LAST_ITEM,
|
||||
items: async ({ auth, lastItemId, propsValue }) => {
|
||||
const s3 = createBackBlazeS3(auth.props);
|
||||
const params: any = {
|
||||
Bucket: auth.props.bucket,
|
||||
MaxKeys: 100,
|
||||
StartAfter: lastItemId,
|
||||
};
|
||||
if (propsValue.folderPath)
|
||||
params.Prefix = `${
|
||||
propsValue.folderPath.endsWith('/')
|
||||
? propsValue.folderPath.slice(0, -1)
|
||||
: propsValue.folderPath
|
||||
}`;
|
||||
|
||||
const currentValues = (await s3.listObjectsV2(params)).Contents ?? [];
|
||||
const items = (currentValues as any[]).map((item: { Key: string }) => ({
|
||||
id: item.Key,
|
||||
data: item,
|
||||
}));
|
||||
return items;
|
||||
},
|
||||
};
|
||||
|
||||
export const newBackBlazeFileTrigger = createTrigger({
|
||||
auth: backBlazeS3Auth,
|
||||
name: 'new_backblaze_file',
|
||||
displayName: 'New File',
|
||||
description: 'Trigger when a new file is uploaded.',
|
||||
props: {
|
||||
folderPath: Property.ShortText({
|
||||
displayName: 'Folder Path',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
onEnable: async (context) => {
|
||||
await pollingHelper.onEnable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
onDisable: async (context) => {
|
||||
await pollingHelper.onDisable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
run: async (context) => {
|
||||
return await pollingHelper.poll(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
files: context.files,
|
||||
});
|
||||
},
|
||||
test: async (context) => {
|
||||
return await pollingHelper.test(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
files: context.files,
|
||||
});
|
||||
},
|
||||
|
||||
sampleData: {
|
||||
Key: 'myfolder/100-3.png',
|
||||
LastModified: '2023-08-04T13:51:26.000Z',
|
||||
ETag: '"e9f16cce12352322272525f5af65a2e"',
|
||||
Size: 40239,
|
||||
StorageClass: 'STANDARD',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user