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,50 @@
import { gristAuth } from '../..';
import { createAction } from '@activepieces/pieces-framework';
import { commonProps } from '../common/props';
import { GristAPIClient, transformTableColumnValues } from '../common/helpers';
export const gristCreateRecordAction = createAction({
auth: gristAuth,
name: 'grist-create-record',
displayName: 'Create Record',
description: 'Creates a new record in specific table.',
props: {
workspace_id: commonProps.workspace_id,
document_id: commonProps.document_id,
table_id: commonProps.table_id,
table_columns: commonProps.table_columns,
},
async run(context) {
const documentId = context.propsValue.document_id;
const tableId = context.propsValue.table_id;
const tableColumnValues = context.propsValue.table_columns;
const client = new GristAPIClient({
domainUrl: context.auth.props.domain,
apiKey: context.auth.props.apiKey,
});
const tableColumnSchema = await client.listTableColumns(
documentId as string,
tableId as string
);
const transformedColumnValues = transformTableColumnValues({
tableColumnSchema,
tableColumnValues,
});
const createRecordResponse = await client.addRecordsToTable(
documentId,
tableId,
{
records: [{ fields: transformedColumnValues }],
}
);
return {
id: createRecordResponse.records[0].id,
fields: transformedColumnValues,
};
},
});

View File

@@ -0,0 +1,87 @@
import { gristAuth } from '../..';
import {
createAction,
DropdownOption,
PiecePropValueSchema,
Property,
} from '@activepieces/pieces-framework';
import { commonProps } from '../common/props';
import { GristAPIClient } from '../common/helpers';
import { HttpMethod } from '@activepieces/pieces-common';
export const gristSearchRecordAction = createAction({
auth: gristAuth,
name: 'grist-search-record',
displayName: 'Search Record',
description: 'Search record by matching criteria.',
props: {
workspace_id: commonProps.workspace_id,
document_id: commonProps.document_id,
table_id: commonProps.table_id,
column: Property.Dropdown({
displayName: 'Column',
auth: gristAuth,
refreshers: ['document_id', 'table_id'],
required: true,
options: async ({ auth, document_id, table_id }) => {
if (!auth || !document_id || !table_id) {
return {
disabled: true,
placeholder: 'Please connect account and select document.',
options: [],
};
}
const authValue = auth.props;
const client = new GristAPIClient({
domainUrl: authValue.domain,
apiKey: authValue.apiKey,
});
const response = await client.listTableColumns(
document_id as string,
table_id as string
);
const options: DropdownOption<string>[] = [];
for (const column of response.columns) {
options.push({ value: column.id, label: column.fields.label });
}
return {
disabled: false,
options,
};
},
}),
value: Property.ShortText({
displayName: 'Value',
required: true,
description:
'Enter the search text. The search operation is case sensitive, exact text match, and supports column-type Text only.',
}),
},
async run(context) {
const documentId = context.propsValue.document_id;
const tableId = context.propsValue.table_id;
const columnName = context.propsValue.column;
const columnValue = context.propsValue.value;
const client = new GristAPIClient({
domainUrl: context.auth.props.domain,
apiKey: context.auth.props.apiKey,
});
const encodedQuery = encodeURIComponent(
JSON.stringify({
[columnName]: [columnValue],
})
);
return await client.makeRequest(
HttpMethod.GET,
`/docs/${documentId}/tables/${tableId}/records?filter=${encodedQuery}`
);
},
});

View File

@@ -0,0 +1,55 @@
import { gristAuth } from '../..';
import { createAction, Property } from '@activepieces/pieces-framework';
import { commonProps } from '../common/props';
import { GristAPIClient, transformTableColumnValues } from '../common/helpers';
export const gristUpdateRecordAction = createAction({
auth: gristAuth,
name: 'grist-update-record',
displayName: 'Update Record',
description: 'Updates an existing record in specific table.',
props: {
workspace_id: commonProps.workspace_id,
document_id: commonProps.document_id,
table_id: commonProps.table_id,
record_id: Property.Number({
displayName: 'Record ID',
required: true,
}),
table_columns: commonProps.table_columns,
},
async run(context) {
const documentId = context.propsValue.document_id;
const tableId = context.propsValue.table_id;
const recordId = context.propsValue.record_id;
const tableColumnValues = context.propsValue.table_columns;
const client = new GristAPIClient({
domainUrl: context.auth.props.domain,
apiKey: context.auth.props.apiKey,
});
const tableColumnSchema = await client.listTableColumns(
documentId as string,
tableId as string
);
const transformedColumnValues = transformTableColumnValues({
tableColumnSchema,
tableColumnValues,
});
const updateRecordResponse = await client.updateRcordsInTable(
documentId,
tableId,
{
records: [{ id: recordId, fields: transformedColumnValues }],
}
);
return {
id: recordId,
fields: transformedColumnValues,
};
},
});

View File

@@ -0,0 +1,70 @@
import { gristAuth } from '../..';
import { createAction, Property } from '@activepieces/pieces-framework';
import { commonProps } from '../common/props';
import FormData from 'form-data';
import {
AuthenticationType,
httpClient,
HttpMethod,
} from '@activepieces/pieces-common';
import { GristAPIClient } from '../common/helpers';
export const gristUploadAttachmentsToDocumnetAction = createAction({
auth: gristAuth,
name: 'grist-upload-attachments-to-document',
displayName: 'Upload Attachment to Document',
description: 'Uploads attachments to specific document.',
props: {
workspace_id: commonProps.workspace_id,
document_id: commonProps.document_id,
attachment: Property.File({
displayName: 'Attachment',
required: true,
}),
attachment_name: Property.ShortText({
displayName: 'Attachment Name',
description: 'In case you want to change the name of the attachment.',
required: false,
}),
},
async run(context) {
const documentId = context.propsValue.document_id;
const attachment = context.propsValue.attachment;
const attachmentName = context.propsValue.attachment_name;
const client = new GristAPIClient({
domainUrl: context.auth.props.domain,
apiKey: context.auth.props.apiKey,
});
const formData = new FormData();
formData.append(
'upload',
Buffer.from(attachment.base64, 'base64'),
attachmentName || attachment.filename
);
const response = await httpClient.sendRequest<Array<number>>({
method: HttpMethod.POST,
url: context.auth.props.domain + '/api' + `/docs/${documentId}/attachments`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: context.auth.props.apiKey,
},
headers: { ...formData.getHeaders() },
body: formData,
});
const attachmentId = response.body[0];
const attachmentMetadata = await client.getDocumentAttachmentMetadata(
documentId,
attachmentId
);
return {
id: attachmentId,
fields: attachmentMetadata,
};
},
});

View File

@@ -0,0 +1,219 @@
import { DynamicPropsValue } from '@activepieces/pieces-framework';
import {
GristAPIClientOptions,
GristCreateRecordsRequest,
GristCreateRecordsResponse,
GristCreateWebhookRequest,
GristCreateWebhookResponse,
GristListRecordsResponse,
GristOrgResponse,
GristTableColumnsResponse,
GristTableResponse,
GristUpdateRecordsRequest,
GristWorkspaceResponse,
} from './types';
import {
AuthenticationType,
httpClient,
HttpHeaders,
HttpMessageBody,
HttpMethod,
HttpRequest,
QueryParams,
} from '@activepieces/pieces-common';
type Query = Record<string, string | number | string[] | undefined>;
export class GristAPIClient {
#domaiUrl: string;
#apiKey: string;
constructor(options: GristAPIClientOptions) {
this.#domaiUrl = options.domainUrl;
this.#apiKey = options.apiKey;
}
async makeRequest<T extends HttpMessageBody>(
method: HttpMethod,
resourceUri: string,
headers?: HttpHeaders,
query?: Query,
body: any | undefined = undefined
): Promise<T> {
const baseUrl = this.#domaiUrl.replace(/\/$/, '');
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: baseUrl + '/api' + resourceUri,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: this.#apiKey,
},
headers,
queryParams: params,
body: body,
};
const response = await httpClient.sendRequest<T>(request);
return response.body;
}
async listOrgs() {
return await this.makeRequest<GristOrgResponse[]>(
HttpMethod.GET,
`/orgs`
);
}
async listWorkspaces(orgId: string) {
return await this.makeRequest<GristWorkspaceResponse[]>(
HttpMethod.GET,
`/orgs/${orgId}/workspaces`
);
}
async getWorkspace(workspaceId: number) {
return await this.makeRequest<GristWorkspaceResponse>(
HttpMethod.GET,
`/workspaces/${workspaceId}`
);
}
async listDocumentTables(docId: string) {
return await this.makeRequest<{ tables: GristTableResponse[] }>(
HttpMethod.GET,
`/docs/${docId}/tables`
);
}
async listTableColumns(docId: string, tableId: string) {
return await this.makeRequest<{ columns: GristTableColumnsResponse[] }>(
HttpMethod.GET,
`/docs/${docId}/tables/${tableId}/columns`
);
}
async addRecordsToTable(
docId: string,
tableId: string,
request: GristCreateRecordsRequest
) {
return await this.makeRequest<GristCreateRecordsResponse>(
HttpMethod.POST,
`/docs/${docId}/tables/${tableId}/records`,
undefined,
{},
request
);
}
async updateRcordsInTable(
docId: string,
tableId: string,
request: GristUpdateRecordsRequest
) {
return await this.makeRequest<GristCreateRecordsResponse>(
HttpMethod.PATCH,
`/docs/${docId}/tables/${tableId}/records`,
undefined,
{},
request
);
}
async listRecordsFromTable(docId: string, tableId: string, query: Query) {
return await this.makeRequest<GristListRecordsResponse>(
HttpMethod.GET,
`/docs/${docId}/tables/${tableId}/records`,
undefined,
query
);
}
async listDocumentAttachments(docId: string, query: Query) {
return await this.makeRequest<GristListRecordsResponse>(
HttpMethod.GET,
`/docs/${docId}/attachments`,
{},
query
);
}
async getDocumentAttachmentMetadata(docId: string, attachmentId: number) {
return await this.makeRequest<GristListRecordsResponse>(
HttpMethod.GET,
`/docs/${docId}/attachments/${attachmentId}`
);
}
async createDocumentWebhook(
docId: string,
request: GristCreateWebhookRequest
) {
return await this.makeRequest<GristCreateWebhookResponse>(
HttpMethod.POST,
`/docs/${docId}/webhooks`,
undefined,
{},
request
);
}
async deleteDocumentWebhook(docId: string, webhookId: number) {
return await this.makeRequest(
HttpMethod.DELETE,
`/docs/${docId}/webhooks/${webhookId}`
);
}
}
export function transformTableColumnValues({
tableColumnSchema,
tableColumnValues,
}: {
tableColumnSchema: { columns: GristTableColumnsResponse[] };
tableColumnValues: DynamicPropsValue;
}): DynamicPropsValue {
const fields: DynamicPropsValue = {};
for (const column of tableColumnSchema.columns) {
const columnId = column.id;
const columnType = column.fields.type;
const columnValue = tableColumnValues[columnId];
if (columnValue !== undefined && columnValue !== '') {
if (columnType === 'Attachments') {
const attachmentsArray = Array.isArray(columnValue)
? columnValue
: JSON.parse(columnValue);
if (Array.isArray(attachmentsArray) && attachmentsArray.length > 0) {
fields[columnId] = ['L', ...attachmentsArray.map(Number)];
}
} else if (columnType === 'ChoiceList') {
if (Array.isArray(columnValue) && columnValue.length > 0) {
fields[columnId] = ['L', ...columnValue];
}
} else if (columnType === 'Int' || columnType === 'Numeric') {
fields[columnId] = Number(columnValue);
} else if (columnType.startsWith('RefList')) {
const refListArray = Array.isArray(columnValue)
? columnValue
: JSON.parse(columnValue);
if (Array.isArray(refListArray) && refListArray.length > 0) {
fields[columnId] = ['L', ...refListArray.map(Number)];
}
} else if (columnType.startsWith('Ref')) {
fields[columnId] = Number(columnValue);
} else {
fields[columnId] = columnValue;
}
}
}
return fields;
}

View File

@@ -0,0 +1,284 @@
import {
DropdownOption,
DynamicPropsValue,
PiecePropValueSchema,
Property,
} from '@activepieces/pieces-framework';
import { gristAuth } from '../..';
import { GristAPIClient } from './helpers';
export const commonProps = {
workspace_id: Property.Dropdown({
displayName: 'Workspace',
refreshers: [],
required: true,
auth: gristAuth,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Please connect account first.',
options: [],
};
}
const authValue = auth.props;
const client = new GristAPIClient({
domainUrl: authValue.domain,
apiKey: authValue.apiKey,
});
const response = await client.listWorkspaces('current');
const options: DropdownOption<number>[] = [];
for (const workspace of response) {
options.push({ label: workspace.name, value: workspace.id });
}
return {
disabled: false,
options,
};
},
}),
document_id: Property.Dropdown({
displayName: 'Document',
refreshers: ['workspace_id'],
required: true,
auth: gristAuth,
options: async ({ auth, workspace_id }) => {
if (!auth || !workspace_id) {
return {
disabled: true,
placeholder: 'Please connect account and select workspace.',
options: [],
};
}
const authValue = auth.props;
const client = new GristAPIClient({
domainUrl: authValue.domain,
apiKey: authValue.apiKey,
});
const response = await client.getWorkspace(
workspace_id as unknown as number
);
const options: DropdownOption<string>[] = [];
for (const document of response.docs) {
options.push({ label: document.name, value: document.id });
}
return {
disabled: false,
options,
};
},
}),
table_id: Property.Dropdown({
displayName: 'Table',
refreshers: ['document_id'],
required: true,
auth: gristAuth,
options: async ({ auth, document_id }) => {
if (!auth || !document_id) {
return {
disabled: true,
placeholder: 'Please connect account and select document.',
options: [],
};
}
const authValue = auth.props;
const client = new GristAPIClient({
domainUrl: authValue.domain,
apiKey: authValue.apiKey,
});
const response = await client.listDocumentTables(
document_id as unknown as string
);
const options: DropdownOption<string>[] = [];
for (const table of response.tables) {
options.push({ label: table.id, value: table.id });
}
return {
disabled: false,
options,
};
},
}),
table_columns: Property.DynamicProperties({
displayName: 'Table Columns',
refreshers: ['document_id', 'table_id'],
required: true,
auth: gristAuth,
props: async ({ auth, document_id, table_id }) => {
if (!auth) return {};
if (!document_id) return {};
if (!table_id) return {};
const fields: DynamicPropsValue = {};
const authValue = auth.props;
const client = new GristAPIClient({
domainUrl: authValue.domain,
apiKey: authValue.apiKey,
});
const response = await client.listTableColumns(
document_id as unknown as string,
table_id as unknown as string
);
for (const column of response.columns) {
if (!column.fields.isFormula) {
switch (column.fields.type) {
case 'Any':
fields[column.id] = Property.ShortText({
displayName: column.fields.label || column.id,
required: false,
});
break;
case 'Attachments':
fields[column.id] = Property.Array({
displayName: column.fields.label || column.id,
description: `Use the **Upload Attachments to Document** action and provide the attachment ID from the response.`,
required: false,
});
break;
case 'Bool':
fields[column.id] = Property.Checkbox({
displayName: column.fields.label || column.id,
required: false,
});
break;
case 'Choice':
case 'ChoiceList': {
let options = [];
try {
const optionsObject = JSON.parse(column.fields.widgetOptions);
options = optionsObject['choices'] as any[];
} catch (error) {
options = [];
}
const dropdownConfig = {
displayName: column.fields.label || column.id,
required: false,
options: {
disabled: false,
options: options.map((choice) => {
return {
label: choice,
value: choice,
};
}),
},
};
fields[column.id] =
column.fields.type === 'Choice'
? Property.StaticDropdown(dropdownConfig)
: Property.StaticMultiSelectDropdown(dropdownConfig);
break;
}
case 'Date':
fields[column.id] = Property.DateTime({
displayName: column.fields.label || column.id,
required: false,
});
break;
case 'Int':
case 'Numeric':
fields[column.id] = Property.Number({
displayName: column.fields.label || column.id,
required: false,
});
break;
case 'Text':
fields[column.id] = Property.LongText({
displayName: column.fields.label || column.id,
required: false,
});
break;
default:
if (column.fields.type.startsWith('DateTime')) {
fields[column.id] = Property.DateTime({
displayName: column.fields.label || column.id,
required: false,
});
} else if (column.fields.type.startsWith('RefList')) {
const refTable = column.fields.type.split(':')[1];
fields[column.id] = Property.Array({
displayName: column.fields.label || column.id,
description: refTable
? `Please provide the row ID from the reference table ${refTable}.`
: '',
required: false,
});
} else if (column.fields.type.startsWith('Ref')) {
const refTable = column.fields.type.split(':')[1];
fields[column.id] = Property.Number({
displayName: column.fields.label || column.id,
description: refTable
? `Please provide the row ID from the reference table ${refTable}.`
: '',
required: false,
});
}
break;
}
}
}
return fields;
},
}),
readiness_column: Property.Dropdown({
displayName: 'Readiness Column',
description: `A toggle (boolean) column which is True when the record is ready. The trigger will only be activated when that record becomes ready.Please follow [guideline](https://support.getgrist.com/integrators/#readiness-column) to create readiness column in table.`,
refreshers: ['document_id', 'table_id'],
required: false,
auth: gristAuth,
options: async ({ auth, document_id, table_id }) => {
if (!auth || !document_id || !table_id) {
return {
disabled: true,
placeholder: 'Please connect account and select document.',
options: [],
};
}
const authValue = auth.props;
const client = new GristAPIClient({
domainUrl: authValue.domain,
apiKey: authValue.apiKey,
});
const response = await client.listTableColumns(
document_id as string,
table_id as string
);
const options: DropdownOption<string>[] = [];
for (const column of response.columns) {
if (column.fields.type === 'Bool') {
options.push({ value: column.id, label: column.fields.label });
}
}
return {
disabled: false,
options,
};
},
}),
};

View File

@@ -0,0 +1,108 @@
export type GristAPIClientOptions = {
domainUrl: string;
apiKey: string;
};
export type GristOrganizationResponse = {
name: string;
id: string;
createdAt: string;
updatedAt: string;
};
export type GristDocumentResponse = {
name: string;
id: string;
createdAt: string;
updatedAt: string;
};
export type GristWorkspaceResponse = {
name: string;
id: number;
createdAt: string;
updatedAt: string;
docs: Array<GristDocumentResponse>;
};
export type GristTableResponse = {
id: string;
};
export type GristTableColumnsResponse = {
id: string;
fields: {
type:
| 'Any'
| 'Text'
| 'Numeric'
| 'Int'
| 'Bool'
| 'Date'
| `DateTime:${string}`
| `Ref:${string}`
| `RefList:${string}`
| 'Choice'
| 'ChoiceList'
| 'Attachments';
label: string;
widgetOptions: string;
isFormula: boolean;
};
};
export type GristTableRecordResponse = {
id: number;
fields: Record<string, any>;
};
export type GristCreateRecordsRequest = {
records: Array<Omit<GristTableRecordResponse, 'id'>>;
};
export type GristUpdateRecordsRequest = {
records: Array<GristTableRecordResponse>;
};
export type GristCreateRecordsResponse = {
records: Array<{ id: number }>;
};
export type GristListRecordsResponse = {
records: Array<GristTableRecordResponse>;
};
export type GristCreateWebhookRequest = {
webhooks: Array<{
fields: {
name?: string;
memo?: string;
url: string;
enabled: boolean;
eventTypes: Array<string>;
isReadyColumn?: string;
tableId: string;
};
}>;
};
export type GristCreateWebhookResponse = {
webhooks: Array<{ id: number }>;
};
export type GristWebhookPayload = Record<string, any>;
export type GristOrgResponse = {
id: number
name: string
domain: string
owner: {
id: number
name: string
picture: any
}
access: string
createdAt: string
updatedAt: string
}

View File

@@ -0,0 +1,85 @@
import { gristAuth } from '../..';
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { commonProps } from '../common/props';
import { GristAPIClient } from '../common/helpers';
import { GristWebhookPayload } from '../common/types';
export const gristNewRecordTrigger = createTrigger({
auth: gristAuth,
name: 'grist-new-record',
displayName: 'New Record',
description: 'Triggers when a new record is added to the table.',
props: {
workspace_id: commonProps.workspace_id,
document_id: commonProps.document_id,
table_id: commonProps.table_id,
readiness_column: commonProps.readiness_column,
},
type: TriggerStrategy.WEBHOOK,
sampleData: {},
async onEnable(context) {
const documentId = context.propsValue.document_id;
const tableId = context.propsValue.table_id;
const readinessColumn = context.propsValue.readiness_column;
const client = new GristAPIClient({
domainUrl: context.auth.props.domain,
apiKey: context.auth.props.apiKey,
});
const response = await client.createDocumentWebhook(documentId, {
webhooks: [
{
fields: {
url: context.webhookUrl,
enabled: true,
eventTypes: ['add'],
tableId,
isReadyColumn: readinessColumn,
},
},
],
});
await context.store.put<number>(
'grist-new-record',
response.webhooks[0].id
);
},
async onDisable(context) {
const documentId = context.propsValue.document_id;
const webhookId = await context.store.get<number>('grist-new-record');
if (webhookId != null) {
const client = new GristAPIClient({
domainUrl: context.auth.props.domain,
apiKey: context.auth.props.apiKey,
});
await client.deleteDocumentWebhook(documentId, webhookId);
}
},
async run(context) {
const payload = context.payload.body as GristWebhookPayload[];
return payload;
},
async test(context) {
const documentId = context.propsValue.document_id;
const tableId = context.propsValue.table_id;
const client = new GristAPIClient({
domainUrl: context.auth.props.domain,
apiKey: context.auth.props.apiKey,
});
const response = await client.listRecordsFromTable(documentId, tableId, {
limit: '10',
});
return response.records.map((record) => {
return {
id: record.id,
...record.fields,
};
});
},
});

View File

@@ -0,0 +1,85 @@
import { gristAuth } from '../..';
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { commonProps } from '../common/props';
import { GristAPIClient } from '../common/helpers';
import { GristWebhookPayload } from '../common/types';
export const gristUpdatedRecordTrigger = createTrigger({
auth: gristAuth,
name: 'grist-updated-record',
displayName: 'Updated Record',
description: 'Triggers when a record is updated in the table.',
props: {
workspace_id: commonProps.workspace_id,
document_id: commonProps.document_id,
table_id: commonProps.table_id,
readiness_column: commonProps.readiness_column,
},
type: TriggerStrategy.WEBHOOK,
sampleData: {},
async onEnable(context) {
const documentId = context.propsValue.document_id;
const tableId = context.propsValue.table_id;
const readinessColumn = context.propsValue.readiness_column;
const client = new GristAPIClient({
domainUrl: context.auth.props.domain,
apiKey: context.auth.props.apiKey,
});
const response = await client.createDocumentWebhook(documentId, {
webhooks: [
{
fields: {
url: context.webhookUrl,
enabled: true,
eventTypes: ['update'],
tableId,
isReadyColumn: readinessColumn,
},
},
],
});
await context.store.put<number>(
'grist-updated-record',
response.webhooks[0].id
);
},
async onDisable(context) {
const documentId = context.propsValue.document_id;
const webhookId = await context.store.get<number>('grist-updated-record');
if (webhookId != null) {
const client = new GristAPIClient({
domainUrl: context.auth.props.domain,
apiKey: context.auth.props.apiKey,
});
await client.deleteDocumentWebhook(documentId, webhookId);
}
},
async run(context) {
const payload = context.payload.body as GristWebhookPayload[];
return payload;
},
async test(context) {
const documentId = context.propsValue.document_id;
const tableId = context.propsValue.table_id;
const client = new GristAPIClient({
domainUrl: context.auth.props.domain,
apiKey: context.auth.props.apiKey,
});
const response = await client.listRecordsFromTable(documentId, tableId, {
limit: '10',
});
return response.records.map((record) => {
return {
id: record.id,
...record.fields,
};
});
},
});