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,19 @@
{
"Customer data platform for user analytics and tracking": "Kundendatenplattform für Benutzeranalyse und -verfolgung",
"API Key": "API-Schlüssel",
"Base URL": "Basis-URL",
"Your API key of Dittofeed.": "Ihr API-Schlüssel des Dittofeed.",
"The base URL of your Dittofeed instance.": "Die Basis-URL deiner Dittofeed-Instanz.",
"Identify User": "Benutzer identifizieren",
"Track Event": "Ereignis verfolgen",
"Screen Event": "Bildschirmereignis",
"Identify a user in Dittofeed.": "Benutzer im Dittofeed identifizieren.",
"Track an event for a user.": "Verfolgen Sie ein Ereignis für einen Benutzer.",
"Track a screen view event.": "Verfolgen Sie eine Bildschirmansicht.",
"User ID": "Benutzer-ID",
"User Traits": "Benutzereigenschaften",
"Event Name": "Ereignisname",
"Event Properties": "Ereigniseigenschaften",
"Screen Name": "Bildschirmname",
"Screen Properties": "Bildschirmeigenschaften"
}

View File

@@ -0,0 +1,19 @@
{
"Customer data platform for user analytics and tracking": "Plataforma de datos de clientes para análisis y seguimiento de usuarios",
"API Key": "Clave API",
"Base URL": "URL base",
"Your API key of Dittofeed.": "Tu clave API de Dittofeed.",
"The base URL of your Dittofeed instance.": "La URL base de tu instancia de Dittofeed.",
"Identify User": "Identificar usuario",
"Track Event": "Rastrear evento",
"Screen Event": "Evento de pantalla",
"Identify a user in Dittofeed.": "Identificar un usuario en Dittofeed.",
"Track an event for a user.": "Rastrear un evento para un usuario.",
"Track a screen view event.": "Rastrear un evento de vista de pantalla.",
"User ID": "ID Usuario",
"User Traits": "Rasgos de usuario",
"Event Name": "Nombre del evento",
"Event Properties": "Propiedades del evento",
"Screen Name": "Nombre de usuario",
"Screen Properties": "Propiedades de pantalla"
}

View File

@@ -0,0 +1,19 @@
{
"Customer data platform for user analytics and tracking": "Plateforme de données client pour l'analyse et le suivi des utilisateurs",
"API Key": "Clé API",
"Base URL": "URL de base",
"Your API key of Dittofeed.": "Votre clé API de Dittofeed.",
"The base URL of your Dittofeed instance.": "L'URL de base de votre instance Dittofeed.",
"Identify User": "Identifier l'utilisateur",
"Track Event": "Suivre l'évènement",
"Screen Event": "Evénement de l'écran",
"Identify a user in Dittofeed.": "Identifier un utilisateur dans Dittofeed.",
"Track an event for a user.": "Suivre un événement pour un utilisateur.",
"Track a screen view event.": "Suivre un événement en vue d'écran.",
"User ID": "Identifiant de l'utilisateur",
"User Traits": "Caractéristiques de l'utilisateur",
"Event Name": "Nom de l'événement",
"Event Properties": "Propriétés de l'événement",
"Screen Name": "Nom d'écran",
"Screen Properties": "Propriétés de l'écran"
}

View File

@@ -0,0 +1,19 @@
{
"Customer data platform for user analytics and tracking": "ユーザー分析と追跡のための顧客データプラットフォーム",
"API Key": "API キー",
"Base URL": "ベースURL",
"Your API key of Dittofeed.": "ディットフィードの API キー。",
"The base URL of your Dittofeed instance.": "DittofeedインスタンスのベースURL。",
"Identify User": "ユーザーを識別する",
"Track Event": "イベントを追跡",
"Screen Event": "スクリーンイベント",
"Identify a user in Dittofeed.": "Dittofeedでユーザーを識別します。",
"Track an event for a user.": "ユーザーのイベントを追跡します。",
"Track a screen view event.": "画面表示イベントを追跡します。",
"User ID": "ユーザー ID",
"User Traits": "ユーザーの特性",
"Event Name": "イベント名",
"Event Properties": "イベントのプロパティ",
"Screen Name": "画面名",
"Screen Properties": "画面のプロパティ"
}

View File

@@ -0,0 +1,19 @@
{
"Customer data platform for user analytics and tracking": "Platform voor klantgegevens voor gebruikersanalyses en het volgen van gegevens",
"API Key": "API Sleutel",
"Base URL": "Basis URL",
"Your API key of Dittofeed.": "Je API-sleutel van Dittofeed.",
"The base URL of your Dittofeed instance.": "De basis-URL van je Dittofeed instantie.",
"Identify User": "Identificeer gebruiker",
"Track Event": "Volg Evenement",
"Screen Event": "Scherm Evenement",
"Identify a user in Dittofeed.": "Identificeer een gebruiker in Dittofeed.",
"Track an event for a user.": "Volg een gebeurtenis voor een gebruiker.",
"Track a screen view event.": "Houd een schermweergave gebeurtenis bij.",
"User ID": "Gebruiker ID",
"User Traits": "Gebruiker Eigenschappen",
"Event Name": "Naam van gebeurtenis",
"Event Properties": "Evenement eigenschappen",
"Screen Name": "Schermnaam",
"Screen Properties": "Scherm Eigenschappen"
}

View File

@@ -0,0 +1,19 @@
{
"Customer data platform for user analytics and tracking": "Plataforma de dados do cliente para análise e rastreamento do usuário",
"API Key": "Chave de API",
"Base URL": "URL Base",
"Your API key of Dittofeed.": "Sua chave da API do Dittofeed.",
"The base URL of your Dittofeed instance.": "A URL base da instância do Dittofeed",
"Identify User": "Identificar Usuário",
"Track Event": "Rastrear evento",
"Screen Event": "Evento Tela",
"Identify a user in Dittofeed.": "Identificar um usuário em Dittofeed.",
"Track an event for a user.": "Acompanha um evento para um usuário.",
"Track a screen view event.": "Rastrear um evento de visualização de tela.",
"User ID": "ID de usuário",
"User Traits": "Características do Usuário",
"Event Name": "Nome do Evento",
"Event Properties": "Propriedades do evento",
"Screen Name": "Nome de exibição",
"Screen Properties": "Propriedades da tela"
}

View File

@@ -0,0 +1,19 @@
{
"Customer data platform for user analytics and tracking": "Customer data platform for user analytics and tracking",
"API Key": "API Key",
"Base URL": "Base URL",
"Your API key of Dittofeed.": "Your API key of Dittofeed.",
"The base URL of your Dittofeed instance.": "The base URL of your Dittofeed instance.",
"Identify User": "Identify User",
"Track Event": "Track Event",
"Screen Event": "Screen Event",
"Identify a user in Dittofeed.": "Identify a user in Dittofeed.",
"Track an event for a user.": "Track an event for a user.",
"Track a screen view event.": "Track a screen view event.",
"User ID": "User ID",
"User Traits": "User Traits",
"Event Name": "Event Name",
"Event Properties": "Event Properties",
"Screen Name": "Screen Name",
"Screen Properties": "Screen Properties"
}

View File

@@ -0,0 +1,19 @@
{
"Customer data platform for user analytics and tracking": "Customer data platform for user analytics and tracking",
"API Key": "API 密钥",
"Base URL": "基本网址",
"Your API key of Dittofeed.": "Your API key of Dittofeed.",
"The base URL of your Dittofeed instance.": "The base URL of your Dittofeed instance.",
"Identify User": "Identify User",
"Track Event": "Track Event",
"Screen Event": "Screen Event",
"Identify a user in Dittofeed.": "Identify a user in Dittofeed.",
"Track an event for a user.": "Track an event for a user.",
"Track a screen view event.": "Track a screen view event.",
"User ID": "User ID",
"User Traits": "User Traits",
"Event Name": "Event Name",
"Event Properties": "Event Properties",
"Screen Name": "Screen Name",
"Screen Properties": "Screen Properties"
}

View File

@@ -0,0 +1,41 @@
import { createPiece, PieceAuth, Property } from "@activepieces/pieces-framework";
import { PieceCategory } from "@activepieces/shared";
import { identifyAction } from './lib/actions/identify';
import { trackAction } from './lib/actions/track';
import { screenAction } from './lib/actions/screen';
export const dittofeedAuth = PieceAuth.CustomAuth({
props: {
apiKey: PieceAuth.SecretText({
displayName: 'API Key',
required: true,
description: 'Your API key of Dittofeed.',
}),
baseUrl: Property.ShortText({
displayName: 'Base URL',
required: true,
description: 'The base URL of your Dittofeed instance.',
defaultValue: 'http://localhost:3200',
}),
},
required: true,
});
export const dittofeed = createPiece({
displayName: "Dittofeed",
auth: dittofeedAuth,
minimumSupportedRelease: '0.36.1',
logoUrl: "https://cdn.activepieces.com/pieces/dittofeed.png",
authors: [
'SmarterService'
],
categories: [
PieceCategory.MARKETING,
PieceCategory.BUSINESS_INTELLIGENCE
],
description: 'Customer data platform for user analytics and tracking',
actions: [identifyAction, trackAction, screenAction],
triggers: [],
});

View File

@@ -0,0 +1,53 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { dittofeedAuth } from '../..';
export const identifyAction = createAction({
name: 'identify',
auth: dittofeedAuth,
displayName: 'Identify User',
description: 'Identify a user in Dittofeed.',
props: {
userId: Property.ShortText({
displayName: 'User ID',
required: true,
}),
traits: Property.Object({
displayName: 'User Traits',
required: false,
}),
},
async run(context) {
const { userId, traits } = context.propsValue;
const { apiKey, baseUrl } = context.auth.props;
try {
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: `${baseUrl}/api/public/apps/identify`,
headers: {
Authorization: apiKey,
},
body: {
type: 'identify',
messageId: `identify-${userId}-${Date.now()}`,
userId,
traits,
},
});
return response.body;
} catch (error: any) {
if (error.response?.status === 401) {
throw new Error('Authentication failed. Please check your API key.');
} else if (error.response?.status === 404) {
throw new Error(`Dittofeed API endpoint not found. Please check your base URL: ${baseUrl}`);
} else if (error.response?.status === 429) {
throw new Error('Rate limit exceeded. Please try again later.');
} else if (error.response?.status >= 500) {
throw new Error(`Dittofeed server error: ${error.response?.body?.message || error.message}`);
}
throw new Error(`Failed to identify user in Dittofeed: ${error.message || 'Unknown error'}`);
}
},
});

View File

@@ -0,0 +1,58 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { dittofeedAuth } from '../..';
export const screenAction = createAction({
name: 'screen',
auth: dittofeedAuth,
displayName: 'Screen Event',
description: 'Track a screen view event.',
props: {
userId: Property.ShortText({
displayName: 'User ID',
required: true,
}),
name: Property.ShortText({
displayName: 'Screen Name',
required: true,
}),
properties: Property.Object({
displayName: 'Screen Properties',
required: false,
}),
},
async run(context) {
const { userId, name, properties } = context.propsValue;
const { apiKey, baseUrl } = context.auth.props;
try {
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: `${baseUrl}/api/public/apps/screen`,
headers: {
Authorization: apiKey,
},
body: {
type: 'screen',
messageId: `screen-${userId}-${name}-${Date.now()}`,
userId,
name,
properties,
},
});
return response.body;
} catch (error: any) {
if (error.response?.status === 401) {
throw new Error('Authentication failed. Please check your API key.');
} else if (error.response?.status === 404) {
throw new Error(`Dittofeed API endpoint not found. Please check your base URL: ${baseUrl}`);
} else if (error.response?.status === 429) {
throw new Error('Rate limit exceeded. Please try again later.');
} else if (error.response?.status >= 500) {
throw new Error(`Dittofeed server error: ${error.response?.body?.message || error.message}`);
}
throw new Error(`Failed to track screen view in Dittofeed: ${error.message || 'Unknown error'}`);
}
},
});

View File

@@ -0,0 +1,58 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { dittofeedAuth } from '../..';
export const trackAction = createAction({
name: 'track',
auth: dittofeedAuth,
displayName: 'Track Event',
description: 'Track an event for a user.',
props: {
userId: Property.ShortText({
displayName: 'User ID',
required: true,
}),
event: Property.ShortText({
displayName: 'Event Name',
required: true,
}),
properties: Property.Object({
displayName: 'Event Properties',
required: false,
}),
},
async run(context) {
const { userId, event, properties } = context.propsValue;
const { apiKey, baseUrl } = context.auth.props;
try {
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: `${baseUrl}/api/public/apps/track`,
headers: {
Authorization: apiKey,
},
body: {
type: 'track',
messageId: `track-${userId}-${event}-${Date.now()}`,
userId,
event,
properties,
},
});
return response.body;
} catch (error: any) {
if (error.response?.status === 401) {
throw new Error('Authentication failed. Please check your API key.');
} else if (error.response?.status === 404) {
throw new Error(`Dittofeed API endpoint not found. Please check your base URL: ${baseUrl}`);
} else if (error.response?.status === 429) {
throw new Error('Rate limit exceeded. Please try again later.');
} else if (error.response?.status >= 500) {
throw new Error(`Dittofeed server error: ${error.response?.body?.message || error.message}`);
}
throw new Error(`Failed to track event in Dittofeed: ${error.message || 'Unknown error'}`);
}
},
});