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:
@@ -0,0 +1,62 @@
|
||||
import { createAction, DynamicPropsValue, Property } from '@activepieces/pieces-framework';
|
||||
|
||||
import { webflowAuth } from '../..';
|
||||
import { webflowProps } from '../common/props';
|
||||
import { WebflowApiClient } from '../common/client';
|
||||
|
||||
export const webflowCreateCollectionItemAction = createAction({
|
||||
auth: webflowAuth,
|
||||
name: 'create_collection_item',
|
||||
displayName: 'Create Collection Item',
|
||||
description: 'Creates new collection item.',
|
||||
props: {
|
||||
site_id: webflowProps.site_id,
|
||||
collection_id: webflowProps.collection_id,
|
||||
collection_fields: webflowProps.collection_fields,
|
||||
is_archived: Property.Checkbox({
|
||||
displayName: 'Is Archived',
|
||||
description: 'Whether the item is archived or not',
|
||||
required: false,
|
||||
}),
|
||||
is_draft: Property.Checkbox({
|
||||
displayName: 'Is Draft',
|
||||
description: 'Whether the item is a draft or not',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const collectionId = context.propsValue.collection_id;
|
||||
const isArchived = context.propsValue.is_archived;
|
||||
const isDraft = context.propsValue.is_draft;
|
||||
const collectionInputFields = context.propsValue.collection_fields;
|
||||
|
||||
const client = new WebflowApiClient(context.auth.access_token);
|
||||
const { fields: CollectionFields } = await client.getCollection(collectionId);
|
||||
|
||||
const formattedCollectionFields: DynamicPropsValue = {};
|
||||
for (const field of CollectionFields) {
|
||||
const fieldValue = collectionInputFields[field.slug];
|
||||
|
||||
if (fieldValue !== undefined && fieldValue !== '') {
|
||||
switch (field.type) {
|
||||
case 'ImageRef':
|
||||
case 'FileRef':
|
||||
formattedCollectionFields[field.slug] = { url: fieldValue };
|
||||
break;
|
||||
case 'Set':
|
||||
formattedCollectionFields[field.slug] = fieldValue.map((url: string) => ({ url: url }));
|
||||
break;
|
||||
case 'Number':
|
||||
formattedCollectionFields[field.slug] = Number(fieldValue);
|
||||
break;
|
||||
default:
|
||||
formattedCollectionFields[field.slug] = fieldValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return await client.createCollectionItem(collectionId, {
|
||||
fields: { ...formattedCollectionFields, _archived: isArchived, _draft: isDraft },
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
|
||||
import { webflowAuth } from '../..';
|
||||
import { webflowProps } from '../common/props';
|
||||
import { WebflowApiClient } from '../common/client';
|
||||
|
||||
export const webflowDeleteCollectionItem = createAction({
|
||||
auth: webflowAuth,
|
||||
name: 'delete_collection_item',
|
||||
description: 'Delete collection item',
|
||||
displayName: 'Delete an item in a collection',
|
||||
props: {
|
||||
site_id: webflowProps.site_id,
|
||||
collection_id: webflowProps.collection_id,
|
||||
collection_item_id: webflowProps.collection_item_id,
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
const collectionId = context.propsValue.collection_id;
|
||||
const collectionItemId = context.propsValue.collection_item_id;
|
||||
|
||||
const client = new WebflowApiClient(context.auth.access_token);
|
||||
|
||||
return await client.deleteCollectionItem(collectionId, collectionItemId);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,70 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import {
|
||||
HttpRequest,
|
||||
HttpMethod,
|
||||
httpClient,
|
||||
AuthenticationType,
|
||||
} from '@activepieces/pieces-common';
|
||||
import { webflowAuth } from '../..';
|
||||
import { webflowProps } from '../common/props';
|
||||
|
||||
export const webflowFindCollectionItem = createAction({
|
||||
auth: webflowAuth,
|
||||
name: 'find_collection_item',
|
||||
description: 'Find collection item in a collection by field',
|
||||
displayName: 'Find a Collection Item by Field',
|
||||
props: {
|
||||
site_id: webflowProps.site_id,
|
||||
collection_id: webflowProps.collection_id,
|
||||
field_name: Property.ShortText({
|
||||
displayName: 'Field Name',
|
||||
description: 'The name of the field to search by',
|
||||
required: true,
|
||||
}),
|
||||
field_value: Property.ShortText({
|
||||
displayName: 'Field Value',
|
||||
description: 'The value of the field to search for',
|
||||
required: true,
|
||||
}),
|
||||
max_results: Property.Number({
|
||||
displayName: 'Max Results',
|
||||
description: 'The maximum number of results to return',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
|
||||
async run(configValue) {
|
||||
const accessToken = configValue.auth['access_token'];
|
||||
const collectionId = configValue.propsValue['collection_id'];
|
||||
const fieldName = configValue.propsValue['field_name'];
|
||||
const fieldValue = configValue.propsValue['field_value'];
|
||||
const maxResults = configValue.propsValue['max_results'];
|
||||
|
||||
const request: HttpRequest = {
|
||||
method: HttpMethod.GET,
|
||||
url: `https://api.webflow.com/collections/${collectionId}/items`,
|
||||
authentication: {
|
||||
type: AuthenticationType.BEARER_TOKEN,
|
||||
token: accessToken,
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await httpClient.sendRequest(request);
|
||||
if (res.status !== 200) {
|
||||
throw new Error('Failed to fetch collection items');
|
||||
}
|
||||
|
||||
const items = res.body.items;
|
||||
const matches = items
|
||||
.filter((item: any) => {
|
||||
return item.fields[fieldName] === fieldValue;
|
||||
})
|
||||
.slice(0, maxResults);
|
||||
|
||||
return { success: true, result: matches };
|
||||
} catch (err) {
|
||||
return { success: false, message: err };
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
|
||||
import { webflowAuth } from '../..';
|
||||
import { webflowProps } from '../common/props';
|
||||
import { WebflowApiClient } from '../common/client';
|
||||
|
||||
export const webflowFindOrder = createAction({
|
||||
auth: webflowAuth,
|
||||
name: 'find_order',
|
||||
description: 'Find order',
|
||||
displayName: 'Find an order',
|
||||
props: {
|
||||
site_id: webflowProps.site_id,
|
||||
order_id: webflowProps.order_id,
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
const orderId = context.propsValue.order_id;
|
||||
const siteId = context.propsValue.site_id;
|
||||
|
||||
const client = new WebflowApiClient(context.auth.access_token);
|
||||
|
||||
return await client.getOrder(siteId, orderId);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
|
||||
import { webflowAuth } from '../..';
|
||||
import { webflowProps } from '../common/props';
|
||||
import { WebflowApiClient } from '../common/client';
|
||||
|
||||
export const webflowFulfillOrder = createAction({
|
||||
auth: webflowAuth,
|
||||
name: 'fulfill_order',
|
||||
description: 'Fulfill order',
|
||||
displayName: 'Fulfill an order',
|
||||
props: {
|
||||
site_id: webflowProps.site_id,
|
||||
order_id: webflowProps.order_id,
|
||||
send_order_fulfilled_email: Property.Checkbox({
|
||||
displayName: 'Send Order Fulfilled Email',
|
||||
description: 'Send an email to the customer that their order has been fulfilled',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
const orderId = context.propsValue.order_id;
|
||||
const siteId = context.propsValue.site_id;
|
||||
const sendOrderFulfilledEmail = context.propsValue.send_order_fulfilled_email;
|
||||
|
||||
const client = new WebflowApiClient(context.auth.access_token);
|
||||
|
||||
return await client.fulfillOrder(siteId, orderId, { sendOrderFulfilledEmail });
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
|
||||
import { webflowAuth } from '../..';
|
||||
import { webflowProps } from '../common/props';
|
||||
import { WebflowApiClient } from '../common/client';
|
||||
|
||||
export const webflowGetCollectionItem = createAction({
|
||||
auth: webflowAuth,
|
||||
name: 'get_collection_item',
|
||||
description: 'Get collection item in a collection by ID',
|
||||
displayName: 'Get a Collection Item by ID',
|
||||
props: {
|
||||
site_id: webflowProps.site_id,
|
||||
collection_id: webflowProps.collection_id,
|
||||
collection_item_id: webflowProps.collection_item_id,
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
const collectionId = context.propsValue.collection_id;
|
||||
const collectionItemId = context.propsValue.collection_item_id;
|
||||
|
||||
const client = new WebflowApiClient(context.auth.access_token);
|
||||
|
||||
return await client.getCollectionItem(collectionId, collectionItemId);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
|
||||
import { webflowAuth } from '../..';
|
||||
import { webflowProps } from '../common/props';
|
||||
import { WebflowApiClient } from '../common/client';
|
||||
|
||||
export const webflowPublishCollectionItem = createAction({
|
||||
auth: webflowAuth,
|
||||
name: 'publish_collection_item',
|
||||
description: 'Publish collection item',
|
||||
displayName: 'Publish a Collection Item',
|
||||
props: {
|
||||
site_id: webflowProps.site_id,
|
||||
collection_id: webflowProps.collection_id,
|
||||
collection_item_id: webflowProps.collection_item_id,
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
const collectionId = context.propsValue.collection_id;
|
||||
const collectionItemId = context.propsValue.collection_item_id;
|
||||
|
||||
const client = new WebflowApiClient(context.auth.access_token);
|
||||
|
||||
return await client.publishCollectionItem(collectionId, collectionItemId);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
|
||||
import { webflowAuth } from '../..';
|
||||
import { webflowProps } from '../common/props';
|
||||
import { WebflowApiClient } from '../common/client';
|
||||
|
||||
export const webflowRefundOrder = createAction({
|
||||
auth: webflowAuth,
|
||||
name: 'refund_order',
|
||||
description: 'Refund order',
|
||||
displayName: 'Refund an order',
|
||||
props: {
|
||||
site_id: webflowProps.site_id,
|
||||
order_id: webflowProps.order_id,
|
||||
// reason: Property.StaticDropdown({
|
||||
// displayName: 'Reason',
|
||||
// description: 'The reason for the refund',
|
||||
// required: false,
|
||||
// options: {
|
||||
// disabled: false,
|
||||
// options: [
|
||||
// {
|
||||
// label: 'Duplicate',
|
||||
// value: 'duplicate',
|
||||
// },
|
||||
// {
|
||||
// label: 'Fraudulent',
|
||||
// value: 'fraudulent',
|
||||
// },
|
||||
// {
|
||||
// label: 'Requested',
|
||||
// value: 'requested',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// }),
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
const orderId = context.propsValue.order_id;
|
||||
const siteId = context.propsValue.site_id;
|
||||
|
||||
const client = new WebflowApiClient(context.auth.access_token);
|
||||
|
||||
return await client.refundOrder(siteId, orderId);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
|
||||
import { webflowAuth } from '../..';
|
||||
import { webflowProps } from '../common/props';
|
||||
import { WebflowApiClient } from '../common/client';
|
||||
|
||||
export const webflowUnfulfillOrder = createAction({
|
||||
auth: webflowAuth,
|
||||
name: 'unfulfill_order',
|
||||
description: 'Unfulfill order',
|
||||
displayName: 'Unfulfill an order',
|
||||
props: {
|
||||
site_id: webflowProps.site_id,
|
||||
order_id: webflowProps.order_id,
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
const orderId = context.propsValue.order_id;
|
||||
const siteId = context.propsValue.site_id;
|
||||
|
||||
const client = new WebflowApiClient(context.auth.access_token);
|
||||
|
||||
return await client.unfulfillOrder(siteId, orderId);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,74 @@
|
||||
import { createAction, DynamicPropsValue, Property } from '@activepieces/pieces-framework';
|
||||
|
||||
import { webflowAuth } from '../..';
|
||||
import { webflowProps } from '../common/props';
|
||||
import { WebflowApiClient } from '../common/client';
|
||||
|
||||
export const webflowUpdateCollectionItem = createAction({
|
||||
auth: webflowAuth,
|
||||
name: 'update_collection_item',
|
||||
description: 'Update collection item',
|
||||
displayName: 'Update an item in a collection',
|
||||
props: {
|
||||
site_id: webflowProps.site_id,
|
||||
collection_id: webflowProps.collection_id,
|
||||
collection_item_id: webflowProps.collection_item_id,
|
||||
collection_fields: webflowProps.collection_fields,
|
||||
is_archived: Property.Checkbox({
|
||||
displayName: 'Is Archived',
|
||||
description: 'Whether the item is archived or not',
|
||||
required: false,
|
||||
}),
|
||||
is_draft: Property.Checkbox({
|
||||
displayName: 'Is Draft',
|
||||
description: 'Whether the item is a draft or not',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
const collectionId = context.propsValue.collection_id;
|
||||
const collectionItemId = context.propsValue.collection_item_id;
|
||||
const isArchived = context.propsValue.is_archived;
|
||||
const isDraft = context.propsValue.is_draft;
|
||||
const collectionInputFields = context.propsValue.collection_fields;
|
||||
|
||||
const client = new WebflowApiClient(context.auth.access_token);
|
||||
const { fields: CollectionFields } = await client.getCollection(collectionId);
|
||||
|
||||
const formattedCollectionFields: DynamicPropsValue = {};
|
||||
for (const field of CollectionFields) {
|
||||
const fieldValue = collectionInputFields[field.slug];
|
||||
|
||||
if (fieldValue !== undefined && fieldValue !== '') {
|
||||
switch (field.type) {
|
||||
case 'ImageRef':
|
||||
case 'FileRef':
|
||||
formattedCollectionFields[field.slug] = { url: fieldValue };
|
||||
break;
|
||||
case 'Set':
|
||||
if (fieldValue.length > 0) {
|
||||
formattedCollectionFields[field.slug] = fieldValue.map((url: string) => ({
|
||||
url: url,
|
||||
}));
|
||||
}
|
||||
break;
|
||||
case 'ItemRefSet':
|
||||
if (fieldValue.length > 0) {
|
||||
formattedCollectionFields[field.slug] = fieldValue;
|
||||
}
|
||||
break;
|
||||
case 'Number':
|
||||
formattedCollectionFields[field.slug] = Number(fieldValue);
|
||||
break;
|
||||
default:
|
||||
formattedCollectionFields[field.slug] = fieldValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return await client.updateCollectionItem(collectionId, collectionItemId, {
|
||||
fields: { ...formattedCollectionFields, _archived: isArchived, _draft: isDraft },
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,148 @@
|
||||
import {
|
||||
AuthenticationType,
|
||||
httpClient,
|
||||
HttpMethod,
|
||||
HttpRequest,
|
||||
QueryParams,
|
||||
} from '@activepieces/pieces-common';
|
||||
|
||||
export class WebflowApiClient {
|
||||
constructor(private accessToken: string) {}
|
||||
|
||||
async makeRequest(
|
||||
method: HttpMethod,
|
||||
resourceUri: string,
|
||||
query?: Record<string, string | number | string[] | undefined>,
|
||||
body: any | undefined = undefined,
|
||||
): Promise<any> {
|
||||
const apiUrl = 'https://api.webflow.com';
|
||||
const params: QueryParams = {};
|
||||
|
||||
if (query) {
|
||||
for (const [key, value] of Object.entries(query)) {
|
||||
if (value !== null && value !== undefined) {
|
||||
params[key] = String(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const request: HttpRequest = {
|
||||
method: method,
|
||||
url: apiUrl + resourceUri,
|
||||
authentication: {
|
||||
type: AuthenticationType.BEARER_TOKEN,
|
||||
token: this.accessToken,
|
||||
},
|
||||
queryParams: params,
|
||||
body: body,
|
||||
};
|
||||
|
||||
const response = await httpClient.sendRequest(request);
|
||||
return response.body;
|
||||
}
|
||||
|
||||
async listSites() {
|
||||
return await this.makeRequest(HttpMethod.GET, '/sites');
|
||||
}
|
||||
|
||||
async listCollections(siteId: string) {
|
||||
return await this.makeRequest(HttpMethod.GET, `/sites/${siteId}/collections`);
|
||||
}
|
||||
|
||||
async getCollection(collectionId: string) {
|
||||
return await this.makeRequest(HttpMethod.GET, `/collections/${collectionId}`);
|
||||
}
|
||||
|
||||
async createCollectionItem(collectionId: string, request: Record<string, any>) {
|
||||
return await this.makeRequest(
|
||||
HttpMethod.POST,
|
||||
`/collections/${collectionId}/items`,
|
||||
undefined,
|
||||
request,
|
||||
);
|
||||
}
|
||||
|
||||
async updateCollectionItem(collectionId: string, itemId: string, request: Record<string, any>) {
|
||||
return await this.makeRequest(
|
||||
HttpMethod.PUT,
|
||||
`/collections/${collectionId}/items/${itemId}`,
|
||||
undefined,
|
||||
request,
|
||||
);
|
||||
}
|
||||
|
||||
async getCollectionItem(collectionId: string, itemId: string) {
|
||||
return await this.makeRequest(HttpMethod.GET, `/collections/${collectionId}/items/${itemId}`);
|
||||
}
|
||||
|
||||
async deleteCollectionItem(collectionId: string, itemId: string) {
|
||||
return await this.makeRequest(
|
||||
HttpMethod.DELETE,
|
||||
`/collections/${collectionId}/items/${itemId}`,
|
||||
);
|
||||
}
|
||||
|
||||
async publishCollectionItem(collectionId: string, itemId: string) {
|
||||
return await this.makeRequest(
|
||||
HttpMethod.POST,
|
||||
`/collections/${collectionId}/items/publish`,
|
||||
undefined,
|
||||
{ itemIds: [itemId] },
|
||||
);
|
||||
}
|
||||
|
||||
async listCollectionItems(collectionId: string, page: number, limit: number) {
|
||||
return await this.makeRequest(HttpMethod.GET, `/collections/${collectionId}/items`, {
|
||||
offset: page,
|
||||
limit,
|
||||
});
|
||||
}
|
||||
|
||||
async getOrder(siteId: string, orderId: string) {
|
||||
return await this.makeRequest(HttpMethod.GET, `/sites/${siteId}/orders/${orderId}`);
|
||||
}
|
||||
|
||||
async fulfillOrder(siteId: string, orderId: string, request: Record<string, any>) {
|
||||
return await this.makeRequest(
|
||||
HttpMethod.POST,
|
||||
`/sites/${siteId}/orders/${orderId}/fulfill`,
|
||||
undefined,
|
||||
request,
|
||||
);
|
||||
}
|
||||
|
||||
async unfulfillOrder(siteId: string, orderId: string) {
|
||||
return await this.makeRequest(
|
||||
HttpMethod.POST,
|
||||
`/sites/${siteId}/orders/${orderId}/unfulfill`,
|
||||
undefined,
|
||||
);
|
||||
}
|
||||
|
||||
async refundOrder(siteId: string, orderId: string) {
|
||||
return await this.makeRequest(HttpMethod.POST, `/sites/${siteId}/orders/${orderId}/refund`);
|
||||
}
|
||||
|
||||
async listOrders(siteId: string, page: number, limit: number) {
|
||||
return await this.makeRequest(HttpMethod.GET, `/sites/${siteId}/orders`, {
|
||||
offset: page,
|
||||
limit,
|
||||
});
|
||||
}
|
||||
|
||||
async createWebhook(siteId: string, triggerType: string, webhookUrl: string) {
|
||||
return await this.makeRequest(
|
||||
HttpMethod.POST,
|
||||
`'/sites/${siteId}/webhooks`,
|
||||
{},
|
||||
{
|
||||
triggerType,
|
||||
url: webhookUrl,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
async deleteWebhook(webhookId: string) {
|
||||
return await this.makeRequest(HttpMethod.DELETE, `/webhooks/${webhookId}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { Property, OAuth2PropertyValue, DynamicPropsValue } from '@activepieces/pieces-framework';
|
||||
import {
|
||||
HttpRequest,
|
||||
HttpMethod,
|
||||
AuthenticationType,
|
||||
httpClient,
|
||||
} from '@activepieces/pieces-common';
|
||||
|
||||
export const webflowCommon = {
|
||||
baseUrl: 'https://api.webflow.com/',
|
||||
subscribeWebhook: async (
|
||||
siteId: string,
|
||||
tag: string,
|
||||
webhookUrl: string,
|
||||
accessToken: string,
|
||||
) => {
|
||||
const request: HttpRequest = {
|
||||
method: HttpMethod.POST,
|
||||
url: `https://api.webflow.com/sites/${siteId}/webhooks`,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: {
|
||||
triggerType: tag,
|
||||
url: webhookUrl,
|
||||
},
|
||||
authentication: {
|
||||
type: AuthenticationType.BEARER_TOKEN,
|
||||
token: accessToken,
|
||||
},
|
||||
queryParams: {},
|
||||
};
|
||||
|
||||
const res = await httpClient.sendRequest(request);
|
||||
return res;
|
||||
},
|
||||
unsubscribeWebhook: async (siteId: string, webhookId: string, accessToken: string) => {
|
||||
const request: HttpRequest = {
|
||||
method: HttpMethod.DELETE,
|
||||
url: `https://api.webflow.com/sites/${siteId}/webhooks/${webhookId}`,
|
||||
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
authentication: {
|
||||
type: AuthenticationType.BEARER_TOKEN,
|
||||
token: accessToken,
|
||||
},
|
||||
};
|
||||
return await httpClient.sendRequest(request);
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,237 @@
|
||||
import {
|
||||
DropdownOption,
|
||||
DynamicPropsValue,
|
||||
PiecePropValueSchema,
|
||||
Property,
|
||||
} from '@activepieces/pieces-framework';
|
||||
|
||||
import { WebflowApiClient } from './client';
|
||||
import { webflowAuth } from '../..';
|
||||
|
||||
export const webflowProps = {
|
||||
site_id: Property.Dropdown({
|
||||
auth: webflowAuth,
|
||||
|
||||
displayName: 'Site',
|
||||
required: true,
|
||||
refreshers: [],
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect account first.',
|
||||
};
|
||||
}
|
||||
const authValue = auth;
|
||||
const client = new WebflowApiClient(authValue.access_token);
|
||||
|
||||
const sites = await client.listSites();
|
||||
|
||||
const options: DropdownOption<string>[] = [];
|
||||
for (const site of sites) {
|
||||
options.push({ label: site.name, value: site._id });
|
||||
}
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options,
|
||||
};
|
||||
},
|
||||
}),
|
||||
collection_id: Property.Dropdown({
|
||||
auth: webflowAuth,
|
||||
|
||||
displayName: 'Collection',
|
||||
required: true,
|
||||
refreshers: ['site_id'],
|
||||
options: async ({ auth, site_id }) => {
|
||||
if (!auth || !site_id) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect account first.',
|
||||
};
|
||||
}
|
||||
const authValue = auth as PiecePropValueSchema<typeof webflowAuth>;
|
||||
const client = new WebflowApiClient(authValue.access_token);
|
||||
|
||||
const collections = await client.listCollections(site_id as string);
|
||||
|
||||
const options: DropdownOption<string>[] = [];
|
||||
for (const collection of collections) {
|
||||
options.push({ label: collection.name, value: collection._id });
|
||||
}
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options,
|
||||
};
|
||||
},
|
||||
}),
|
||||
collection_fields: Property.DynamicProperties({
|
||||
auth: webflowAuth,
|
||||
displayName: 'Collection Fields',
|
||||
required: true,
|
||||
refreshers: ['collection_id'],
|
||||
props: async ({ auth, collection_id }) => {
|
||||
if (!auth) return {};
|
||||
if (!collection_id) return {};
|
||||
|
||||
const collectionFields: DynamicPropsValue = {};
|
||||
const authValue = auth as PiecePropValueSchema<typeof webflowAuth>;
|
||||
const client = new WebflowApiClient(authValue.access_token);
|
||||
|
||||
const { fields } = await client.getCollection(collection_id as unknown as string);
|
||||
|
||||
for (const field of fields) {
|
||||
if (field.editable && field.slug !== '_archived' && field.slug !== '_draft') {
|
||||
switch (field.type) {
|
||||
case 'Option':
|
||||
collectionFields[field.slug] = Property.StaticDropdown({
|
||||
displayName: field.name,
|
||||
required: field.required,
|
||||
options: {
|
||||
disabled: false,
|
||||
options: field.validations.options.map((option: { name: string }) => {
|
||||
return {
|
||||
label: option.name,
|
||||
value: option.name,
|
||||
};
|
||||
}),
|
||||
},
|
||||
});
|
||||
break;
|
||||
case 'RichText':
|
||||
case 'Email':
|
||||
case 'PlainText':
|
||||
case 'Phone':
|
||||
case 'Link':
|
||||
case 'Video':
|
||||
case 'Color':
|
||||
case 'ItemRef':
|
||||
case 'FileRef':
|
||||
collectionFields[field.slug] = Property.ShortText({
|
||||
displayName: field.name,
|
||||
required: field.required,
|
||||
});
|
||||
break;
|
||||
case 'ImageRef':
|
||||
collectionFields[field.slug] = Property.ShortText({
|
||||
displayName: field.name,
|
||||
required: field.required,
|
||||
description:
|
||||
'Images must be hosted on a publicly accessible URL to be uploaded via the API.The maximum file size for images is 4MB.',
|
||||
});
|
||||
break;
|
||||
case 'Set':
|
||||
collectionFields[field.slug] = Property.Array({
|
||||
displayName: field.name,
|
||||
required: field.required,
|
||||
description:
|
||||
' Images must be hosted on a publicly accessible URL to be uploaded via the API.The maximum file size for images is 4MB.',
|
||||
});
|
||||
break;
|
||||
case 'ItemRefSet':
|
||||
collectionFields[field.slug] = Property.Array({
|
||||
displayName: field.name,
|
||||
required: field.required,
|
||||
});
|
||||
break;
|
||||
case 'Number':
|
||||
collectionFields[field.slug] = Property.Number({
|
||||
displayName: field.name,
|
||||
required: field.required,
|
||||
});
|
||||
break;
|
||||
case 'Date':
|
||||
collectionFields[field.slug] = Property.DateTime({
|
||||
displayName: field.name,
|
||||
required: field.required,
|
||||
});
|
||||
break;
|
||||
case 'Bool':
|
||||
collectionFields[field.slug] = Property.Checkbox({
|
||||
displayName: field.name,
|
||||
required: false,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return collectionFields;
|
||||
},
|
||||
}),
|
||||
collection_item_id: Property.Dropdown({
|
||||
auth: webflowAuth,
|
||||
|
||||
displayName: 'Collection Item',
|
||||
required: true,
|
||||
refreshers: ['collection_id'],
|
||||
options: async ({ auth, collection_id }) => {
|
||||
if (!auth || !collection_id) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect account first.',
|
||||
};
|
||||
}
|
||||
const authValue = auth as PiecePropValueSchema<typeof webflowAuth>;
|
||||
const client = new WebflowApiClient(authValue.access_token);
|
||||
|
||||
const options: DropdownOption<string>[] = [];
|
||||
|
||||
let page = 0;
|
||||
let response;
|
||||
do {
|
||||
response = await client.listCollectionItems(collection_id as string, page, 100);
|
||||
page += 100;
|
||||
|
||||
for (const item of response.items) {
|
||||
options.push({ label: item.name, value: item._id });
|
||||
}
|
||||
} while (response.items.length > 0);
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options,
|
||||
};
|
||||
},
|
||||
}),
|
||||
order_id: Property.Dropdown({
|
||||
auth: webflowAuth,
|
||||
|
||||
displayName: 'Order',
|
||||
required: true,
|
||||
refreshers: ['site_id'],
|
||||
options: async ({ auth, site_id }) => {
|
||||
if (!auth || !site_id) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect account first.',
|
||||
};
|
||||
}
|
||||
const authValue = auth as PiecePropValueSchema<typeof webflowAuth>;
|
||||
const client = new WebflowApiClient(authValue.access_token);
|
||||
|
||||
const options: DropdownOption<string>[] = [];
|
||||
|
||||
let page = 0;
|
||||
let response;
|
||||
do {
|
||||
response = await client.listOrders(site_id as string, page, 100);
|
||||
page += 100;
|
||||
|
||||
for (const order of response) {
|
||||
options.push({ label: order.orderId, value: order.orderId });
|
||||
}
|
||||
} while (response.length > 0);
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options,
|
||||
};
|
||||
},
|
||||
}),
|
||||
};
|
||||
@@ -0,0 +1,79 @@
|
||||
import { webflowCommon } from '../common/common';
|
||||
import { createTrigger, TriggerStrategy, Property } from '@activepieces/pieces-framework';
|
||||
import { getAccessTokenOrThrow } from '@activepieces/pieces-common';
|
||||
import { webflowAuth } from '../..';
|
||||
import { webflowProps } from '../common/props';
|
||||
|
||||
const triggerNameInStore = 'webflow_created_form_submissions_trigger';
|
||||
|
||||
export const webflowNewSubmission = createTrigger({
|
||||
auth: webflowAuth,
|
||||
|
||||
name: 'new_submission',
|
||||
displayName: 'New Submission',
|
||||
description: 'Triggers when Webflow Site receives a new submission',
|
||||
props: {
|
||||
site_id: webflowProps.site_id,
|
||||
formName: Property.ShortText({
|
||||
displayName: 'Form Name',
|
||||
required: false,
|
||||
description: 'Copy from the form settings, or from one of the responses',
|
||||
}),
|
||||
},
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
// TODO remove and force testing as the data can be custom.
|
||||
sampleData: {
|
||||
name: 'Sample Form',
|
||||
site: '62749158efef318abc8d5a0f',
|
||||
data: {
|
||||
field_one: 'mock valued',
|
||||
},
|
||||
d: '2022-09-14T12:35:16.117Z',
|
||||
_id: '6321ca84df3949bfc6752327',
|
||||
},
|
||||
async onEnable(context) {
|
||||
const formSubmissionTag = 'form_submission';
|
||||
|
||||
const res = await webflowCommon.subscribeWebhook(
|
||||
context.propsValue['site_id']!,
|
||||
formSubmissionTag,
|
||||
context.webhookUrl,
|
||||
getAccessTokenOrThrow(context.auth),
|
||||
);
|
||||
await context.store?.put<WebhookInformation>(triggerNameInStore, {
|
||||
webhookId: res.body._id,
|
||||
});
|
||||
},
|
||||
async onDisable(context) {
|
||||
const response = await context.store?.get<WebhookInformation>(triggerNameInStore);
|
||||
if (response !== null && response !== undefined) {
|
||||
await webflowCommon.unsubscribeWebhook(
|
||||
context.propsValue['site_id']!,
|
||||
response.webhookId,
|
||||
getAccessTokenOrThrow(context.auth),
|
||||
);
|
||||
}
|
||||
},
|
||||
async run(context) {
|
||||
const body = context.payload.body as PayloadBody;
|
||||
const { formName } = context.propsValue;
|
||||
//if formName provided, trigger only required formName if it's matched; else trigger all forms in selected webflow site.
|
||||
if (formName) {
|
||||
if (body.name == formName) {
|
||||
return [body];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
} else {
|
||||
return [body];
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
interface WebhookInformation {
|
||||
webhookId: string;
|
||||
}
|
||||
|
||||
type PayloadBody = {
|
||||
name: string;
|
||||
};
|
||||
Reference in New Issue
Block a user