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,60 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import jimp from 'jimp';
|
||||
|
||||
export const compressImage = createAction({
|
||||
name: 'compress_image',
|
||||
description: 'Compresses an image',
|
||||
displayName: 'Compresses an image',
|
||||
props: {
|
||||
image: Property.File({
|
||||
displayName: 'Image',
|
||||
required: true,
|
||||
}),
|
||||
quality: Property.StaticDropdown({
|
||||
displayName: 'Quality',
|
||||
description:
|
||||
'Specifies the quality of the image after compression (0-100).',
|
||||
required: true,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'High Quality', value: 90 },
|
||||
{ label: 'Lossy Quality', value: 60 },
|
||||
],
|
||||
},
|
||||
}),
|
||||
format: Property.StaticDropdown({
|
||||
displayName: 'Format',
|
||||
description: 'Specifies the format of the image after compression.',
|
||||
required: true,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'JPG', value: 'jpg' },
|
||||
{ label: 'PNG', value: 'png' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
resultFileName: Property.ShortText({
|
||||
displayName: 'Result File Name',
|
||||
description:
|
||||
'Specifies the output file name for the result image (without extension).',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const image = await jimp.read(context.propsValue.image.data);
|
||||
|
||||
image.quality(context.propsValue.quality);
|
||||
|
||||
const imageBuffer = await image.getBufferAsync(image.getMIME());
|
||||
|
||||
const imageReference = await context.files.write({
|
||||
fileName:
|
||||
(context.propsValue.resultFileName ?? 'image') +
|
||||
'.' +
|
||||
context.propsValue.format,
|
||||
data: imageBuffer,
|
||||
});
|
||||
|
||||
return imageReference;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,65 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import jimp from 'jimp';
|
||||
|
||||
export const cropImage = createAction({
|
||||
name: 'crop_image',
|
||||
description: 'Crops an image',
|
||||
displayName: 'Crop an image',
|
||||
props: {
|
||||
image: Property.File({
|
||||
displayName: 'Image',
|
||||
required: true,
|
||||
}),
|
||||
left: Property.Number({
|
||||
displayName: 'Left',
|
||||
description:
|
||||
'Specifies the horizontal position, indicating where the cropping starts from the left side of the image.',
|
||||
required: true,
|
||||
}),
|
||||
top: Property.Number({
|
||||
displayName: 'Top',
|
||||
description:
|
||||
'Represents the vertical position, indicating the starting point from the top of the image.',
|
||||
required: true,
|
||||
}),
|
||||
width: Property.Number({
|
||||
displayName: 'Width',
|
||||
description: 'Determines the horizontal size of the cropped area.',
|
||||
required: true,
|
||||
}),
|
||||
height: Property.Number({
|
||||
displayName: 'Height',
|
||||
description: 'Determines the vertical size of the cropped area.',
|
||||
required: true,
|
||||
}),
|
||||
resultFileName: Property.ShortText({
|
||||
displayName: 'Result File Name',
|
||||
description:
|
||||
'Specifies the output file name for the cropped image (without extension).',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const image = await jimp.read(context.propsValue.image.data);
|
||||
await image.crop(
|
||||
context.propsValue.left,
|
||||
context.propsValue.top,
|
||||
context.propsValue.width,
|
||||
context.propsValue.height
|
||||
);
|
||||
|
||||
const imageBuffer = await image.getBufferAsync(image.getMIME());
|
||||
|
||||
const fileName =
|
||||
(context.propsValue.resultFileName ?? 'image') +
|
||||
'.' +
|
||||
image.getExtension();
|
||||
|
||||
const imageReference = await context.files.write({
|
||||
fileName: fileName,
|
||||
data: imageBuffer,
|
||||
});
|
||||
|
||||
return imageReference;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import * as ExifReader from 'exifreader';
|
||||
|
||||
export const getMetaData = createAction({
|
||||
name: 'get_meta_data',
|
||||
description: 'Gets metadata from an image',
|
||||
displayName: 'Get image metadata',
|
||||
props: {
|
||||
image: Property.File({
|
||||
displayName: 'Image',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const tags = await ExifReader.load(context.propsValue.image.data);
|
||||
return tags;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import mime from 'mime-types';
|
||||
|
||||
export const imageToBase64 = createAction({
|
||||
name: 'image_to_base64',
|
||||
description: 'Converts an image to an url-like Base64 string',
|
||||
displayName: 'Image to Base64',
|
||||
props: {
|
||||
image: Property.File({
|
||||
displayName: 'Image',
|
||||
description: 'The image to convert',
|
||||
required: true,
|
||||
}),
|
||||
override_mime_type: Property.ShortText({
|
||||
displayName: 'Override mime type',
|
||||
description:
|
||||
'The mime type to use when converting the image. In case you want to override the default mime type. Example image/png',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const image = context.propsValue.image;
|
||||
const mimeType = mime.lookup(
|
||||
image.extension ? image.extension : 'image/png'
|
||||
);
|
||||
|
||||
const actualMimeType = context.propsValue.override_mime_type
|
||||
? context.propsValue.override_mime_type
|
||||
: mimeType;
|
||||
return `data:${actualMimeType};base64,${image.base64}`;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import jimp from 'jimp';
|
||||
|
||||
export const resizeImage = createAction({
|
||||
name: 'resize_image',
|
||||
description: 'Resizes an image',
|
||||
displayName: 'Resize an image',
|
||||
props: {
|
||||
image: Property.File({
|
||||
displayName: 'Image',
|
||||
required: true,
|
||||
}),
|
||||
width: Property.Number({
|
||||
displayName: 'Width',
|
||||
description: 'Specifies the width of the image.',
|
||||
required: true,
|
||||
}),
|
||||
height: Property.Number({
|
||||
displayName: 'Height',
|
||||
description: 'Specifies the height of the image.',
|
||||
required: true,
|
||||
}),
|
||||
aspectRatio: Property.Checkbox({
|
||||
displayName: 'Maintain aspect ratio for height',
|
||||
required: false,
|
||||
defaultValue: false,
|
||||
}),
|
||||
resultFileName: Property.ShortText({
|
||||
displayName: 'Result File Name',
|
||||
description:
|
||||
'Specifies the output file name for the result image (without extension).',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const image = await jimp.read(context.propsValue.image.data);
|
||||
await image.resize(
|
||||
context.propsValue.width,
|
||||
context.propsValue.aspectRatio ? jimp.AUTO : context.propsValue.height
|
||||
);
|
||||
|
||||
const imageBuffer = await image.getBufferAsync(image.getMIME());
|
||||
|
||||
const imageReference = await context.files.write({
|
||||
fileName:
|
||||
(context.propsValue.resultFileName ?? 'image') +
|
||||
'.' +
|
||||
image.getExtension(),
|
||||
data: imageBuffer,
|
||||
});
|
||||
|
||||
return imageReference;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import jimp from 'jimp';
|
||||
|
||||
export const rotateImage = createAction({
|
||||
name: 'rotate_image',
|
||||
description: 'Rotates an image',
|
||||
displayName: 'Rotate an image',
|
||||
props: {
|
||||
image: Property.File({
|
||||
displayName: 'Image',
|
||||
required: true,
|
||||
}),
|
||||
degree: Property.StaticDropdown({
|
||||
displayName: 'Degree',
|
||||
description:
|
||||
'Specifies the degree of clockwise rotation applied to the image.',
|
||||
required: true,
|
||||
options: {
|
||||
options: [
|
||||
{ value: 90, label: '90°' },
|
||||
{ value: 180, label: '180°' },
|
||||
{ value: 270, label: '270°' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
resultFileName: Property.ShortText({
|
||||
displayName: 'Result File Name',
|
||||
description:
|
||||
'Specifies the output file name for the result image (without extension).',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const image = await jimp.read(context.propsValue.image.data);
|
||||
await image.rotate(-context.propsValue.degree);
|
||||
|
||||
const imageBuffer = await image.getBufferAsync(image.getMIME());
|
||||
|
||||
const imageReference = await context.files.write({
|
||||
fileName:
|
||||
(context.propsValue.resultFileName ?? 'image') +
|
||||
'.' +
|
||||
image.getExtension(),
|
||||
data: imageBuffer,
|
||||
});
|
||||
|
||||
return imageReference;
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user