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,32 @@
{
"Tables": "Tables",
"Create Record(s)": "Create Record(s)",
"Delete Record(s)": "Delete Record(s)",
"Update Record": "Update Record",
"Get Record": "Get Record",
"Find Records": "Find Records",
"Insert one or more new records to a table.": "Insert one or more new records to a table.",
"Delete record(s) from a table": "Delete record(s) from a table",
"Update values in an existing record": "Update values in an existing record",
"Get single record by its id.": "Get single record by its id.",
"Find records in a table with filters.": "Find records in a table with filters.",
"Table Name": "Table Name",
"Records": "Records",
"Records IDs": "Records IDs",
"Record ID": "Record ID",
"Values": "Values",
"Limit": "Limit",
"Filters": "Filters",
"The records to create.": "The records to create.",
"The IDs of the records to delete": "The IDs of the records to delete",
"The ID of the record to do the action on.": "The ID of the record to do the action on.",
"The values to update. Leave empty to keep current value.": "The values to update. Leave empty to keep current value.",
"Maximum number of records to return (default no limit).": "Maximum number of records to return (default no limit).",
"Filter conditions to apply": "Filter conditions to apply",
"New Record Created": "New Record Created",
"Record Updated": "Record Updated",
"Record Deleted": "Record Deleted",
"Triggers when a new record is added to the selected table.": "Triggers when a new record is added to the selected table.",
"Triggers when a record is updated in the selected table.": "Triggers when a record is updated in the selected table.",
"Triggers when a record is deleted from the selected table.": "Triggers when a record is deleted from the selected table."
}

View File

@@ -0,0 +1,31 @@
{
"Create Record(s)": "Datensatz(e) erstellen",
"Delete Record(s)": "Datensatz(e) löschen",
"Update Record": "Datensatz aktualisieren",
"Get Record": "Datensatz abrufen",
"Find Records": "Datensätze finden",
"Insert one or more new records to a table.": "Fügen Sie einen oder mehrere neue Datensätze in eine Tabelle ein.",
"Delete record(s) from a table": "Datensatze(n) aus einer Tabelle löschen",
"Update values in an existing record": "Werte in einem vorhandenen Datensatz aktualisieren",
"Get single record by its id.": "Holen Sie sich einen einzelnen Datensatz durch seine ID.",
"Find records in a table with filters.": "Suchen Sie Datensätze in einer Tabelle mit Filtern.",
"Table Name": "Tabellenname",
"Records": "Datensätze",
"Records IDs": "Datensatz-ID",
"Record ID": "Datensatz-ID",
"Values": "Werte",
"Limit": "Limit",
"Filters": "Filter",
"The records to create.": "Zu erstellende Datensätze.",
"The IDs of the records to delete": "Die IDs der zu löschenden Datensätze",
"The ID of the record to do the action on.": "Die ID des Datensatzes, auf dem die Aktion ausgeführt wird.",
"The values to update. Leave empty to keep current value.": "Die zu aktualisierenden Werte. Leer lassen, um den aktuellen Wert zu behalten.",
"Maximum number of records to return (default no limit).": "Maximale Anzahl der zurückzugebenden Datensätze (Standard kein Limit).",
"Filter conditions to apply": "Zu verwendende Bedingungen filtern",
"New Record Created": "Neuer Datensatz erstellt",
"Record Updated": "Datensatz aktualisiert",
"Record Deleted": "Eintrag gelöscht",
"Triggers when a new record is added to the selected table.": "Wird ausgelöst, wenn ein neuer Datensatz zur ausgewählten Tabelle hinzugefügt wird.",
"Triggers when a record is updated in the selected table.": "Wird ausgelöst, wenn ein Datensatz in der ausgewählten Tabelle aktualisiert wird.",
"Triggers when a record is deleted from the selected table.": "Wird ausgelöst, wenn ein Datensatz aus der ausgewählten Tabelle gelöscht wird."
}

View File

@@ -0,0 +1,31 @@
{
"Create Record(s)": "Crear registro(s)",
"Delete Record(s)": "Eliminar registro(s)",
"Update Record": "Actualizar registro",
"Get Record": "Obtener registro",
"Find Records": "Buscar registros",
"Insert one or more new records to a table.": "Inserte uno o más registros nuevos en una tabla.",
"Delete record(s) from a table": "Eliminar registro(s) de una tabla",
"Update values in an existing record": "Actualizar valores en un registro existente",
"Get single record by its id.": "Obtener un único registro por su id.",
"Find records in a table with filters.": "Buscar registros en una tabla con filtros.",
"Table Name": "Nombre de tabla",
"Records": "Registros",
"Records IDs": "ID de registros",
"Record ID": "ID de registro",
"Values": "Valores",
"Limit": "Límite",
"Filters": "Filtros",
"The records to create.": "Los registros a crear.",
"The IDs of the records to delete": "Los IDs de los registros a eliminar",
"The ID of the record to do the action on.": "El ID del registro en el que realizar la acción.",
"The values to update. Leave empty to keep current value.": "Los valores a actualizar. Dejar en blanco para mantener el valor actual.",
"Maximum number of records to return (default no limit).": "Número máximo de registros a devolver (por defecto sin límite).",
"Filter conditions to apply": "Filtrar condiciones a aplicar",
"New Record Created": "Nuevo registro creado",
"Record Updated": "Registro actualizado",
"Record Deleted": "Registro eliminado",
"Triggers when a new record is added to the selected table.": "Se activa cuando se añade un nuevo registro a la tabla seleccionada.",
"Triggers when a record is updated in the selected table.": "Se activa cuando un registro se actualiza en la tabla seleccionada.",
"Triggers when a record is deleted from the selected table.": "Se activa cuando se elimina un registro de la tabla seleccionada."
}

View File

@@ -0,0 +1,31 @@
{
"Create Record(s)": "Créer un ou des enregistrement(s)",
"Delete Record(s)": "Supprimer les enregistrement(s)",
"Update Record": "Mettre à jour l'enregistrement",
"Get Record": "Obtenir un enregistrement",
"Find Records": "Trouver des enregistrements",
"Insert one or more new records to a table.": "Insérer un ou plusieurs nouveaux enregistrements dans une table.",
"Delete record(s) from a table": "Supprimer le(s) enregistrement(s) d'une table",
"Update values in an existing record": "Mettre à jour les valeurs dans un enregistrement existant",
"Get single record by its id.": "Obtenir un enregistrement unique par son identifiant.",
"Find records in a table with filters.": "Rechercher les enregistrements dans une table avec des filtres.",
"Table Name": "Nom de la table",
"Records": "Enregistrements",
"Records IDs": "ID d'enregistrements",
"Record ID": "ID de l'enregistrement",
"Values": "Valeurs",
"Limit": "Limite",
"Filters": "Filtres",
"The records to create.": "Les enregistrements à créer.",
"The IDs of the records to delete": "Les identifiants des enregistrements à supprimer",
"The ID of the record to do the action on.": "L'ID de l'enregistrement sur lequel effectuer l'action.",
"The values to update. Leave empty to keep current value.": "Les valeurs à mettre à jour. Laisser vide pour conserver la valeur actuelle.",
"Maximum number of records to return (default no limit).": "Nombre maximum d'enregistrements à retourner (sans limite par défaut).",
"Filter conditions to apply": "Filtrer les conditions à appliquer",
"New Record Created": "Nouvel enregistrement créé",
"Record Updated": "Enregistrement mis à jour",
"Record Deleted": "Enregistrement supprimé",
"Triggers when a new record is added to the selected table.": "Déclenche lorsqu'un nouvel enregistrement est ajouté à la table sélectionnée.",
"Triggers when a record is updated in the selected table.": "Déclenche lorsqu'un enregistrement est mis à jour dans le tableau sélectionné.",
"Triggers when a record is deleted from the selected table.": "Déclenche lorsqu'un enregistrement est supprimé de la table sélectionnée."
}

View File

@@ -0,0 +1,32 @@
{
"Tables": "Tables",
"Create Record(s)": "Create Record(s)",
"Delete Record(s)": "Delete Record(s)",
"Update Record": "Update Record",
"Get Record": "Get Record",
"Find Records": "Find Records",
"Insert one or more new records to a table.": "Insert one or more new records to a table.",
"Delete record(s) from a table": "Delete record(s) from a table",
"Update values in an existing record": "Update values in an existing record",
"Get single record by its id.": "Get single record by its id.",
"Find records in a table with filters.": "Find records in a table with filters.",
"Table Name": "Table Name",
"Records": "Records",
"Records IDs": "Records IDs",
"Record ID": "Record ID",
"Values": "Values",
"Limit": "Limit",
"Filters": "Filters",
"The records to create.": "The records to create.",
"The IDs of the records to delete": "The IDs of the records to delete",
"The ID of the record to do the action on.": "The ID of the record to do the action on.",
"The values to update. Leave empty to keep current value.": "The values to update. Leave empty to keep current value.",
"Maximum number of records to return (default no limit).": "Maximum number of records to return (default no limit).",
"Filter conditions to apply": "Filter conditions to apply",
"New Record Created": "New Record Created",
"Record Updated": "Record Updated",
"Record Deleted": "Record Deleted",
"Triggers when a new record is added to the selected table.": "Triggers when a new record is added to the selected table.",
"Triggers when a record is updated in the selected table.": "Triggers when a record is updated in the selected table.",
"Triggers when a record is deleted from the selected table.": "Triggers when a record is deleted from the selected table."
}

View File

@@ -0,0 +1,32 @@
{
"Tables": "Tables",
"Create Record(s)": "Create Record(s)",
"Delete Record(s)": "Delete Record(s)",
"Update Record": "Update Record",
"Get Record": "Get Record",
"Find Records": "Find Records",
"Insert one or more new records to a table.": "Insert one or more new records to a table.",
"Delete record(s) from a table": "Delete record(s) from a table",
"Update values in an existing record": "Update values in an existing record",
"Get single record by its id.": "Get single record by its id.",
"Find records in a table with filters.": "Find records in a table with filters.",
"Table Name": "Table Name",
"Records": "Records",
"Records IDs": "Records IDs",
"Record ID": "Record ID",
"Values": "Values",
"Limit": "Limit",
"Filters": "Filter",
"The records to create.": "The records to create.",
"The IDs of the records to delete": "The IDs of the records to delete",
"The ID of the record to do the action on.": "The ID of the record to do the action on.",
"The values to update. Leave empty to keep current value.": "The values to update. Leave empty to keep current value.",
"Maximum number of records to return (default no limit).": "Maximum number of records to return (default no limit).",
"Filter conditions to apply": "Filter conditions to apply",
"New Record Created": "New Record Created",
"Record Updated": "Record Updated",
"Record Deleted": "Record Deleted",
"Triggers when a new record is added to the selected table.": "Triggers when a new record is added to the selected table.",
"Triggers when a record is updated in the selected table.": "Triggers when a record is updated in the selected table.",
"Triggers when a record is deleted from the selected table.": "Triggers when a record is deleted from the selected table."
}

View File

@@ -0,0 +1,31 @@
{
"Create Record(s)": "レコードを作成",
"Delete Record(s)": "レコードを削除",
"Update Record": "更新記録",
"Get Record": "レコードを取得",
"Find Records": "レコードを検索",
"Insert one or more new records to a table.": "1つ以上の新しいレコードをテーブルに挿入します。",
"Delete record(s) from a table": "テーブルからレコードを削除",
"Update values in an existing record": "既存のレコードの値を更新",
"Get single record by its id.": "IDでシングルレコードを取得します。",
"Find records in a table with filters.": "フィルタ付きのテーブル内のレコードを検索します。",
"Table Name": "テーブル名",
"Records": "レコード",
"Records IDs": "レコードID",
"Record ID": "レコードID",
"Values": "値",
"Limit": "制限",
"Filters": "絞り込み",
"The records to create.": "作成するレコード。",
"The IDs of the records to delete": "削除するレコードの ID",
"The ID of the record to do the action on.": "アクションを実行するレコードの ID。",
"The values to update. Leave empty to keep current value.": "更新する値。空のままにすると現在の値が維持されます。",
"Maximum number of records to return (default no limit).": "Maximum number of records to return (default no limit).",
"Filter conditions to apply": "適用するフィルタ条件",
"New Record Created": "新しいレコードが作成されました",
"Record Updated": "レコードが更新されました",
"Record Deleted": "レコードが削除されました",
"Triggers when a new record is added to the selected table.": "選択したテーブルに新しいレコードが追加されたときにトリガーされます。",
"Triggers when a record is updated in the selected table.": "選択したテーブルでレコードが更新されたときにトリガーされます。",
"Triggers when a record is deleted from the selected table.": "選択したテーブルからレコードが削除されたときにトリガーされます。"
}

View File

@@ -0,0 +1,31 @@
{
"Create Record(s)": "Maak Opname(s)",
"Delete Record(s)": "Opname(s) verwijderen",
"Update Record": "Update Record",
"Get Record": "Krijg Record",
"Find Records": "Records zoeken",
"Insert one or more new records to a table.": "Een of meer nieuwe records toevoegen aan een tabel.",
"Delete record(s) from a table": "Verwijder record(s) uit een tabel",
"Update values in an existing record": "Waarden in een bestaand record bijwerken",
"Get single record by its id.": "Krijg enkele record bij zijn id.",
"Find records in a table with filters.": "Zoek records in een tabel met filters.",
"Table Name": "Tafel naam",
"Records": "Records",
"Records IDs": "Records ID's",
"Record ID": "Record ID",
"Values": "Waarden",
"Limit": "Limiet",
"Filters": "Filters",
"The records to create.": "De records om te maken.",
"The IDs of the records to delete": "De ID's van de te verwijderen records",
"The ID of the record to do the action on.": "Het ID van het record waar u de actie aan wilt doen.",
"The values to update. Leave empty to keep current value.": "De waarden om bij te werken. Laat leeg om de huidige waarde te behouden.",
"Maximum number of records to return (default no limit).": "Maximum aantal records om terug te sturen (standaard geen limiet).",
"Filter conditions to apply": "Filter voorwaarden toe te passen",
"New Record Created": "Nieuw Record Gemaakt",
"Record Updated": "Record bijgewerkt",
"Record Deleted": "Record verwijderd",
"Triggers when a new record is added to the selected table.": "Activeert wanneer een nieuwe record wordt toegevoegd aan de geselecteerde tabel.",
"Triggers when a record is updated in the selected table.": "Activeert wanneer een record wordt bijgewerkt in de geselecteerde tabel.",
"Triggers when a record is deleted from the selected table.": "Activeert wanneer een record wordt verwijderd uit de geselecteerde tabel."
}

View File

@@ -0,0 +1,31 @@
{
"Create Record(s)": "Criar Registro(s)",
"Delete Record(s)": "Excluir Registro(s)",
"Update Record": "Atualizar Registro",
"Get Record": "Obter Registro",
"Find Records": "Encontrar registros",
"Insert one or more new records to a table.": "Inserir um ou mais registros em uma tabela.",
"Delete record(s) from a table": "Excluir registro(s) de uma tabela",
"Update values in an existing record": "Atualizar valores em um registro existente",
"Get single record by its id.": "Obtenha um único registro por seu id.",
"Find records in a table with filters.": "Encontrar registros em uma tabela com filtros.",
"Table Name": "Nome da Tabela",
"Records": "registros",
"Records IDs": "IDs de registros",
"Record ID": "ID do Registro",
"Values": "Valores",
"Limit": "Limitar",
"Filters": "Filtros",
"The records to create.": "Os registros a criar.",
"The IDs of the records to delete": "Os IDs dos registros a serem excluídos",
"The ID of the record to do the action on.": "A ID do registro para fazer a ação.",
"The values to update. Leave empty to keep current value.": "Os valores a serem atualizados. Deixe em branco para manter o valor atual.",
"Maximum number of records to return (default no limit).": "Número máximo de registros para retornar (padrão sem limite)",
"Filter conditions to apply": "Condições de filtro a aplicar",
"New Record Created": "Novo Registro Criado",
"Record Updated": "Registro Atualizado",
"Record Deleted": "Registro Excluído",
"Triggers when a new record is added to the selected table.": "Dispara quando um novo registro é adicionado à tabela selecionada.",
"Triggers when a record is updated in the selected table.": "Dispara quando um registro é atualizado na tabela selecionada.",
"Triggers when a record is deleted from the selected table.": "Dispara quando um registro é excluído da tabela selecionada."
}

View File

@@ -0,0 +1,32 @@
{
"Tables": "Таблицы",
"Create Record(s)": "Создать запись(и)",
"Delete Record(s)": "Удалить запись(и)",
"Update Record": "Обновить запись",
"Get Record": "Получить запись",
"Find Records": "Найти записи",
"Insert one or more new records to a table.": "Вставьте одну или несколько новых записей в таблицу.",
"Delete record(s) from a table": "Удалить записи из таблицы",
"Update values in an existing record": "Обновить значения в существующей записи",
"Get single record by its id.": "Получить одну запись по идентификатору.",
"Find records in a table with filters.": "Найти записи в таблице с фильтрами.",
"Table Name": "Название таблицы",
"Records": "Отчеты",
"Records IDs": "Идентификаторы записей",
"Record ID": "ID записи",
"Values": "Значения",
"Limit": "Лимит",
"Filters": "Фильтры",
"The records to create.": "Записи для создания.",
"The IDs of the records to delete": "ID удаляемых записей",
"The ID of the record to do the action on.": "ID записи, на которую нужно выполнить действие.",
"The values to update. Leave empty to keep current value.": "Значения для обновления. Оставьте пустым, чтобы сохранить текущее значение.",
"Maximum number of records to return (default no limit).": "Максимальное количество возвращаемых записей (без ограничения по умолчанию).",
"Filter conditions to apply": "Фильтр условий для применения",
"New Record Created": "Создана новая запись",
"Record Updated": "Запись обновлена",
"Record Deleted": "Запись удалена",
"Triggers when a new record is added to the selected table.": "Включает при добавлении новой записи в выбранную таблицу.",
"Triggers when a record is updated in the selected table.": "Включает при обновлении записи в выбранной таблице.",
"Triggers when a record is deleted from the selected table.": "Включает при удалении записи из выбранной таблицы."
}

View File

@@ -0,0 +1,33 @@
{
"Create Record(s)": "Create Record(s)",
"Delete Record(s)": "Delete Record(s)",
"Update Record": "Update Record",
"Get Record": "Get Record",
"Find Records": "Find Records",
"Clear Table": "Clear Table",
"Insert one or more new records to a table.": "Insert one or more new records to a table.",
"Delete record(s) from a table": "Delete record(s) from a table",
"Update values in an existing record": "Update values in an existing record",
"Get single record by its id.": "Get single record by its id.",
"Find records in a table with filters.": "Find records in a table with filters.",
"Delete all records from a table": "Delete all records from a table",
"Table Name": "Table Name",
"Records": "Records",
"Records IDs": "Records IDs",
"Record ID": "Record ID",
"Values": "Values",
"Limit": "Limit",
"Filters": "Filters",
"The records to create.": "The records to create.",
"The IDs of the records to delete": "The IDs of the records to delete",
"The ID of the record to do the action on.": "The ID of the record to do the action on.",
"The values to update. Leave empty to keep current value.": "The values to update. Leave empty to keep current value.",
"Maximum number of records to return (default no limit).": "Maximum number of records to return (default no limit).",
"Filter conditions to apply": "Filter conditions to apply",
"New Record Created": "New Record Created",
"Record Updated": "Record Updated",
"Record Deleted": "Record Deleted",
"Triggers when a new record is added to the selected table.": "Triggers when a new record is added to the selected table.",
"Triggers when a record is updated in the selected table.": "Triggers when a record is updated in the selected table.",
"Triggers when a record is deleted from the selected table.": "Triggers when a record is deleted from the selected table."
}

View File

@@ -0,0 +1,32 @@
{
"Tables": "Tables",
"Create Record(s)": "Create Record(s)",
"Delete Record(s)": "Delete Record(s)",
"Update Record": "Update Record",
"Get Record": "Get Record",
"Find Records": "Find Records",
"Insert one or more new records to a table.": "Insert one or more new records to a table.",
"Delete record(s) from a table": "Delete record(s) from a table",
"Update values in an existing record": "Update values in an existing record",
"Get single record by its id.": "Get single record by its id.",
"Find records in a table with filters.": "Find records in a table with filters.",
"Table Name": "Table Name",
"Records": "Records",
"Records IDs": "Records IDs",
"Record ID": "Record ID",
"Values": "Values",
"Limit": "Limit",
"Filters": "Bộ lọc",
"The records to create.": "The records to create.",
"The IDs of the records to delete": "The IDs of the records to delete",
"The ID of the record to do the action on.": "The ID of the record to do the action on.",
"The values to update. Leave empty to keep current value.": "The values to update. Leave empty to keep current value.",
"Maximum number of records to return (default no limit).": "Maximum number of records to return (default no limit).",
"Filter conditions to apply": "Filter conditions to apply",
"New Record Created": "New Record Created",
"Record Updated": "Record Updated",
"Record Deleted": "Record Deleted",
"Triggers when a new record is added to the selected table.": "Triggers when a new record is added to the selected table.",
"Triggers when a record is updated in the selected table.": "Triggers when a record is updated in the selected table.",
"Triggers when a record is deleted from the selected table.": "Triggers when a record is deleted from the selected table."
}

View File

@@ -0,0 +1,31 @@
{
"Create Record(s)": "Create Record(s)",
"Delete Record(s)": "Delete Record(s)",
"Update Record": "Update Record",
"Get Record": "Get Record",
"Find Records": "Find Records",
"Insert one or more new records to a table.": "Insert one or more new records to a table.",
"Delete record(s) from a table": "Delete record(s) from a table",
"Update values in an existing record": "Update values in an existing record",
"Get single record by its id.": "Get single record by its id.",
"Find records in a table with filters.": "Find records in a table with filters.",
"Table Name": "Table Name",
"Records": "Records",
"Records IDs": "Records IDs",
"Record ID": "Record ID",
"Values": "值",
"Limit": "Limit",
"Filters": "篩選條件",
"The records to create.": "The records to create.",
"The IDs of the records to delete": "The IDs of the records to delete",
"The ID of the record to do the action on.": "The ID of the record to do the action on.",
"The values to update. Leave empty to keep current value.": "The values to update. Leave empty to keep current value.",
"Maximum number of records to return (default no limit).": "Maximum number of records to return (default no limit).",
"Filter conditions to apply": "Filter conditions to apply",
"New Record Created": "New Record Created",
"Record Updated": "Record Updated",
"Record Deleted": "Record Deleted",
"Triggers when a new record is added to the selected table.": "Triggers when a new record is added to the selected table.",
"Triggers when a record is updated in the selected table.": "Triggers when a record is updated in the selected table.",
"Triggers when a record is deleted from the selected table.": "Triggers when a record is deleted from the selected table."
}

View File

@@ -0,0 +1,22 @@
import { createPiece, PieceAuth } from "@activepieces/pieces-framework";
import { createRecords } from "./lib/actions/create-records";
import { PieceCategory } from "@activepieces/shared";
import { deleteRecord } from "./lib/actions/delete-record";
import { updateRecord } from "./lib/actions/update-record";
import { getRecord } from "./lib/actions/get-record";
import { findRecords } from "./lib/actions/find-records";
import { clearTable } from "./lib/actions/clear-table";
import { newRecordTrigger } from "./lib/triggers/new-record";
import { deletedRecordTrigger } from "./lib/triggers/deleted-record";
import { updatedRecordTrigger } from "./lib/triggers/updated-record";
export const tables = createPiece({
displayName: 'Tables',
logoUrl: 'https://cdn.activepieces.com/pieces/tables_piece.svg',
categories: [PieceCategory.CORE],
minimumSupportedRelease: '0.71.5',
authors: ['amrdb'],
auth: PieceAuth.None(),
actions: [createRecords, deleteRecord, updateRecord, getRecord, findRecords, clearTable],
triggers: [newRecordTrigger, updatedRecordTrigger, deletedRecordTrigger],
});

View File

@@ -0,0 +1,31 @@
import { createAction, PieceAuth } from '@activepieces/pieces-framework';
import { tablesCommon } from '../common';
import { AuthenticationType, httpClient, HttpMethod } from '@activepieces/pieces-common';
export const clearTable = createAction({
name: 'tables-clear-table',
displayName: 'Clear Table',
description: 'Delete all records from a table',
auth: PieceAuth.None(),
props: {
table_id: tablesCommon.table_id,
},
async run(context) {
const { table_id: tableExternalId } = context.propsValue;
const tableId = await tablesCommon.convertTableExternalIdToId(tableExternalId, context);
await httpClient.sendRequest({
method: HttpMethod.POST,
url: `${context.server.apiUrl}v1/tables/${tableId}/clear`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: context.server.token,
},
retries: 5,
});
return {
success: true,
};
},
});

View File

@@ -0,0 +1,78 @@
import { createAction, PieceAuth, Property } from '@activepieces/pieces-framework';
import { AuthenticationType, httpClient, HttpMethod, propsValidation } from '@activepieces/pieces-common';
import { CreateRecordsRequest } from '@activepieces/shared';
import { tablesCommon } from '../common';
export const createRecords = createAction({
name: 'tables-create-records',
displayName: 'Create Record(s)',
description: 'Insert one or more new records to a table.',
auth: PieceAuth.None(),
props: {
table_id: tablesCommon.table_id,
values: Property.DynamicProperties({
auth: PieceAuth.None(),
displayName: 'Records',
description: 'The records to create.',
required: true,
refreshers: ['table_id'],
props: async ({ table_id }, context) => {
const tableExternalId = table_id as unknown as string;
if ((tableExternalId ?? '').toString().length === 0) {
return {};
}
const tableId = await tablesCommon.convertTableExternalIdToId(tableExternalId, context);
const fields = await tablesCommon.createFieldProperties({ tableId, context });
if ('markdown' in fields) {
return fields;
}
return {
values: Property.Array({
displayName: 'Records',
description: 'Add one or more records to insert',
required: true,
properties: fields,
}),
};
},
}),
},
async run(context) {
const { table_id: tableExternalId, values } = context.propsValue;
const tableId = await tablesCommon.convertTableExternalIdToId(tableExternalId, context);
const tableFields = await tablesCommon.getTableFields({ tableId, context });
const records: CreateRecordsRequest['records'] = values['values'].map((record: Record<string, unknown>) =>
Object.entries(record)
.filter(([_, value]) => value !== null && value !== undefined && value !== '')
.map(([fieldExternalId, value]) => ({
fieldId: tableFields.find((field) => field.externalId === fieldExternalId)?.id,
value,
})).filter((record) => record.fieldId !== undefined)
)
const fieldValidations = tablesCommon.createFieldValidations(tableFields);
for (const record of values['values']) {
const cleanedRecord = Object.fromEntries(Object.entries(record).filter(([_, value]) => value !== null && value !== undefined && value !== ''));
await propsValidation.validateZod(cleanedRecord, fieldValidations);
}
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: `${context.server.apiUrl}v1/records`,
body: {
records,
tableId,
},
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: context.server.token,
},
retries: 5,
});
return response.body.map(tablesCommon.formatRecord);
},
});

View File

@@ -0,0 +1,38 @@
import { createAction, PieceAuth, Property } from '@activepieces/pieces-framework';
import { tablesCommon } from '../common';
import { AuthenticationType, httpClient, HttpMethod } from '@activepieces/pieces-common';
export const deleteRecord = createAction({
name: 'tables-delete-record',
displayName: 'Delete Record(s)',
description: 'Delete record(s) from a table',
auth: PieceAuth.None(),
props: {
table_id: tablesCommon.table_id,
records_ids: Property.Array({
displayName: 'Records IDs',
required: true,
description: 'The IDs of the records to delete'
}),
},
async run(context) {
const { records_ids } = context.propsValue;
await httpClient.sendRequest({
method: HttpMethod.DELETE,
url: `${context.server.apiUrl}v1/records/`,
body: {
ids: records_ids,
},
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: context.server.token,
},
retries: 5,
});
return {
success: true
};
},
});

View File

@@ -0,0 +1,153 @@
import { createAction, DynamicPropsValue, PieceAuth, Property, PropertyContext } from '@activepieces/pieces-framework';
import { tablesCommon } from '../common';
import { AuthenticationType, httpClient, HttpMethod, propsValidation } from '@activepieces/pieces-common';
import { FieldType, Filter, FilterOperator, ListRecordsRequest, PopulatedRecord, SeekPage } from '@activepieces/shared';
import { z } from 'zod';
import qs from 'qs';
type FieldInfo = {
id: string;
type: FieldType;
name: string;
};
export const findRecords = createAction({
name: 'tables-find-records',
displayName: 'Find Records',
description: 'Find records in a table with filters.',
auth: PieceAuth.None(),
props: {
table_id: tablesCommon.table_id,
limit: Property.Number({
displayName: 'Limit',
description: 'Maximum number of records to return (default no limit).',
required: false,
}),
filters: Property.DynamicProperties({
auth: PieceAuth.None(),
displayName: 'Filters',
description: 'Filter conditions to apply',
required: false,
refreshers: ['table_id'],
props: async (propsValue, context) => {
const table_id = propsValue['table_id'];
if (!table_id || typeof table_id !== 'string') {
return {
filters: Property.Array({
displayName: 'Filters',
required: false,
properties: {},
}),
};
}
const convertedTableId = await tablesCommon.convertTableExternalIdToId(table_id, context);
const fields = await tablesCommon.getTableFields({
tableId: convertedTableId,
context,
});
return {
filters: Property.Array({
displayName: 'Filters',
required: false,
properties: {
field: Property.StaticDropdown({
displayName: 'Field',
required: true,
options: {
options: fields.map((field) => ({
label: field.name,
value: { id: field.id, type: field.type, name: field.name } as FieldInfo,
})),
},
}),
operator: Property.StaticDropdown({
displayName: 'Operator',
required: true,
options: {
options: [
{ label: 'Equals', value: FilterOperator.EQ },
{ label: 'Not Equals', value: FilterOperator.NEQ },
{ label: 'Greater Than', value: FilterOperator.GT },
{ label: 'Greater Than or Equal', value: FilterOperator.GTE },
{ label: 'Less Than', value: FilterOperator.LT },
{ label: 'Less Than or Equal', value: FilterOperator.LTE },
{ label: 'Contains', value: FilterOperator.CO },
],
},
}),
value: Property.ShortText({
displayName: 'Value',
required: true,
}),
},
}),
};
},
}),
},
async run(context) {
const { table_id: tableExternalId, limit, filters } = context.propsValue;
const tableId = await tablesCommon.convertTableExternalIdToId(tableExternalId, context);
const filtersArray: { field: FieldInfo; operator: FilterOperator; value: unknown }[] = filters?.['filters'] ?? [];
for (const filter of filtersArray) {
const value = filter.value;
const fieldType = filter.field.type;
let schema: Record<string, z.ZodType>;
switch (fieldType) {
case FieldType.NUMBER:
schema = {
value: z.union([z.number(), z.string().transform(val => {
const num = Number(val);
if (isNaN(num)) throw new Error(`Invalid number for field "${filter.field.name}"`);
return num;
})]),
};
break;
case FieldType.DATE:
schema = {
value: z.union([z.date(), z.string().transform(val => {
const date = new Date(val);
if (isNaN(date.getTime())) throw new Error(`Invalid date for field "${filter.field.name}"`);
return date;
})]),
};
break;
default:
schema = {
value: z.string(),
};
}
await propsValidation.validateZod({ value }, schema);
}
const parsedFilters: Filter[] = filtersArray.map((filter) => ({
fieldId: filter.field.id,
operator: filter.operator,
value: filter.value as string,
}));
const request: ListRecordsRequest = {
tableId,
limit: limit ?? 999999999,
cursor: undefined,
filters: parsedFilters,
};
const response = await httpClient.sendRequest<SeekPage<PopulatedRecord>>({
method: HttpMethod.GET,
url: `${context.server.apiUrl}v1/records?${qs.stringify(request)}`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: context.server.token,
},
retries: 5,
});
return response.body.data.map(tablesCommon.formatRecord);
},
});

View File

@@ -0,0 +1,30 @@
import { createAction, PieceAuth, Property } from '@activepieces/pieces-framework';
import { tablesCommon } from '../common';
import { AuthenticationType, httpClient, HttpMethod } from '@activepieces/pieces-common';
import { PopulatedRecord } from '@activepieces/shared';
export const getRecord = createAction({
name: 'tables-get-record',
displayName: 'Get Record',
description: 'Get single record by its id.',
auth: PieceAuth.None(),
props: {
table_id: tablesCommon.table_id,
record_id: tablesCommon.record_id,
},
async run(context) {
const { record_id } = context.propsValue;
const response = await httpClient.sendRequest({
method: HttpMethod.GET,
url: `${context.server.apiUrl}v1/records/${record_id}`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: context.server.token,
},
retries: 5,
});
return tablesCommon.formatRecord(response.body as PopulatedRecord);
},
});

View File

@@ -0,0 +1,64 @@
import { createAction, PieceAuth, Property } from '@activepieces/pieces-framework';
import { tablesCommon } from '../common';
import { AuthenticationType, httpClient, HttpMethod, propsValidation } from '@activepieces/pieces-common';
import { PopulatedRecord, UpdateRecordRequest } from '@activepieces/shared';
export const updateRecord = createAction({
name: 'tables-update-record',
displayName: 'Update Record',
description: 'Update values in an existing record',
auth: PieceAuth.None(),
props: {
table_id: tablesCommon.table_id,
record_id: tablesCommon.record_id,
values: Property.DynamicProperties({
auth: PieceAuth.None(),
displayName: 'Values',
description: 'The values to update. Leave empty to keep current value.',
required: true,
refreshers: ['table_id'],
props: async ({ table_id }, context) => {
const tableExternalId = table_id as unknown as string;
const tableId = await tablesCommon.convertTableExternalIdToId(tableExternalId, context);
if ((tableId ?? '').toString().length === 0) {
return {};
}
return tablesCommon.createFieldProperties({ tableId, context });
},
}),
},
async run(context) {
const { table_id: tableExternalId, record_id, values } = context.propsValue;
const tableId = await tablesCommon.convertTableExternalIdToId(tableExternalId, context);
const tableFields = await tablesCommon.getTableFields({ tableId, context });
const fieldValidations = tablesCommon.createFieldValidations(tableFields);
await propsValidation.validateZod(values, fieldValidations);
const cells: UpdateRecordRequest['cells'] = Object.entries(values)
.filter(([_, value]) => value !== null && value !== undefined && value !== '')
.map(([fieldExternalId, value]) => ({
fieldId: tableFields.find((field) => field.externalId === fieldExternalId)?.id ?? '',
value,
})).filter((cell) => cell.fieldId !== '');
const request: UpdateRecordRequest = {
cells,
tableId,
};
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: `${context.server.apiUrl}v1/records/${record_id}`,
body: request,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: context.server.token,
},
retries: 5,
});
return tablesCommon.formatRecord(response.body as PopulatedRecord);
},
});

View File

@@ -0,0 +1,317 @@
import { AuthenticationType, httpClient, HttpMethod } from "@activepieces/pieces-common";
import { DynamicPropsValue, PieceAuth, Property } from "@activepieces/pieces-framework";
import { assertNotNullOrUndefined, CreateTableWebhookRequest, Field, FieldType, MarkdownVariant, PopulatedRecord, SeekPage, StaticDropdownEmptyOption, Table, TableWebhookEventType, ListTablesRequest } from "@activepieces/shared";
import { z } from 'zod';
import qs from 'qs';
type FormattedRecord = {
id: string;
created: string;
updated: string;
cells: Record<string, {
fieldName: string;
updated: string;
created: string;
value: unknown;
}>;
}
const getFieldTypeText = (fieldType: FieldType) => {
switch (fieldType) {
case FieldType.STATIC_DROPDOWN:
return 'Single Select';
case FieldType.DATE:
return 'Date';
case FieldType.NUMBER:
return 'Number';
case FieldType.TEXT:
return 'Text';
}
}
export const tablesCommon = {
table_id: Property.Dropdown({
auth: PieceAuth.None(),
displayName: 'Table Name',
required: true,
refreshers: [],
refreshOnSearch: true,
options: async (_propsValue, context) => {
try {
const tables = await fetchAllTables(context);
if (!Array.isArray(tables) || tables.length === 0) {
return {
options: [],
disabled: true,
placeholder: 'No tables found. Please create a table first.',
};
}
return {
options: tables.map((table: Table) => ({ label: table.name, value: table.externalId })),
};
} catch (e) {
console.error('Error fetching tables:', e);
return {
options: [],
disabled: true,
placeholder: 'Error loading tables. Please try again.',
};
}
},
}),
record_id: Property.ShortText({
displayName: 'Record ID',
description: 'The ID of the record to do the action on.',
required: true,
}),
async getTableFields({ tableId, context }: { tableId: string, context: { server: { apiUrl: string, token: string } } }) {
const fieldsResponse = await httpClient.sendRequest({
method: HttpMethod.GET,
url: `${context.server.apiUrl}v1/fields`,
queryParams: {
tableId,
},
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: context.server.token,
},
});
return fieldsResponse.body as Field[];
},
createFieldValidations(tableFields: Field[]) {
const fieldValidations: Record<string, z.ZodType> = {};
tableFields.forEach(field => {
switch (field.type) {
case FieldType.NUMBER:
fieldValidations[field.id] = z.union([z.number(), z.string().transform(val => {
const num = Number(val);
if (isNaN(num)) throw new Error(`Invalid number for field "${field.name}"`);
return num;
})]).optional();
break;
case FieldType.DATE:
fieldValidations[field.id] = z.union([z.date(), z.string().transform(val => {
const date = new Date(val);
if (isNaN(date.getTime())) throw new Error(`Invalid date for field "${field.name}"`);
return date;
})]).optional();
break;
default:
fieldValidations[field.id] = z.string().optional();
}
});
return fieldValidations;
},
async createFieldProperties({ tableId, context }: { tableId: string, context: { server: { apiUrl: string, token: string } } }): Promise<DynamicPropsValue> {
const fields: DynamicPropsValue = {};
try {
const tableFields = await this.getTableFields({ tableId, context });
if (!Array.isArray(tableFields) || tableFields.length === 0) {
fields['markdown'] = Property.MarkDown({
value: `We couldn't find any fields in the selected table. Please add fields to the table first.`,
variant: MarkdownVariant.INFO,
});
return fields;
}
for (const field of tableFields) {
const description = getFieldTypeText(field.type);
switch (field.type) {
case FieldType.NUMBER:
fields[field.externalId] = Property.Number({
displayName: field.name,
description,
required: false,
});
break;
case FieldType.DATE:
fields[field.externalId] = Property.DateTime({
displayName: field.name,
description,
required: false,
});
break;
case FieldType.STATIC_DROPDOWN:
fields[field.externalId] = Property.StaticDropdown({
displayName: field.name,
description,
defaultValue:'',
required: false,
options: {
options:[StaticDropdownEmptyOption,...field.data.options.map(option => ({ label: option.value, value: option.value }))],
},
});
break;
default:
fields[field.externalId] = Property.ShortText({
displayName: field.name,
description,
required: false,
defaultValue: '',
});
break;
}
}
return fields;
} catch (e) {
console.error('Error fetching fields:', e);
fields['markdown'] = Property.MarkDown({
value: `We couldn't find any fields in the selected table. Please add fields to the table first.`,
variant: MarkdownVariant.INFO,
});
return fields;
}
},
async createWebhook({
tableId,
events,
webhookUrl,
flowId,
server,
}: {
tableId: string;
events: TableWebhookEventType[];
webhookUrl: string;
flowId: string;
server: { apiUrl: string, token: string };
}) {
const request: CreateTableWebhookRequest = {
events,
webhookUrl,
flowId,
}
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: `${server.apiUrl}v1/tables/${tableId}/webhooks`,
body: request,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: server.token,
},
});
return response.body;
},
async deleteWebhook({
tableId,
webhookId,
server,
}: {
tableId: string;
webhookId: string;
server: { apiUrl: string, token: string };
}) {
const response = await httpClient.sendRequest({
method: HttpMethod.DELETE,
url: `${server.apiUrl}v1/tables/${tableId}/webhooks/${webhookId}`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: server.token,
},
});
return response.body;
},
async getRecentRecords({
tableId,
limit = 5,
context
}: {
tableId: string,
limit?: number,
context: { server: { apiUrl: string, token: string } }
}) {
if ((tableId ?? '').toString().length === 0) {
throw new Error(JSON.stringify({
message: 'Please add some records to the table before testing this trigger'
}))
}
const response = await httpClient.sendRequest({
method: HttpMethod.GET,
url: `${context.server.apiUrl}v1/records?tableId=${tableId}&limit=${limit}`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: context.server.token,
},
});
return response.body.data.map(this.formatRecord);
},
formatRecord(record: PopulatedRecord | { record: PopulatedRecord }): FormattedRecord {
const actualRecord = 'record' in record ? record.record : record;
return {
id: actualRecord.id,
created: actualRecord.created,
updated: actualRecord.updated,
cells: actualRecord.cells ? Object.fromEntries(Object.entries(actualRecord.cells).map(([fieldId, cell]) => {
return [fieldId, {
fieldName: cell.fieldName,
updated: cell.updated,
created: cell.created,
value: cell.value
}]
})) : {},
}
},
async convertTableExternalIdToId(tableId: string, context: { server: { apiUrl: string, token: string } }) {
const list: ListTablesRequest = {
externalIds: [tableId],
}
const res = await httpClient.sendRequest({
method: HttpMethod.GET,
url: `${context.server.apiUrl}v1/tables?${qs.stringify(list)}`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: context.server.token,
},
});
const table = (res.body as SeekPage<Table>).data[0];
assertNotNullOrUndefined(table, `Table with externalId ${tableId} not found`);
return table.id;
}
}
const fetchAllTables = async (context: { server: { apiUrl: string, token: string } }): Promise<Table[]> => {
const res = await httpClient.sendRequest({
method: HttpMethod.GET,
url: `${context.server.apiUrl}v1/tables?limit=100`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: context.server.token,
},
});
const resultBody = res.body as SeekPage<Table>
const tables = [...resultBody.data];
if (!Array.isArray(tables) || tables.length === 0) {
return [];
}
let next = resultBody.next;
while (next) {
const nextPage = await httpClient.sendRequest({
method: HttpMethod.GET,
url: `${context.server.apiUrl}v1/tables?cursor=${next}&limit=100`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: context.server.token,
},
});
const nextPageBody = nextPage.body as SeekPage<Table>
tables.push(...nextPageBody.data)
next = nextPageBody.next
}
return tables;
}

View File

@@ -0,0 +1,66 @@
import { createTrigger, PieceAuth, TriggerStrategy } from '@activepieces/pieces-framework';
import { tablesCommon } from '../common';
import { PopulatedRecord, TableWebhookEventType } from '@activepieces/shared';
export const deletedRecordTrigger = createTrigger({
name: 'deletedRecord',
displayName: 'Record Deleted',
description: 'Triggers when a record is deleted from the selected table.',
auth: PieceAuth.None(),
props: {
table_id: tablesCommon.table_id,
},
sampleData: {},
type: TriggerStrategy.WEBHOOK,
async onEnable(context) {
const tableExternalId = context.propsValue.table_id;
if ((tableExternalId ?? '').toString().length === 0) {
return;
}
const tableId = await tablesCommon.convertTableExternalIdToId(tableExternalId, context);
const { id: webhookId } = await tablesCommon.createWebhook({
tableId,
events: [TableWebhookEventType.RECORD_DELETED],
webhookUrl: context.webhookUrl,
flowId: context.flows.current.id,
server: {
apiUrl: context.server.apiUrl,
token: context.server.token,
},
});
context.store.put('webhookId', webhookId);
},
async onDisable(context) {
const tableExternalId = context.propsValue.table_id;
if ((tableExternalId ?? '').toString().length === 0) {
return;
}
const tableId = await tablesCommon.convertTableExternalIdToId(tableExternalId, context);
const webhookId = await context.store.get<string>('webhookId');
if (!webhookId) {
return;
}
await tablesCommon.deleteWebhook({
tableId,
webhookId: webhookId,
server: {
apiUrl: context.server.apiUrl,
token: context.server.token,
},
});
},
async run(context) {
return [tablesCommon.formatRecord(context.payload.body as PopulatedRecord)]
},
async test(context) {
const tableId = await tablesCommon.convertTableExternalIdToId(context.propsValue.table_id, context);
return tablesCommon.getRecentRecords({
tableId,
context
});
}
})

View File

@@ -0,0 +1,65 @@
import { createTrigger, PieceAuth, TriggerStrategy } from '@activepieces/pieces-framework';
import { tablesCommon } from '../common';
import { PopulatedRecord, TableWebhookEventType } from '@activepieces/shared';
export const newRecordTrigger = createTrigger({
name: 'newRecord',
displayName: 'New Record Created',
description: 'Triggers when a new record is added to the selected table.',
auth: PieceAuth.None(),
props: {
table_id: tablesCommon.table_id,
},
sampleData: {},
type: TriggerStrategy.WEBHOOK,
async onEnable(context){
const tableExternalId = context.propsValue.table_id;
if ((tableExternalId ?? '').toString().length === 0) {
return;
}
const tableId = await tablesCommon.convertTableExternalIdToId(tableExternalId, context);
const { id: webhookId } = await tablesCommon.createWebhook({
tableId,
events: [TableWebhookEventType.RECORD_CREATED],
webhookUrl: context.webhookUrl,
flowId: context.flows.current.id,
server: {
apiUrl: context.server.apiUrl,
token: context.server.token,
},
});
context.store.put('webhookId', webhookId);
},
async onDisable(context){
const tableExternalId = context.propsValue.table_id;
if ((tableExternalId ?? '').toString().length === 0) {
return;
}
const tableId = await tablesCommon.convertTableExternalIdToId(tableExternalId, context);
const webhookId = await context.store.get<string>('webhookId');
if (!webhookId) {
return;
}
await tablesCommon.deleteWebhook({
tableId,
webhookId: webhookId,
server: {
apiUrl: context.server.apiUrl,
token: context.server.token,
},
});
},
async run(context){
return [tablesCommon.formatRecord(context.payload.body as PopulatedRecord)]
},
async test(context) {
const tableId = await tablesCommon.convertTableExternalIdToId(context.propsValue.table_id, context);
return tablesCommon.getRecentRecords({
tableId,
context
});
}
})

View File

@@ -0,0 +1,66 @@
import { createTrigger, PieceAuth, TriggerStrategy } from '@activepieces/pieces-framework';
import { tablesCommon } from '../common';
import { PopulatedRecord, TableWebhookEventType } from '@activepieces/shared';
export const updatedRecordTrigger = createTrigger({
name: 'updatedRecord',
displayName: 'Record Updated',
description: 'Triggers when a record is updated in the selected table.',
auth: PieceAuth.None(),
props: {
table_id: tablesCommon.table_id,
},
sampleData: {},
type: TriggerStrategy.WEBHOOK,
async onEnable(context) {
const tableExternalId = context.propsValue.table_id;
if ((tableExternalId ?? '').toString().length === 0) {
return;
}
const tableId = await tablesCommon.convertTableExternalIdToId(tableExternalId, context);
const { id: webhookId } = await tablesCommon.createWebhook({
tableId,
events: [TableWebhookEventType.RECORD_UPDATED],
webhookUrl: context.webhookUrl,
flowId: context.flows.current.id,
server: {
apiUrl: context.server.apiUrl,
token: context.server.token,
},
});
context.store.put('webhookId', webhookId);
},
async onDisable(context) {
const tableExternalId = context.propsValue.table_id;
if ((tableExternalId ?? '').toString().length === 0) {
return;
}
const tableId = await tablesCommon.convertTableExternalIdToId(tableExternalId, context);
const webhookId = await context.store.get<string>('webhookId');
if (!webhookId) {
return;
}
await tablesCommon.deleteWebhook({
tableId,
webhookId: webhookId,
server: {
apiUrl: context.server.apiUrl,
token: context.server.token,
},
});
},
async run(context) {
return [tablesCommon.formatRecord(context.payload.body as PopulatedRecord)]
},
async test(context) {
const tableId = await tablesCommon.convertTableExternalIdToId(context.propsValue.table_id, context);
return tablesCommon.getRecentRecords({
tableId,
context
});
}
})