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 @@
import { actualBudgetAuth } from '../..';
import { createAction } from '@activepieces/pieces-framework';
import * as api from '@actual-app/api';
import { initializeAndDownloadBudget } from '../common/common';
export const getAccounts = createAction({
auth: actualBudgetAuth,
name: 'get_accounts',
displayName: 'Get Accounts',
description: 'Get your accounts',
props: {},
async run(context) {
await initializeAndDownloadBudget(api, context.auth.props)
const accounts = await api.getAccounts();
await api.shutdown();
return accounts;
},
});

View File

@@ -0,0 +1,36 @@
import { actualBudgetAuth } from '../..';
import { Property, createAction } from '@activepieces/pieces-framework';
import * as api from '@actual-app/api';
import { getMonths, getYears, initializeAndDownloadBudget } from '../common/common';
export const getBudget = createAction({
auth: actualBudgetAuth,
name: 'get_budget',
displayName: 'Get Budget',
description: 'Get your monthly budget',
props: {
month: Property.StaticDropdown({
displayName: 'Month',
description: 'The month of the budget you want to get',
required: true,
options: {
options: getMonths()
}
}),
year: Property.StaticDropdown({
displayName: 'Year',
description: 'The year of the budget you want to get',
required: true,
options: {
options: getYears()
}
})
},
async run(context) {
await initializeAndDownloadBudget(api, context.auth.props)
const budget = await api.getBudgetMonth(`${context.propsValue.year}-${context.propsValue.month}`);
await api.shutdown();
return budget;
},
});

View File

@@ -0,0 +1,19 @@
import { actualBudgetAuth } from '../..';
import { createAction } from '@activepieces/pieces-framework';
import * as api from '@actual-app/api';
import { initializeAndDownloadBudget } from '../common/common';
export const getCategories = createAction({
auth: actualBudgetAuth,
name: 'get_categories',
displayName: 'Get Categories',
description: 'Get your categories',
props: {},
async run(context) {
await initializeAndDownloadBudget(api, context.auth.props)
const categories = await api.getCategories();
await api.shutdown();
return categories;
},
});

View File

@@ -0,0 +1,90 @@
import { actualBudgetAuth } from '../..';
import {
Property,
createAction,
} from '@activepieces/pieces-framework';
import { Transaction } from '../common/models';
import * as api from '@actual-app/api';
import { initializeAndDownloadBudget } from '../common/common';
export const importTransaction = createAction({
auth: actualBudgetAuth,
name: 'import_transaction',
displayName: 'Import Transaction',
description: 'Add a transaction',
props: {
account_id: Property.ShortText({
displayName: 'Account ID',
description: 'ID of the account you want to import a transaction to',
required: true,
}),
date: Property.DateTime({
displayName: 'Date',
description: 'Date the transaction took place',
required: true,
}),
payee_name: Property.ShortText({
displayName: 'Payee Name',
description: 'Name of the payee',
required: false,
}),
amount: Property.Number({
displayName: 'Amount',
description: 'The dollar value of the transaction',
required: false,
}),
category: Property.ShortText({
displayName: 'Category ID',
description: 'ID of the transaction category',
required: false,
}),
notes: Property.LongText({
displayName: 'Notes',
description: 'Additional notes about the transaction',
required: false,
}),
imported_id: Property.ShortText({
displayName: 'Imported ID',
description: 'Unique ID given by the bank for importing',
required: false,
}),
transfer_id: Property.ShortText({
displayName: 'Transfer ID',
description: 'ID of the transaction in the other account for the transfer',
required: false,
}),
cleared: Property.Checkbox({
displayName: 'Cleared',
description: 'Flag indicating if the transaction has cleared or not',
required: false,
}),
imported_payee: Property.ShortText({
displayName: 'Imported Payee',
description: 'Raw description when importing, representing the original value',
required: false,
}),
},
async run({ auth, propsValue: { account_id, payee_name, date, amount, category, notes, imported_id, transfer_id, cleared, imported_payee } }) {
const formattedDate = new Date(date).toISOString().split('T')[0];
const transaction: Transaction = {
payee_name,
date: formattedDate,
amount: amount !== undefined ? api.utils.amountToInteger(amount): undefined,
category,
account: account_id,
notes,
imported_id,
transfer_id,
cleared,
imported_payee,
};
await initializeAndDownloadBudget(api, auth.props)
const res = await api.importTransactions(account_id,[transaction]);
await api.shutdown();
return res;
},
});

View File

@@ -0,0 +1,31 @@
import { actualBudgetAuth } from '../..';
import { Property, createAction } from '@activepieces/pieces-framework';
import * as api from '@actual-app/api';
import { initializeAndDownloadBudget } from '../common/common';
export const importTransactions = createAction({
auth: actualBudgetAuth,
name: 'import_transactions',
displayName: 'Import Transactions',
description: 'Import Transactions',
props: {
account_id: Property.ShortText({
displayName: 'Account ID',
description: 'ID of the account you want to import a transaction to',
required: true,
}),
transactions: Property.Json({
displayName: 'Transactions',
description: 'A json array of the transaction object',
required: true,
defaultValue: [{"payee_name": "Kroger", "date": "2026-12-25", "amount": 1200 }]
})
},
async run({ auth, propsValue: { account_id, transactions } }) {
await initializeAndDownloadBudget(api, auth.props)
const res = await api.importTransactions(account_id, transactions);
await api.shutdown();
return res;
},
});

View File

@@ -0,0 +1,80 @@
import { DropdownOption } from '@activepieces/pieces-framework';
import os from 'os';
export async function initializeAndDownloadBudget(api: any, auth: any): Promise<void> {
await api.init({
// Budget data will be cached locally here, in subdirectories for each file.
dataDir: os.tmpdir(),
serverURL: auth.server_url,
password: auth.password,
});
await api.downloadBudget(auth.sync_id, { password: auth.encryption_password ?? undefined });
}
export function getYears(): DropdownOption<string>[] {
const dropDownOptions: DropdownOption<string>[] = [];
const currentDate = new Date();
const currentYear = currentDate.getFullYear();
const startYear = currentYear-10;
for (let year = startYear; year <= currentYear + 5; year++) {
dropDownOptions.push({ label: year.toString(), value: year.toString() });
}
return dropDownOptions;
}
export function getMonths(): DropdownOption<string>[] {
return [
{
label: 'January',
value: '01'
},
{
label: 'February',
value: '02'
},
{
label: 'March',
value: '03'
},
{
label: 'April',
value: '04'
},
{
label: 'May',
value: '05'
},
{
label: 'June',
value: '06'
},
{
label: 'July',
value: '07'
},
{
label: 'August',
value: '08'
},
{
label: 'September',
value: '09'
},
{
label: 'October',
value: '10'
},
{
label: 'November',
value: '11'
},
{
label: 'December',
value: '12'
}
]
}

View File

@@ -0,0 +1,15 @@
export interface Transaction {
id?: string;
account?: string;
date: string;
amount?: number;
payee?: string;
payee_name?: string; // Only available in a create request
imported_payee?: string;
category?: string;
notes?: string;
imported_id?: string;
transfer_id?: string;
cleared?: boolean;
}