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,22 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { googleSearchConsoleAuth, createAuthClient } from '../../';
export const addSite = createAction({
auth: googleSearchConsoleAuth,
name: 'add_site',
displayName: 'Add a Site',
description: "Adds a site to the set of the user's sites in Search Console.",
props: {
siteUrl: Property.ShortText({
displayName: 'Site URL',
required: true,
}),
},
async run(context) {
const webmasters = createAuthClient(context.auth.access_token);
await webmasters.sites.add({
siteUrl: context.propsValue.siteUrl,
});
return { success: true };
},
});

View File

@@ -0,0 +1,30 @@
import { createAction } from '@activepieces/pieces-framework';
import { googleSearchConsoleAuth, createAuthClient } from '../../';
import { commonProps } from '../common';
export const deleteSite = createAction({
auth: googleSearchConsoleAuth,
name: 'delete_site',
displayName: 'Delete a Site',
description:
"Removes a site from the set of the user's Search Console sites.",
props: {
siteUrl: commonProps.siteUrl,
},
async run(context) {
const siteUrl = context.propsValue.siteUrl;
if (!siteUrl) {
throw new Error(
'You must provide either a Site URL or select one from the list.'
);
}
const webmasters = createAuthClient(context.auth.access_token);
await webmasters.sites.delete({
siteUrl: siteUrl,
});
return { success: true };
},
});

View File

@@ -0,0 +1,20 @@
import { createAction } from '@activepieces/pieces-framework';
import { googleSearchConsoleAuth, createAuthClient } from '../../';
import { commonProps } from '../common';
export const listSitemaps = createAction({
auth: googleSearchConsoleAuth,
name: 'list_sitemaps',
displayName: 'List Sitemaps',
description: 'List all your sitemaps for a given site',
props: {
siteUrl: commonProps.siteUrl,
},
async run(context) {
const webmasters = createAuthClient(context.auth.access_token);
const res = await webmasters.sitemaps.list({
siteUrl: context.propsValue.siteUrl,
});
return res.data;
},
});

View File

@@ -0,0 +1,15 @@
import { createAction } from '@activepieces/pieces-framework';
import { googleSearchConsoleAuth, createAuthClient } from '../../';
export const listSites = createAction({
auth: googleSearchConsoleAuth,
name: 'list_sites',
displayName: 'List Sites',
description: "Lists the user's Search Console sites.",
props: {},
async run(context) {
const webmasters = createAuthClient(context.auth.access_token);
const res = await webmasters.sites.list();
return res.data;
},
});

View File

@@ -0,0 +1,98 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { googleSearchConsoleAuth, createAuthClient } from '../../';
import { commonProps } from '../common';
import dayjs from 'dayjs';
export const searchAnalytics = createAction({
auth: googleSearchConsoleAuth,
name: 'search_analytics',
displayName: 'Search Analytics',
description:
'Query traffic data for your site using the Google Search Console API.',
props: {
siteUrl: commonProps.siteUrl,
startDate: Property.DateTime({
displayName: 'Start Date',
description:
'The start date of the date range to query (in YYYY-MM-DD format).',
required: true,
defaultValue: new Date().toISOString().split('T')[0],
}),
endDate: Property.DateTime({
displayName: 'End Date',
description:
'The end date of the date range to query (in YYYY-MM-DD format).',
required: true,
defaultValue: new Date().toISOString().split('T')[0],
}),
dimensions: Property.Array({
displayName: 'Dimensions',
description:
'The dimensions to group results by. For example: ["query", "page", "country", "device", "searchAppearance", "date"].',
required: false,
}),
filters: Property.Array({
displayName: 'Filters',
description:
'Optional filters to apply to the data. Filters can be used to restrict the results to a specific subset.',
properties: {
dimension: Property.ShortText({
displayName: 'Dimension',
description:
'The dimension to filter by (e.g., query, page, country, device).',
required: true,
}),
operator: Property.ShortText({
displayName: 'Operator',
description: 'The filter operator to apply (e.g., equals, contains).',
required: true,
}),
expression: Property.ShortText({
displayName: 'Expression',
description: 'The expression to compare the dimension against.',
required: true,
}),
},
required: false,
}),
aggregationType: Property.ShortText({
displayName: 'Aggregation Type',
description:
'How data is aggregated. Options include "auto", "byPage", "byProperty".',
required: false,
}),
rowLimit: Property.Number({
displayName: 'Row Limit',
description: 'The maximum number of rows to return.',
required: false,
}),
startRow: Property.Number({
displayName: 'Start Row',
description:
'The first row to return. Use this parameter to paginate results.',
required: false,
}),
},
async run(context) {
const webmasters = createAuthClient(context.auth.access_token);
const filters = context.propsValue.filters as any;
const res = await webmasters.searchanalytics.query({
siteUrl: context.propsValue.siteUrl,
requestBody: {
startDate: dayjs(context.propsValue.startDate).format('YYYY-MM-DD'),
endDate: dayjs(context.propsValue.endDate).format('YYYY-MM-DD'),
dimensions: context.propsValue.dimensions as string[],
dimensionFilterGroups: filters.map((filter: any) => ({
dimension: filter.dimension,
operator: filter.operator,
expression: filter.expression,
})),
aggregationType: context.propsValue.aggregationType,
rowLimit: context.propsValue.rowLimit,
startRow: context.propsValue.startRow,
},
});
return res;
},
});

View File

@@ -0,0 +1,25 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { googleSearchConsoleAuth, createAuthClient } from '../../';
import { commonProps } from '../common';
export const submitSitemap = createAction({
auth: googleSearchConsoleAuth,
name: 'submit_sitemap',
displayName: 'Submit a Sitemap',
description: 'Submits a sitemap for a site.',
props: {
siteUrl: commonProps.siteUrl,
feedpath: Property.ShortText({
displayName: 'Sitemap Path',
required: true,
}),
},
async run(context) {
const webmasters = createAuthClient(context.auth.access_token);
await webmasters.sitemaps.submit({
siteUrl: context.propsValue.siteUrl,
feedpath: context.propsValue.feedpath,
});
return { success: true };
},
});

View File

@@ -0,0 +1,43 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { googleSearchConsoleAuth } from '../../';
import {
AuthenticationType,
httpClient,
HttpMethod,
HttpRequest,
} from '@activepieces/pieces-common';
import { commonProps } from '../common';
export const urlInspection = createAction({
auth: googleSearchConsoleAuth,
name: 'urlInspection',
displayName: 'URL Inspection',
description:
"Use the URL Inspection action to check the status and presence of a specific page within Google's index.",
props: {
siteUrl: commonProps.siteUrl,
url: Property.ShortText({
displayName: 'URL to Inspect',
required: true,
}),
},
async run(context) {
const request: HttpRequest = {
method: HttpMethod.POST,
url: 'https://searchconsole.googleapis.com/v1/urlInspection/index:inspect',
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: context.auth.access_token,
},
headers: { 'Content-Type': 'application/json' },
body: {
inspectionUrl: context.propsValue.url,
siteUrl: context.propsValue.siteUrl,
},
};
const response = await httpClient.sendRequest(request);
return response.body;
},
});

View File

@@ -0,0 +1,32 @@
import { createAuthClient, googleSearchConsoleAuth } from '../../';
import { PiecePropValueSchema, Property } from '@activepieces/pieces-framework';
export const commonProps = {
siteUrl: Property.Dropdown({
auth: googleSearchConsoleAuth,
displayName: 'Site URL',
required: true,
refreshers: [],
refreshOnSearch: false,
options: async ({ auth }) => {
const authValue = auth
if (!authValue) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first',
};
}
const webmasters = createAuthClient(authValue.access_token);
const res = await webmasters.sites.list();
const sites = res.data.siteEntry || [];
return {
options: sites.map((site: any) => ({
label: site.siteUrl,
value: site.siteUrl,
})),
};
},
}),
};