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,15 @@
{
"Calculate Average": "Durchschnittsberechnung",
"Calculate Sum": "Summe berechnen",
"Count Uniques": "Count Uniques",
"Find Min and Max": "Finde Min und Max",
"Calculates the average of a list of values.": "Berechnet den Durchschnitt einer Liste von Werten.",
"Calculates the sum of a list of values.": "Berechnet die Summe einer Liste von Werten.",
"Counts the number of unique values for multiple fields": "Zählt die Anzahl der eindeutigen Werte für mehrere Felder",
"Get the smallest and greatest values from a list of numeric values.": "Holen Sie die kleinsten und größten Werte aus einer Liste von numerischen Werten.",
"Markdown": "Markdown",
"Values": "Werte",
"Fields": "Felder",
"If you'd like to use the values with a previous step, click the (X) first, and then select the step you want to use.": "Wenn Sie die Werte mit einem vorherigen Schritt verwenden möchten, klicken Sie zuerst auf (X) und wählen dann den Schritt, den Sie verwenden möchten.",
"If the data you're passing in is an object, you can specify certain fields to filter on. The object will be discarded if the fields don't exist. Otherwise, leave fields empty.": "Wenn die Daten, die Sie weitergeben, ein Objekt sind, können Sie bestimmte Felder angeben, nach denen Sie filtern können. Das Objekt wird verworfen, wenn die Felder nicht existieren. Andernfalls lassen Sie die Felder leer."
}

View File

@@ -0,0 +1,15 @@
{
"Calculate Average": "Cálculo medio",
"Calculate Sum": "Suma de Calcular",
"Count Uniques": "Count Uniques",
"Find Min and Max": "Encontrar mínimo y máximo",
"Calculates the average of a list of values.": "Calcula el promedio de una lista de valores.",
"Calculates the sum of a list of values.": "Calcula la suma de una lista de valores.",
"Counts the number of unique values for multiple fields": "Cuenta el número de valores únicos para varios campos",
"Get the smallest and greatest values from a list of numeric values.": "Obtener los valores más pequeños y mayores de una lista de valores numéricos.",
"Markdown": "Markdown",
"Values": "Valores",
"Fields": "Campos",
"If you'd like to use the values with a previous step, click the (X) first, and then select the step you want to use.": "Si quieres usar los valores con un paso anterior, haz clic en el (X) primero, y luego selecciona el paso que quieres utilizar.",
"If the data you're passing in is an object, you can specify certain fields to filter on. The object will be discarded if the fields don't exist. Otherwise, leave fields empty.": "Si los datos que está pasando son un objeto, puede especificar ciertos campos en los que filtrar. El objeto se descartará si los campos no existen. De lo contrario, deje los campos vacíos."
}

View File

@@ -0,0 +1,15 @@
{
"Calculate Average": "Calculer la moyenne",
"Calculate Sum": "Calculer la somme",
"Count Uniques": "Count Uniques",
"Find Min and Max": "Trouver Min et Max",
"Calculates the average of a list of values.": "Calcule la moyenne d'une liste de valeurs.",
"Calculates the sum of a list of values.": "Calcule la somme d'une liste de valeurs.",
"Counts the number of unique values for multiple fields": "Compte le nombre de valeurs uniques pour plusieurs champs",
"Get the smallest and greatest values from a list of numeric values.": "Récupère les plus petites et les plus grandes valeurs à partir d'une liste de valeurs numériques.",
"Markdown": "Markdown",
"Values": "Valeurs",
"Fields": "Champs",
"If you'd like to use the values with a previous step, click the (X) first, and then select the step you want to use.": "Si vous souhaitez utiliser les valeurs avec une étape précédente, cliquez sur le (X) d'abord, puis sélectionnez l'étape que vous souhaitez utiliser.",
"If the data you're passing in is an object, you can specify certain fields to filter on. The object will be discarded if the fields don't exist. Otherwise, leave fields empty.": "Si les données que vous passez sont un objet, vous pouvez spécifier certains champs sur lesquels filtrer. L'objet sera supprimé si les champs n'existent pas. Sinon, laissez les champs vides."
}

View File

@@ -0,0 +1,15 @@
{
"Calculate Average": "平均を計算する",
"Calculate Sum": "合計を計算",
"Count Uniques": "Count Uniques",
"Find Min and Max": "最小値と最大値を検索",
"Calculates the average of a list of values.": "値のリストの平均を計算します。",
"Calculates the sum of a list of values.": "値のリストの合計を計算します。",
"Counts the number of unique values for multiple fields": "複数のフィールドの一意の値の数をカウントします。",
"Get the smallest and greatest values from a list of numeric values.": "数値のリストから最小値と最大値を取得します。",
"Markdown": "Markdown",
"Values": "値",
"Fields": "フィールド",
"If you'd like to use the values with a previous step, click the (X) first, and then select the step you want to use.": "前のステップで値を使用する場合は、まず (X) をクリックしてから、使用するステップを選択します。",
"If the data you're passing in is an object, you can specify certain fields to filter on. The object will be discarded if the fields don't exist. Otherwise, leave fields empty.": "渡すデータがオブジェクトの場合、フィルタリングする特定のフィールドを指定できます。 フィールドが存在しない場合、オブジェクトは破棄されます。そうでなければ、フィールドは空のままにします。"
}

View File

@@ -0,0 +1,15 @@
{
"Calculate Average": "Gemiddelde berekening",
"Calculate Sum": "Som berekenen",
"Count Uniques": "Count Uniques",
"Find Min and Max": "Vind Min en Max",
"Calculates the average of a list of values.": "Berekent het gemiddelde van een lijst met waarden.",
"Calculates the sum of a list of values.": "Berekent de som van een lijst met waarden.",
"Counts the number of unique values for multiple fields": "Telt het aantal unieke waarden voor meerdere velden",
"Get the smallest and greatest values from a list of numeric values.": "Krijg de kleinste en beste waarden van een lijst met numerieke waarden.",
"Markdown": "Markdown",
"Values": "Waarden",
"Fields": "Velden",
"If you'd like to use the values with a previous step, click the (X) first, and then select the step you want to use.": "Als je de waardes met een vorige stap wilt gebruiken, klik dan eerst op de (X) en vervolgens op de stap die je wilt gebruiken.",
"If the data you're passing in is an object, you can specify certain fields to filter on. The object will be discarded if the fields don't exist. Otherwise, leave fields empty.": "Als de gegevens die je doorgeeft een object zijn, kun je bepaalde velden opgeven waarop je moet filteren. Het object wordt verwijderd als de velden niet bestaan. Laat anders de velden leeg."
}

View File

@@ -0,0 +1,15 @@
{
"Calculate Average": "Calcular média",
"Calculate Sum": "Calcular Soma",
"Count Uniques": "Count Uniques",
"Find Min and Max": "Encontre Min e Max",
"Calculates the average of a list of values.": "Calcula a média de uma lista de valores.",
"Calculates the sum of a list of values.": "Calcula a soma de uma lista de valores.",
"Counts the number of unique values for multiple fields": "Conta o número de valores exclusivos para vários campos",
"Get the smallest and greatest values from a list of numeric values.": "Obtenha o menor e o maior valor a partir de uma lista de valores numéricos.",
"Markdown": "Markdown",
"Values": "Valores",
"Fields": "campos",
"If you'd like to use the values with a previous step, click the (X) first, and then select the step you want to use.": "Se você deseja usar os valores com um passo anterior, clique primeiro no (X) e depois selecione o passo que você deseja usar.",
"If the data you're passing in is an object, you can specify certain fields to filter on. The object will be discarded if the fields don't exist. Otherwise, leave fields empty.": "Se os dados que você está passando forem um objeto, você pode especificar certos campos para filtrar. O objeto será descartado se os campos não existirem. Caso contrário, deixe os campos vazios."
}

View File

@@ -0,0 +1,16 @@
{
"Data Summarizer": "Сводка данных",
"Calculate Average": "Вычислить среднее",
"Calculate Sum": "Вычислить сумму",
"Count Uniques": "Count Uniques",
"Find Min and Max": "Найти мин и Макс",
"Calculates the average of a list of values.": "Вычисляет среднее значение списка.",
"Calculates the sum of a list of values.": "Вычисляет сумму списка значений.",
"Counts the number of unique values for multiple fields": "Засчитывает количество уникальных значений для нескольких полей",
"Get the smallest and greatest values from a list of numeric values.": "Получить наименьшие и наибольшие значения из списка числовых значений.",
"Markdown": "Markdown",
"Values": "Значения",
"Fields": "Поля",
"If you'd like to use the values with a previous step, click the (X) first, and then select the step you want to use.": "Если вы хотите использовать значения с предыдущим шагом, нажмите сначала (X), а затем выберите шаг, который вы хотите использовать.",
"If the data you're passing in is an object, you can specify certain fields to filter on. The object will be discarded if the fields don't exist. Otherwise, leave fields empty.": "Если данные, в которых вы передаете это объект, вы можете указать определенные поля для фильтрации. Объект будет удален, если поля не существуют. Иначе оставьте поля пустыми."
}

View File

@@ -0,0 +1,15 @@
{
"Calculate Average": "Calculate Average",
"Calculate Sum": "Calculate Sum",
"Count Uniques": "Count Uniques",
"Find Min and Max": "Find Min and Max",
"Calculates the average of a list of values.": "Calculates the average of a list of values.",
"Calculates the sum of a list of values.": "Calculates the sum of a list of values.",
"Counts the number of unique values for multiple fields": "Counts the number of unique values for multiple fields",
"Get the smallest and greatest values from a list of numeric values.": "Get the smallest and greatest values from a list of numeric values.",
"Markdown": "Markdown",
"Values": "Values",
"Fields": "Fields",
"If you'd like to use the values with a previous step, click the (X) first, and then select the step you want to use.": "If you'd like to use the values with a previous step, click the (X) first, and then select the step you want to use.",
"If the data you're passing in is an object, you can specify certain fields to filter on. The object will be discarded if the fields don't exist. Otherwise, leave fields empty.": "If the data you're passing in is an object, you can specify certain fields to filter on. The object will be discarded if the fields don't exist. Otherwise, leave fields empty."
}

View File

@@ -0,0 +1,16 @@
{
"Data Summarizer": "Data Summarizer",
"Calculate Average": "Calculate Average",
"Calculate Sum": "Calculate Sum",
"Count Uniques": "Count Uniques",
"Find Min and Max": "Find Min and Max",
"Calculates the average of a list of values.": "Calculates the average of a list of values.",
"Calculates the sum of a list of values.": "Calculates the sum of a list of values.",
"Counts the number of unique values for multiple fields": "Counts the number of unique values for multiple fields",
"Get the smallest and greatest values from a list of numeric values.": "Get the smallest and greatest values from a list of numeric values.",
"Markdown": "Markdown",
"Values": "Values",
"Fields": "Fields",
"If you'd like to use the values with a previous step, click the (X) first, and then select the step you want to use.": "If you'd like to use the values with a previous step, click the (X) first, and then select the step you want to use.",
"If the data you're passing in is an object, you can specify certain fields to filter on. The object will be discarded if the fields don't exist. Otherwise, leave fields empty.": "If the data you're passing in is an object, you can specify certain fields to filter on. The object will be discarded if the fields don't exist. Otherwise, leave fields empty."
}

View File

@@ -0,0 +1,15 @@
{
"Calculate Average": "Calculate Average",
"Calculate Sum": "Calculate Sum",
"Count Uniques": "Count Uniques",
"Find Min and Max": "Find Min and Max",
"Calculates the average of a list of values.": "Calculates the average of a list of values.",
"Calculates the sum of a list of values.": "Calculates the sum of a list of values.",
"Counts the number of unique values for multiple fields": "Counts the number of unique values for multiple fields",
"Get the smallest and greatest values from a list of numeric values.": "Get the smallest and greatest values from a list of numeric values.",
"Markdown": "Markdown",
"Values": "值",
"Fields": "Fields",
"If you'd like to use the values with a previous step, click the (X) first, and then select the step you want to use.": "If you'd like to use the values with a previous step, click the (X) first, and then select the step you want to use.",
"If the data you're passing in is an object, you can specify certain fields to filter on. The object will be discarded if the fields don't exist. Otherwise, leave fields empty.": "If the data you're passing in is an object, you can specify certain fields to filter on. The object will be discarded if the fields don't exist. Otherwise, leave fields empty."
}

View File

@@ -0,0 +1,17 @@
import { createPiece, PieceAuth } from '@activepieces/pieces-framework';
import { calculateAverage } from './lib/actions/calculate-average';
import { calculateSum } from './lib/actions/calculate-sum';
import { countUniques } from './lib/actions/count-uniques';
import { getMinMax } from './lib/actions/get-min-max';
import { PieceCategory } from '@activepieces/shared';
export const dataSummarizer = createPiece({
displayName: 'Data Summarizer',
auth: PieceAuth.None(),
minimumSupportedRelease: '0.30.0',
logoUrl: 'https://cdn.activepieces.com/pieces/data-summarizer.svg',
authors: ['tahboubali'],
actions: [calculateAverage, calculateSum, countUniques, getMinMax],
triggers: [],
categories: [PieceCategory.CORE]
});

View File

@@ -0,0 +1,25 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { common } from '../common';
export const calculateAverage = createAction({
name: 'calculateAverage',
displayName: 'Calculate Average',
description: 'Calculates the average of a list of values.',
props: {
note: common.note,
values: Property.Array({
displayName: "Values",
required: true,
})
},
async run({ propsValue }) {
const result = common.validateArray(propsValue.values);
if (result.hasError) {
throw new Error(JSON.stringify(result.error));
}
const sum = result.values.reduce((acc, value) => acc + value, 0);
return {
average: sum / result.values.length
};
},
});

View File

@@ -0,0 +1,25 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { common } from '../common';
export const calculateSum = createAction({
name: 'calculateSum',
displayName: 'Calculate Sum',
description: 'Calculates the sum of a list of values.',
props: {
note: common.note,
values: Property.Array({
displayName: "Values",
required: true,
})
},
async run({ propsValue }) {
const result = common.validateArray(propsValue.values);
if (result.hasError) {
throw new Error(JSON.stringify(result.error));
}
const sum = result.values.reduce((acc, value) => acc + value, 0);
return {
sum: sum
};
},
});

View File

@@ -0,0 +1,57 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { common } from '../common';
import { isNil } from '@activepieces/shared';
export const countUniques = createAction({
name: 'countUniques',
displayName: 'Count Uniques',
description: 'Counts the number of unique values for multiple fields',
props: {
note: common.note,
values: Property.Array({
displayName: "Values",
required: true,
}),
fieldsExplanation: Property.MarkDown({
value: "If the data you're passing in is an object, you can specify certain fields to filter on. The object will be discarded if the fields don't exist. Otherwise, leave fields empty."
}),
fields: Property.Array({
displayName: "Fields",
required: false
})
},
async run({ propsValue }) {
const values = propsValue.values;
const unknownFields = propsValue.fields != undefined && propsValue.fields.length > 0 ? propsValue.fields : null;
const fields = validateFields(unknownFields)
return {
numUniques: numUniques(values, fields)
};
},
});
function validateFields(fields: unknown[] | null): string[] | null {
if (!isNil(fields) && Array.isArray(fields) && fields.every(value => typeof value === 'string')) {
return fields as string[]
}
else return null
}
function numUniques<T>(values: T[], fields: string[] | null = null) {
if (isNil(fields)) {
return new Set(values.map(value => JSON.stringify(value))).size
}
const newValues = values.map(value => {
const obj: { [k: string]: unknown } = {}
if (typeof value !== 'object') {
return obj
}
for (const key in value) {
if (fields.includes(key)) {
obj[key] = value[key]
}
}
return obj
})
return new Set(newValues.map(value => JSON.stringify(value))).size
}

View File

@@ -0,0 +1,24 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { common } from '../common';
export const getMinMax = createAction({
name: 'getMinMax',
displayName: 'Find Min and Max',
description: 'Get the smallest and greatest values from a list of numeric values.',
props: {
note: common.note,
values: Property.Array({
displayName: 'Values',
required: true
})
},
async run({ propsValue }) {
const result = common.validateArray(propsValue.values);
if (result.hasError)
throw new Error(JSON.stringify(result.error));
return {
max: Math.max(...result.values),
min: Math.min(...result.values)
};
}
});

View File

@@ -0,0 +1,63 @@
import { Property } from "@activepieces/pieces-framework"
import { isNil } from "@activepieces/shared"
type ErrorInfo = {
value: unknown | null,
location: number
}
type Response = {
hasError: true,
error: {
message: string,
errors: ErrorInfo[]
}
} | {
hasError: false,
values: number[]
}
export const common = {
note: Property.MarkDown({
value: "If you'd like to use the values with a previous step, click the (X) first, and then select the step you want to use.",
}),
validateArray: function (values: unknown[]): Response {
const newValues = values.map((value, index) => checkValueIsNumber(value, index))
const isAllNumbers = newValues.every((value) => value.error === null)
if(isAllNumbers) {
return {
hasError: false,
values: newValues.map((value) => value.value as number),
}
}
return {
hasError: true,
error: {
message: 'The following values are not numbers',
errors: newValues.filter((value) => !isNil(value)).map((value) => value.error as ErrorInfo)
}
}
}
}
type ValueInfo = {
error: ErrorInfo | null,
value: number | null
}
export const checkValueIsNumber = function (value: unknown, location: number): ValueInfo {
const parsedValue = Number(value);
if (!Number.isNaN(parsedValue)) {
return {
error: null,
value: Number(value)
}
}
return {
error: {
value: value,
location: location
},
value: -1
}
}