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,65 @@
import {
AuthenticationType,
httpClient,
HttpMethod,
HttpRequest,
} from '@activepieces/pieces-common';
import { bexioCommon } from './index';
export class BexioClient {
constructor(private auth: {access_token: string}) {}
async makeRequest<T>(
method: HttpMethod,
endpoint: string,
data?: unknown,
queryParams?: Record<string, string>
): Promise<T> {
// If endpoint already includes version (starts with /2.0/ or /3.0/), use it directly
// Otherwise, prepend the default API version
const url = endpoint.startsWith('/2.0/') || endpoint.startsWith('/3.0/')
? `${bexioCommon.baseUrl}${endpoint}`
: `${bexioCommon.baseUrl}/${bexioCommon.api_version}${endpoint}`;
const request: HttpRequest = {
method,
url,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: this.auth.access_token,
},
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
};
if (data) {
request.body = data;
}
if (queryParams) {
request.queryParams = queryParams;
}
const response = await httpClient.sendRequest<T>(request);
return response.body;
}
async get<T>(endpoint: string, queryParams?: Record<string, string>): Promise<T> {
return this.makeRequest<T>(HttpMethod.GET, endpoint, undefined, queryParams);
}
async post<T>(endpoint: string, data: unknown, queryParams?: Record<string, string>): Promise<T> {
return this.makeRequest<T>(HttpMethod.POST, endpoint, data, queryParams);
}
async patch<T>(endpoint: string, data: unknown): Promise<T> {
return this.makeRequest<T>(HttpMethod.PATCH, endpoint, data);
}
async delete<T>(endpoint: string): Promise<T> {
return this.makeRequest<T>(HttpMethod.DELETE, endpoint);
}
}

View File

@@ -0,0 +1,5 @@
export const bexioCommon = {
baseUrl: 'https://api.bexio.com',
api_version: '3.0',
};

View File

@@ -0,0 +1,127 @@
import { Property, OAuth2PropertyValue } from '@activepieces/pieces-framework';
import { BexioClient } from './client';
import { BexioAccount, BexioTax, BexioCurrency } from './types';
import { bexioAuth } from '../..';
export const bexioCommonProps = {
account: (options: {
displayName: string;
description?: string;
required: boolean;
}) => {
return Property.Dropdown({
auth: bexioAuth,
displayName: options.displayName,
description: options.description,
required: options.required,
refreshers: [],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Connect your Bexio account first',
options: [],
};
}
try {
const client = new BexioClient(auth);
const accounts = await client.get<BexioAccount[]>('/accounts');
return {
disabled: false,
options: accounts.map((account) => ({
label: `${account.account_no} - ${account.name}`,
value: account.id,
})),
};
} catch (error) {
return {
disabled: true,
placeholder: 'Failed to load accounts',
options: [],
};
}
},
});
},
tax: Property.Dropdown({
auth: bexioAuth,
displayName: 'Tax',
description: 'Select a tax rate',
required: false,
refreshers: [],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Connect your Bexio account first',
options: [],
};
}
try {
const client = new BexioClient(auth);
const taxes = await client.get<BexioTax[]>('/taxes');
return {
disabled: false,
options: taxes.map((tax) => ({
label: `${tax.name} (${tax.percentage}%)`,
value: tax.id,
})),
};
} catch (error) {
return {
disabled: true,
placeholder: 'Failed to load taxes',
options: [],
};
}
},
}),
currency: (options: {
displayName: string;
description?: string;
required: boolean;
}) => {
return Property.Dropdown({
auth: bexioAuth,
displayName: options.displayName,
description: options.description,
required: options.required,
refreshers: [],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Connect your Bexio account first',
options: [],
};
}
try {
const client = new BexioClient(auth);
const currencies = await client.get<BexioCurrency[]>('/3.0/currencies');
return {
disabled: false,
options: currencies.map((currency) => ({
label: currency.name,
value: currency.id,
})),
};
} catch (error) {
return {
disabled: true,
placeholder: 'Failed to load currencies',
options: [],
};
}
},
});
},
};

View File

@@ -0,0 +1,99 @@
// Common types for Bexio API
export interface BexioContact {
id: number;
nr: string;
contact_type_id: number;
name_1: string;
name_2?: string;
salutation_id?: number;
salutation_form?: number;
title_id?: number;
birthday?: string;
address?: string;
postcode?: string;
city?: string;
country_id?: number;
mail?: string;
mail_second?: string;
phone_fixed?: string;
phone_fixed_second?: string;
phone_mobile?: string;
fax?: string;
url?: string;
skype_name?: string;
remarks?: string;
language_id?: number;
contact_group_ids?: string;
contact_branch_ids?: string;
user_id?: number;
owner_id?: number;
}
export interface BexioCompany {
id: number;
name: string;
address?: string;
address_nr?: string;
postcode?: string;
city?: string;
country_id?: number;
legal_form?: string;
}
export interface BexioAccount {
id: number;
account_no: string;
name: string;
account_type: number;
}
export interface BexioTax {
id: number;
name: string;
percentage: string;
}
export interface BexioCurrency {
id: number;
name: string;
}
export interface BexioManualEntry {
debit_account_id?: number;
credit_account_id?: number;
tax_id?: number;
tax_account_id?: number;
description?: string;
amount?: number;
currency_id?: number;
currency_factor?: number;
}
export interface BexioManualEntryResponse {
id: number;
type: 'manual_single_entry' | 'manual_compound_entry' | 'manual_group_entry';
date: string;
reference_nr?: string;
created_by_user_id?: number;
edited_by_user_id?: number;
entries: BexioManualEntry[];
is_locked?: boolean;
locked_info?: string;
}
export interface BexioError {
error_code: number;
message: string;
}
export interface BexioListResponse<T> {
data: T[];
paging?: {
page: number;
page_size: number;
page_count: number;
item_count: number;
};
}