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,46 @@
{
"Create an API key in the [Coda Account dashboard](https://coda.io/account).": "Erstellen Sie einen API-Schlüssel im [Coda Account Dashboard](https://coda.io/account).",
"Create Row": "Zeile erstellen",
"Update Row": "Zeile aktualisieren",
"Upsert Row": "Upsert-Zeile",
"Find Row(s)": "Zeile(n) finden",
"Get Row": "Zeile holen",
"List Table(s)": "Tabelle(s) auflisten",
"Get Table": "Tisch holen",
"Custom API Call": "Eigener API-Aufruf",
"Creates a new row in the selected table.": "Erstellt eine neue Zeile in der ausgewählten Tabelle.",
"Updates an existing row in the selected table.": "Aktualisiert eine vorhandene Zeile in der ausgewählten Tabelle.",
"Creates a new row or updates an existing one if it matches key columns.": "Erstellt eine neue Zeile oder aktualisiert eine existierende Zeile, wenn sie zu Schlüsselspalten passt.",
"Find specific rows in the selected table using a column match search.": "Finden Sie bestimmte Zeilen in der ausgewählten Tabelle, indem Sie eine Spaltensuche verwenden.",
"Retrieves a single row by specified ID.": "Ruft eine einzelne Zeile durch die angegebene ID ab.",
"List tables in a selected document.": "Listet Tabellen in einem ausgewählten Dokument auf.",
"Get structure and details of a specific table (e.g., columns, schema).": "Holen Sie sich Struktur und Details einer bestimmten Tabelle (z.B. Spalten, Schema).",
"Make a custom API call to a specific endpoint": "Einen benutzerdefinierten API-Aufruf an einen bestimmten Endpunkt machen",
"Document": "Dokument",
"Table": "Tisch",
"Row Data": "Zeilendaten",
"Row ID or Name": "Zeilennummer oder Name",
"Matching Columns": "Passende Spalten",
"Search Column": "Spalte durchsuchen",
"Search Value": "Suchwert",
"Max Tables": "Max. Tabellen",
"Method": "Methode",
"Headers": "Kopfzeilen",
"Query Parameters": "Abfrageparameter",
"Body": "Körper",
"Response is Binary ?": "Antwort ist binär?",
"No Error on Failure": "Kein Fehler bei Fehler",
"Timeout (in seconds)": "Timeout (in Sekunden)",
"Define the data for the new row based on table columns.": "Definieren Sie die Daten für den neuen Datensatz basierend auf Tabellenspalten.",
"Maximum number of results to return.": "Maximale Anzahl der zurückzugebenden Ergebnisse.",
"Authorization headers are injected automatically from your connection.": "Autorisierungs-Header werden automatisch von Ihrer Verbindung injiziert.",
"Enable for files like PDFs, images, etc..": "Aktivieren für Dateien wie PDFs, Bilder, etc..",
"GET": "ERHALTEN",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "LÖSCHEN",
"HEAD": "HEAD",
"New Row Created": "Neue Zeile erstellt",
"Triggers when a new row is added to the selected table.": "Wird ausgelöst, wenn der ausgewählten Tabelle eine neue Zeile hinzugefügt wird."
}

View File

@@ -0,0 +1,46 @@
{
"Create an API key in the [Coda Account dashboard](https://coda.io/account).": "Crear una clave API en el [Panel de control de la cuenta Coda](https://coda.io/account).",
"Create Row": "Crear fila",
"Update Row": "Actualizar fila",
"Upsert Row": "Subir fila",
"Find Row(s)": "Buscar fila(s)",
"Get Row": "Obtener fila",
"List Table(s)": "Listar tabla(s)",
"Get Table": "Obtener tabla",
"Custom API Call": "Llamada API personalizada",
"Creates a new row in the selected table.": "Crea una nueva fila en la tabla seleccionada.",
"Updates an existing row in the selected table.": "Actualiza una fila existente en la tabla seleccionada.",
"Creates a new row or updates an existing one if it matches key columns.": "Crea una nueva fila o actualiza una existente si coincide con columnas clave.",
"Find specific rows in the selected table using a column match search.": "Encuentre registros específicos en la tabla seleccionada usando una búsqueda de columnas.",
"Retrieves a single row by specified ID.": "Recuperar una sola fila con el ID especificado.",
"List tables in a selected document.": "Listar tablas en un documento seleccionado.",
"Get structure and details of a specific table (e.g., columns, schema).": "Obtener la estructura y los detalles de una tabla específica (por ejemplo, columnas, esquema).",
"Make a custom API call to a specific endpoint": "Hacer una llamada API personalizada a un extremo específico",
"Document": "Documento",
"Table": "Tabla",
"Row Data": "Datos de fila",
"Row ID or Name": "ID o nombre de fila",
"Matching Columns": "Columnas coincidentes",
"Search Column": "Columna de búsqueda",
"Search Value": "Valor de búsqueda",
"Max Tables": "Tablas Máximas",
"Method": "Método",
"Headers": "Encabezados",
"Query Parameters": "Parámetros de consulta",
"Body": "Cuerpo",
"Response is Binary ?": "¿Respuesta es binaria?",
"No Error on Failure": "No hay ningún error en fallo",
"Timeout (in seconds)": "Tiempo de espera (en segundos)",
"Define the data for the new row based on table columns.": "Definir los datos para el nuevo registro basado en columnas de la tabla.",
"Maximum number of results to return.": "Número máximo de resultados a regresar.",
"Authorization headers are injected automatically from your connection.": "Las cabeceras de autorización se inyectan automáticamente desde tu conexión.",
"Enable for files like PDFs, images, etc..": "Activar para archivos como PDFs, imágenes, etc.",
"GET": "RECOGER",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "BORRAR",
"HEAD": "LIMPIO",
"New Row Created": "Nueva fila creada",
"Triggers when a new row is added to the selected table.": "Se activa cuando se añade una nueva fila a la tabla seleccionada."
}

View File

@@ -0,0 +1,46 @@
{
"Create an API key in the [Coda Account dashboard](https://coda.io/account).": "Créez une clé API dans le [Tableau de bord du compte Coda](https://coda.io/account).",
"Create Row": "Créer une ligne",
"Update Row": "Mettre à jour la ligne",
"Upsert Row": "Lignée supérieure",
"Find Row(s)": "Trouver des lignes(s)",
"Get Row": "Obtenir la ligne",
"List Table(s)": "Liste(s) table(s)",
"Get Table": "Récupérer la table",
"Custom API Call": "Appel API personnalisé",
"Creates a new row in the selected table.": "Crée une nouvelle ligne dans la table sélectionnée.",
"Updates an existing row in the selected table.": "Met à jour une ligne existante dans la table sélectionnée.",
"Creates a new row or updates an existing one if it matches key columns.": "Crée une nouvelle ligne ou met à jour une ligne existante si elle correspond aux colonnes de clés.",
"Find specific rows in the selected table using a column match search.": "Trouver des lignes spécifiques dans la table sélectionnée à l'aide d'une recherche de colonnes.",
"Retrieves a single row by specified ID.": "Récupère une seule ligne par l'ID spécifié.",
"List tables in a selected document.": "Lister les tables dans un document sélectionné.",
"Get structure and details of a specific table (e.g., columns, schema).": "Récupère la structure et les détails d'une table spécifique (par exemple, colonnes, schéma).",
"Make a custom API call to a specific endpoint": "Passez un appel API personnalisé à un point de terminaison spécifique",
"Document": "Document",
"Table": "Tableau",
"Row Data": "Données de la ligne",
"Row ID or Name": "ID de ligne ou nom",
"Matching Columns": "Colonnes correspondantes",
"Search Column": "Colonne de recherche",
"Search Value": "Valeur de la recherche",
"Max Tables": "Tables max",
"Method": "Méthode",
"Headers": "En-têtes",
"Query Parameters": "Paramètres de requête",
"Body": "Corps",
"Response is Binary ?": "La réponse est Binaire ?",
"No Error on Failure": "Aucune erreur en cas d'échec",
"Timeout (in seconds)": "Délai d'attente (en secondes)",
"Define the data for the new row based on table columns.": "Définit les données de la nouvelle ligne en fonction des colonnes de la table.",
"Maximum number of results to return.": "Nombre maximum de résultats à retourner.",
"Authorization headers are injected automatically from your connection.": "Les en-têtes d'autorisation sont injectés automatiquement à partir de votre connexion.",
"Enable for files like PDFs, images, etc..": "Activer pour les fichiers comme les PDFs, les images, etc.",
"GET": "OBTENIR",
"POST": "POSTER",
"PATCH": "PATCH",
"PUT": "EFFACER",
"DELETE": "SUPPRIMER",
"HEAD": "TÊTE",
"New Row Created": "Nouvelle ligne créée",
"Triggers when a new row is added to the selected table.": "Déclenche quand une nouvelle ligne est ajoutée à la table sélectionnée."
}

View File

@@ -0,0 +1,46 @@
{
"Create an API key in the [Coda Account dashboard](https://coda.io/account).": "[Coda Account dashboard](https://coda.io/account)にAPIキーを作成します。",
"Create Row": "行を作成",
"Update Row": "行を更新",
"Upsert Row": "Upsert Row",
"Find Row(s)": "行を検索",
"Get Row": "行を取得",
"List Table(s)": "表の一覧",
"Get Table": "テーブルを取得する",
"Custom API Call": "カスタムAPI通話",
"Creates a new row in the selected table.": "選択したテーブルに新しい行を作成します。",
"Updates an existing row in the selected table.": "選択した表の既存の行を更新します。",
"Creates a new row or updates an existing one if it matches key columns.": "新しい行を作成するか、キー列と一致する場合は既存の行を更新します。",
"Find specific rows in the selected table using a column match search.": "列一致検索を使用して、選択したテーブル内の特定の行を検索します。",
"Retrieves a single row by specified ID.": "指定した ID で単一行を取得します。",
"List tables in a selected document.": "選択したドキュメント内の表の一覧です。",
"Get structure and details of a specific table (e.g., columns, schema).": "特定のテーブル (列、スキーマなど) の構造と詳細を取得します。",
"Make a custom API call to a specific endpoint": "特定のエンドポイントへのカスタム API コールを実行します。",
"Document": "ドキュメント",
"Table": "表",
"Row Data": "行データ",
"Row ID or Name": "行IDまたは名前",
"Matching Columns": "一致する列",
"Search Column": "列を検索",
"Search Value": "検索値",
"Max Tables": "テーブルの最大数",
"Method": "方法",
"Headers": "ヘッダー",
"Query Parameters": "クエリパラメータ",
"Body": "本文",
"Response is Binary ?": "応答はバイナリですか?",
"No Error on Failure": "失敗時にエラーはありません",
"Timeout (in seconds)": "タイムアウト(秒)",
"Define the data for the new row based on table columns.": "テーブル列に基づいて新しい行のデータを定義します。",
"Maximum number of results to return.": "返す結果の最大数。",
"Authorization headers are injected automatically from your connection.": "認証ヘッダは接続から自動的に注入されます。",
"Enable for files like PDFs, images, etc..": "PDF、画像などのファイルを有効にします。",
"GET": "取得",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "削除",
"HEAD": "頭",
"New Row Created": "新しい行を作成しました",
"Triggers when a new row is added to the selected table.": "選択したテーブルに新しい行が追加されたときにトリガーされます。"
}

View File

@@ -0,0 +1,46 @@
{
"Create an API key in the [Coda Account dashboard](https://coda.io/account).": "Maak een API-sleutel in het [Coda Account dashboard](https://coda.io/account).",
"Create Row": "Rij maken",
"Update Row": "Rij bijwerken",
"Upsert Row": "In de woestijn rij",
"Find Row(s)": "Rij(en) zoeken",
"Get Row": "Verkrijg rij",
"List Table(s)": "Toon tabel(s)",
"Get Table": "Tabel ophalen",
"Custom API Call": "Custom API Call",
"Creates a new row in the selected table.": "Maakt een nieuwe rij in de geselecteerde tabel.",
"Updates an existing row in the selected table.": "Werkt een bestaande rij in de geselecteerde tabel bij.",
"Creates a new row or updates an existing one if it matches key columns.": "Maakt een nieuwe rij of update een bestaande als het overeenkomt met sleutelkolommen.",
"Find specific rows in the selected table using a column match search.": "Vind specifieke rijen in de geselecteerde tabel met behulp van een kolommatch zoeken.",
"Retrieves a single row by specified ID.": "Haalt een enkele rij op met een opgegeven ID.",
"List tables in a selected document.": "Lijst tabellen in een geselecteerd document.",
"Get structure and details of a specific table (e.g., columns, schema).": "Krijg de structuur en details van een specifieke tabel (bijv. kolommen, schema).",
"Make a custom API call to a specific endpoint": "Maak een aangepaste API call naar een specifiek eindpunt",
"Document": "Document",
"Table": "Tabel",
"Row Data": "Rij gegevens",
"Row ID or Name": "Rij ID of naam",
"Matching Columns": "Overeenkomende kolommen",
"Search Column": "Zoek in kolom",
"Search Value": "Waarde zoeken",
"Max Tables": "Max. aantal tabellen",
"Method": "Methode",
"Headers": "Kopteksten",
"Query Parameters": "Query parameters",
"Body": "Lichaam",
"Response is Binary ?": "Antwoord is binair?",
"No Error on Failure": "Geen fout bij fout",
"Timeout (in seconds)": "Time-out (in seconden)",
"Define the data for the new row based on table columns.": "Definieer de gegevens voor de nieuwe rij gebaseerd op tabel kolommen.",
"Maximum number of results to return.": "Maximum aantal resultaten om weer te geven.",
"Authorization headers are injected automatically from your connection.": "Autorisatie headers worden automatisch geïnjecteerd vanuit uw verbinding.",
"Enable for files like PDFs, images, etc..": "Inschakelen voor bestanden zoals PDF's, afbeeldingen etc..",
"GET": "KRIJG",
"POST": "POSTE",
"PATCH": "BEKIJK",
"PUT": "PUT",
"DELETE": "VERWIJDEREN",
"HEAD": "HOOFD",
"New Row Created": "Nieuwe rij gemaakt",
"Triggers when a new row is added to the selected table.": "Triggert wanneer een nieuwe rij wordt toegevoegd aan de geselecteerde tabel."
}

View File

@@ -0,0 +1,46 @@
{
"Create an API key in the [Coda Account dashboard](https://coda.io/account).": "Criar uma chave de API no [Painel de Conta Coda](https://coda.io/account).",
"Create Row": "Criar Linha",
"Update Row": "Atualizar linha",
"Upsert Row": "Linha Recorrente",
"Find Row(s)": "Localizar Linha(s)",
"Get Row": "Obter Linha",
"List Table(s)": "Listar Tabela(s)",
"Get Table": "Obter mesa",
"Custom API Call": "Chamada de API personalizada",
"Creates a new row in the selected table.": "Cria uma nova linha na tabela selecionada.",
"Updates an existing row in the selected table.": "Atualiza uma linha existente na tabela selecionada.",
"Creates a new row or updates an existing one if it matches key columns.": "Cria uma nova linha ou atualiza uma existente se corresponder a colunas chave.",
"Find specific rows in the selected table using a column match search.": "Localizar linhas específicas na tabela selecionada usando uma busca de coluna para coincidir.",
"Retrieves a single row by specified ID.": "Recupera uma única linha com a ID especificada.",
"List tables in a selected document.": "Listar tabelas em um documento selecionado.",
"Get structure and details of a specific table (e.g., columns, schema).": "Obter estrutura e detalhes de uma tabela específica (por exemplo, colunas, esquema).",
"Make a custom API call to a specific endpoint": "Faça uma chamada de API personalizada para um ponto de extremidade específico",
"Document": "Documento",
"Table": "Classificações",
"Row Data": "Dados da Linha",
"Row ID or Name": "ID ou Nome da Linha",
"Matching Columns": "Colunas correspondentes",
"Search Column": "Pesquisar Coluna",
"Search Value": "Pesquisar Valor",
"Max Tables": "Máximo de tabelas",
"Method": "Método",
"Headers": "Cabeçalhos",
"Query Parameters": "Parâmetros da consulta",
"Body": "Conteúdo",
"Response is Binary ?": "A resposta é binária ?",
"No Error on Failure": "Nenhum erro no Failure",
"Timeout (in seconds)": "Tempo limite (em segundos)",
"Define the data for the new row based on table columns.": "Define os dados para a nova linha baseada nas colunas da tabela.",
"Maximum number of results to return.": "Número máximo de resultados para retornar.",
"Authorization headers are injected automatically from your connection.": "Os cabeçalhos de autorização são inseridos automaticamente a partir da sua conexão.",
"Enable for files like PDFs, images, etc..": "Habilitar para arquivos como PDFs, imagens, etc..",
"GET": "OBTER",
"POST": "POSTAR",
"PATCH": "COMPRAR",
"PUT": "COLOCAR",
"DELETE": "EXCLUIR",
"HEAD": "CABEÇA",
"New Row Created": "Nova Linha Criada",
"Triggers when a new row is added to the selected table.": "Dispara quando uma nova linha é adicionada à tabela selecionada."
}

View File

@@ -0,0 +1,45 @@
{
"Coda": "Coda",
"Create an API key in the [Coda Account dashboard](https://coda.io/account).": "Создайте ключ API в [Панели учетной записи Coda](https://coda.io/account).",
"Create Row": "Создать строку",
"Update Row": "Обновить строку",
"Upsert Row": "Верхняя строка",
"Find Row(s)": "Найти строку(и)",
"Get Row": "Получить строку",
"List Table(s)": "Таблица(ы) списка",
"Get Table": "Получить таблицу",
"Custom API Call": "Пользовательский вызов API",
"Creates a new row in the selected table.": "Создает новую строку в выбранной таблице.",
"Updates an existing row in the selected table.": "Обновляет существующую строку в выбранной таблице.",
"Creates a new row or updates an existing one if it matches key columns.": "Создает новую строку или обновляет существующий, если он соответствует колонкам ключей.",
"Find specific rows in the selected table using a column match search.": "Найти конкретные строки в выбранной таблице, используя поиск по столбцам.",
"Retrieves a single row by specified ID.": "Получает одну строку по указанному ID.",
"List tables in a selected document.": "Список таблиц в выбранном документе.",
"Get structure and details of a specific table (e.g., columns, schema).": "Получить структуру и детали конкретной таблицы (например, колонки, схема).",
"Make a custom API call to a specific endpoint": "Сделать пользовательский API вызов к определенной конечной точке",
"Document": "Документ",
"Table": "Таблица",
"Row Data": "Данные строк",
"Row ID or Name": "ID или имя строки",
"Matching Columns": "Соответствующие столбцы",
"Search Column": "Столбец поиска",
"Search Value": "Поисковое значение",
"Max Tables": "Макс. таблиц",
"Method": "Метод",
"Headers": "Заголовки",
"Query Parameters": "Параметры запроса",
"Body": "Тело",
"No Error on Failure": "Нет ошибок при ошибке",
"Timeout (in seconds)": "Таймаут (в секундах)",
"Define the data for the new row based on table columns.": "Определите данные для новой строки на основе столбцов таблиц.",
"Maximum number of results to return.": "Максимальное количество результатов возврата.",
"Authorization headers are injected automatically from your connection.": "Заголовки авторизации включаются автоматически из вашего соединения.",
"GET": "ПОЛУЧИТЬ",
"POST": "ПОСТ",
"PATCH": "ПАТЧ",
"PUT": "ПОКУПИТЬ",
"DELETE": "УДАЛИТЬ",
"HEAD": "HEAD",
"New Row Created": "Создана новая строка",
"Triggers when a new row is added to the selected table.": "Включает при добавлении новой строки в выбранную таблицу."
}

View File

@@ -0,0 +1,46 @@
{
"Create an API key in the [Coda Account dashboard](https://coda.io/account).": "Create an API key in the [Coda Account dashboard](https://coda.io/account).",
"Create Row": "Create Row",
"Update Row": "Update Row",
"Upsert Row": "Upsert Row",
"Find Row(s)": "Find Row(s)",
"Get Row": "Get Row",
"List Table(s)": "List Table(s)",
"Get Table": "Get Table",
"Custom API Call": "Custom API Call",
"Creates a new row in the selected table.": "Creates a new row in the selected table.",
"Updates an existing row in the selected table.": "Updates an existing row in the selected table.",
"Creates a new row or updates an existing one if it matches key columns.": "Creates a new row or updates an existing one if it matches key columns.",
"Find specific rows in the selected table using a column match search.": "Find specific rows in the selected table using a column match search.",
"Retrieves a single row by specified ID.": "Retrieves a single row by specified ID.",
"List tables in a selected document.": "List tables in a selected document.",
"Get structure and details of a specific table (e.g., columns, schema).": "Get structure and details of a specific table (e.g., columns, schema).",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Document": "Document",
"Table": "Table",
"Row Data": "Row Data",
"Row ID or Name": "Row ID or Name",
"Matching Columns": "Matching Columns",
"Search Column": "Search Column",
"Search Value": "Search Value",
"Max Tables": "Max Tables",
"Method": "Method",
"Headers": "Headers",
"Query Parameters": "Query Parameters",
"Body": "Body",
"Response is Binary ?": "Response is Binary ?",
"No Error on Failure": "No Error on Failure",
"Timeout (in seconds)": "Timeout (in seconds)",
"Define the data for the new row based on table columns.": "Define the data for the new row based on table columns.",
"Maximum number of results to return.": "Maximum number of results to return.",
"Authorization headers are injected automatically from your connection.": "Authorization headers are injected automatically from your connection.",
"Enable for files like PDFs, images, etc..": "Enable for files like PDFs, images, etc..",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"New Row Created": "New Row Created",
"Triggers when a new row is added to the selected table.": "Triggers when a new row is added to the selected table."
}

View File

@@ -0,0 +1,45 @@
{
"Coda": "Coda",
"Create an API key in the [Coda Account dashboard](https://coda.io/account).": "Create an API key in the [Coda Account dashboard](https://coda.io/account).",
"Create Row": "Create Row",
"Update Row": "Update Row",
"Upsert Row": "Upsert Row",
"Find Row(s)": "Find Row(s)",
"Get Row": "Get Row",
"List Table(s)": "List Table(s)",
"Get Table": "Get Table",
"Custom API Call": "Custom API Call",
"Creates a new row in the selected table.": "Creates a new row in the selected table.",
"Updates an existing row in the selected table.": "Updates an existing row in the selected table.",
"Creates a new row or updates an existing one if it matches key columns.": "Creates a new row or updates an existing one if it matches key columns.",
"Find specific rows in the selected table using a column match search.": "Find specific rows in the selected table using a column match search.",
"Retrieves a single row by specified ID.": "Retrieves a single row by specified ID.",
"List tables in a selected document.": "List tables in a selected document.",
"Get structure and details of a specific table (e.g., columns, schema).": "Get structure and details of a specific table (e.g., columns, schema).",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Document": "Document",
"Table": "Table",
"Row Data": "Row Data",
"Row ID or Name": "Row ID or Name",
"Matching Columns": "Matching Columns",
"Search Column": "Search Column",
"Search Value": "Search Value",
"Max Tables": "Max Tables",
"Method": "Method",
"Headers": "Headers",
"Query Parameters": "Query Parameters",
"Body": "Body",
"No Error on Failure": "No Error on Failure",
"Timeout (in seconds)": "Timeout (in seconds)",
"Define the data for the new row based on table columns.": "Define the data for the new row based on table columns.",
"Maximum number of results to return.": "Maximum number of results to return.",
"Authorization headers are injected automatically from your connection.": "Authorization headers are injected automatically from your connection.",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"New Row Created": "New Row Created",
"Triggers when a new row is added to the selected table.": "Triggers when a new row is added to the selected table."
}

View File

@@ -0,0 +1,46 @@
{
"Create an API key in the [Coda Account dashboard](https://coda.io/account).": "Create an API key in the [Coda Account dashboard](https://coda.io/account).",
"Create Row": "Create Row",
"Update Row": "更新行",
"Upsert Row": "Upsert Row",
"Find Row(s)": "Find Row(s)",
"Get Row": "获取行",
"List Table(s)": "List Table(s)",
"Get Table": "Get Table",
"Custom API Call": "自定义 API 呼叫",
"Creates a new row in the selected table.": "Creates a new row in the selected table.",
"Updates an existing row in the selected table.": "Updates an existing row in the selected table.",
"Creates a new row or updates an existing one if it matches key columns.": "Creates a new row or updates an existing one if it matches key columns.",
"Find specific rows in the selected table using a column match search.": "Find specific rows in the selected table using a column match search.",
"Retrieves a single row by specified ID.": "Retrieves a single row by specified ID.",
"List tables in a selected document.": "List tables in a selected document.",
"Get structure and details of a specific table (e.g., columns, schema).": "Get structure and details of a specific table (e.g., columns, schema).",
"Make a custom API call to a specific endpoint": "将一个自定义 API 调用到一个特定的终点",
"Document": "Document",
"Table": "表",
"Row Data": "Row Data",
"Row ID or Name": "Row ID or Name",
"Matching Columns": "Matching Columns",
"Search Column": "Search Column",
"Search Value": "搜索值",
"Max Tables": "Max Tables",
"Method": "方法",
"Headers": "信头",
"Query Parameters": "查询参数",
"Body": "正文内容",
"Response is Binary ?": "Response is Binary ?",
"No Error on Failure": "失败时没有错误",
"Timeout (in seconds)": "超时(秒)",
"Define the data for the new row based on table columns.": "Define the data for the new row based on table columns.",
"Maximum number of results to return.": "Maximum number of results to return.",
"Authorization headers are injected automatically from your connection.": "授权头自动从您的连接中注入。",
"Enable for files like PDFs, images, etc..": "Enable for files like PDFs, images, etc..",
"GET": "获取",
"POST": "帖子",
"PATCH": "PATCH",
"PUT": "弹出",
"DELETE": "删除",
"HEAD": "黑色",
"New Row Created": "New Row Created",
"Triggers when a new row is added to the selected table.": "Triggers when a new row is added to the selected table."
}

View File

@@ -0,0 +1,45 @@
import { PieceAuth, createPiece } from '@activepieces/pieces-framework';
import { findRowAction } from './lib/actions/find-row';
import { createRowAction } from './lib/actions/create-row';
import { upsertRowAction } from './lib/actions/upsert-row';
import { updateRowAction } from './lib/actions/update-row';
import { newRowCreatedTrigger } from './lib/triggers/new-row-created';
import { PieceCategory } from '@activepieces/shared';
import { getRowAction } from './lib/actions/get-row';
import { listTablesAction } from './lib/actions/list-tables';
import { getTableAction } from './lib/actions/get-table';
import { createCustomApiCallAction } from '@activepieces/pieces-common';
import { CODA_BASE_URL } from './lib/common/types';
export const codaAuth = PieceAuth.SecretText({
displayName: 'Coda API Key',
description: `Create an API key in the [Coda Account dashboard](https://coda.io/account).`,
required: true,
});
export const coda = createPiece({
displayName: 'Coda',
logoUrl: 'https://cdn.activepieces.com/pieces/coda.png',
categories: [PieceCategory.PRODUCTIVITY],
auth: codaAuth,
authors: ['onyedikachi-david', 'kishanprmr','rimjhimyadav'],
actions: [
createRowAction,
updateRowAction,
upsertRowAction,
findRowAction,
getRowAction,
listTablesAction,
getTableAction,
createCustomApiCallAction({
auth:codaAuth,
baseUrl:()=>CODA_BASE_URL,
authMapping: async (auth) => ({
Authorization: `Bearer ${auth.secret_text}`,
}),
})
],
triggers: [newRowCreatedTrigger],
});

View File

@@ -0,0 +1,52 @@
import { createAction } from '@activepieces/pieces-framework';
import { codaAuth } from '../..';
import { codaClient } from '../common/types';
import { docIdDropdown, tableIdDropdown, tableRowsDynamicProps } from '../common/props';
import { isNil } from '@activepieces/shared';
export const createRowAction = createAction({
auth: codaAuth,
name: 'create-row',
displayName: 'Create Row',
description: 'Creates a new row in the selected table.',
props: {
docId: docIdDropdown,
tableId: tableIdDropdown,
rowData: tableRowsDynamicProps,
},
async run(context) {
const { docId, tableId, rowData } = context.propsValue;
const client = codaClient(context.auth);
const cells = Object.entries(rowData as Record<string, any>)
.filter(([, value]) => value !== undefined && value !== null && value !== '')
.map(([columnId, value]) => ({
column: columnId,
value: value,
}));
if (cells.length === 0) {
throw new Error('Provide any column values to create new row.');
}
const payload = {
rows: [
{
cells: cells,
},
],
};
const response = await client.mutateRows(docId, tableId, payload, {
disableParsing: false,
});
const rowId = response.addedRowIds?.[0];
if (isNil(rowId)) {
throw new Error(`Unexpected error occured : ${JSON.stringify(response)}`);
}
return { rowId };
},
});

View File

@@ -0,0 +1,49 @@
import { Property, createAction } from '@activepieces/pieces-framework';
import { codaAuth } from '../..';
import { CodaRow, codaClient } from '../common/types';
import { columnIdsDropdown, docIdDropdown, tableIdDropdown } from '../common/props';
export const findRowAction = createAction({
auth: codaAuth,
name: 'find-row',
displayName: 'Find Row(s)',
description: 'Find specific rows in the selected table using a column match search.',
props: {
docId: docIdDropdown,
tableId: tableIdDropdown,
searchColumn: columnIdsDropdown('Search Column', true),
searchValue: Property.ShortText({
displayName: 'Search Value',
required: true,
}),
},
async run(context) {
const { docId, tableId, searchColumn, searchValue } = context.propsValue;
const client = codaClient(context.auth);
const matchedRows: CodaRow[] = [];
let nextPageToken: string | undefined = undefined;
do {
const response = await client.listRows(docId, tableId, {
query: `${searchColumn}:${JSON.stringify(searchValue)}`,
sortBy: 'natural',
useColumnNames: true,
valueFormat: 'simpleWithArrays',
visibleOnly: true,
limit: 100,
pageToken: nextPageToken,
});
if (response.items) {
matchedRows.push(...response.items);
}
nextPageToken = response.nextPageToken;
} while (nextPageToken);
return {
found: matchedRows.length > 0,
result: matchedRows,
};
},
});

View File

@@ -0,0 +1,28 @@
import { Property, createAction } from '@activepieces/pieces-framework';
import { codaAuth } from '../..';
import { codaClient } from '../common/types';
import { docIdDropdown, tableIdDropdown } from '../common/props';
export const getRowAction = createAction({
auth: codaAuth,
name: 'get-row',
displayName: 'Get Row',
description: 'Retrieves a single row by specified ID.',
props: {
docId: docIdDropdown,
tableId: tableIdDropdown,
rowIdOrName: Property.ShortText({
displayName: 'Row ID or Name',
required: true,
}),
},
async run(context) {
const { docId, tableId, rowIdOrName } = context.propsValue;
const client = codaClient(context.auth);
return await client.getRow(docId, tableId, rowIdOrName, {
useColumnNames: true,
valueFormat: 'simpleWithArrays',
});
},
});

View File

@@ -0,0 +1,21 @@
import { codaAuth } from '../../index';
import { createAction } from '@activepieces/pieces-framework';
import { docIdDropdown, tableIdDropdown } from '../common/props';
import { codaClient } from '../common/types';
export const getTableAction = createAction({
auth: codaAuth,
name: 'get-table',
displayName: 'Get Table',
description: 'Get structure and details of a specific table (e.g., columns, schema).',
props: {
docId: docIdDropdown,
tableId: tableIdDropdown,
},
async run(context) {
const { docId, tableId } = context.propsValue;
const client = codaClient(context.auth);
return await client.getTableDetails(docId, tableId, {});
},
});

View File

@@ -0,0 +1,47 @@
import { Property, createAction } from '@activepieces/pieces-framework';
import { codaAuth } from '../..';
import { CodaTableReference, codaClient } from '../common/types';
import { docIdDropdown } from '../common/props';
export const listTablesAction = createAction({
auth: codaAuth,
name: 'list-tables',
displayName: 'List Table(s)',
description: 'List tables in a selected document.',
props: {
docId: docIdDropdown,
max: Property.Number({
displayName: 'Max Tables',
description: 'Maximum number of results to return.',
required: true,
}),
},
async run(context) {
const { docId, max } = context.propsValue;
const client = codaClient(context.auth);
const allTables: CodaTableReference[] = [];
let nextPageToken: string | undefined = undefined;
do {
const response = await client.listTables(docId as string, {
limit: 100,
sortBy: 'name',
tableTypes: 'table',
pageToken: nextPageToken,
});
if (response.items) {
allTables.push(...response.items);
}
nextPageToken = response.nextPageToken;
} while (nextPageToken && allTables.length < max);
if (allTables.length > max) allTables.length = max;
return {
found: allTables.length > 0,
result: allTables,
};
},
});

View File

@@ -0,0 +1,50 @@
import { Property, createAction } from '@activepieces/pieces-framework';
import { codaAuth } from '../..';
import { codaClient } from '../common/types';
import { docIdDropdown, tableIdDropdown, tableRowsDynamicProps } from '../common/props';
import { isNil } from '@activepieces/shared';
export const updateRowAction = createAction({
auth: codaAuth,
name: 'update-row',
displayName: 'Update Row',
description: 'Updates an existing row in the selected table.',
props: {
docId: docIdDropdown,
tableId: tableIdDropdown,
rowIdOrName: Property.ShortText({
displayName: 'Row ID or Name',
required: true,
}),
rowData: tableRowsDynamicProps,
},
async run(context) {
const { docId, tableId, rowIdOrName, rowData } = context.propsValue;
const client = codaClient(context.auth);
const cells = Object.entries(rowData as Record<string, any>)
.filter(([, value]) => value !== undefined && value !== null && value !== '')
.map(([columnId, value]) => ({
column: columnId,
value: value,
}));
const payload = {
row: {
cells: cells,
},
};
const response = await client.updateRow(docId, tableId, rowIdOrName, payload, {
disableParsing: false,
});
const rowId = response.id;
if (isNil(rowId)) {
throw new Error(`Unexpected error occured : ${JSON.stringify(response)}`);
}
return { rowId };
},
});

View File

@@ -0,0 +1,52 @@
import { createAction } from '@activepieces/pieces-framework';
import { codaAuth } from '../..';
import { codaClient } from '../common/types';
import {
columnIdsDropdown,
docIdDropdown,
tableIdDropdown,
tableRowsDynamicProps,
} from '../common/props';
export const upsertRowAction = createAction({
auth: codaAuth,
name: 'upsert-row',
displayName: 'Upsert Row',
description: 'Creates a new row or updates an existing one if it matches key columns.',
props: {
docId: docIdDropdown,
tableId: tableIdDropdown,
keyColumns: columnIdsDropdown('Matching Columns', false),
rowData: tableRowsDynamicProps,
},
async run(context) {
const { docId, tableId, rowData, keyColumns } = context.propsValue;
const client = codaClient(context.auth);
const cells = Object.entries(rowData as Record<string, any>)
.filter(([, value]) => value !== undefined && value !== null && value !== '')
.map(([columnId, value]) => ({
column: columnId,
value: value,
}));
const payload = {
rows: [
{
cells: cells,
},
],
keyColumns: keyColumns as string[],
};
const response = await client.mutateRows(docId, tableId, payload, {
disableParsing: false,
});
if (!response.requestId) {
throw new Error(`Unexpected error occured : ${JSON.stringify(response)}`);
}
return { success: true };
},
});

View File

@@ -0,0 +1,249 @@
import { DropdownOption, DynamicPropsValue, Property } from '@activepieces/pieces-framework';
import { codaClient, CodaTableColumn } from './types';
import { codaAuth } from '../..';
export const docIdDropdown = Property.Dropdown({
auth: codaAuth,
displayName: 'Document',
required: true,
refreshers: [],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Connect your Coda account first.',
options: [],
};
}
const client = codaClient(auth);
const docs: DropdownOption<string>[] = [];
let nextPageToken: string | undefined = undefined;
try {
do {
const response = await client.listDocs({
limit: 100,
pageToken: nextPageToken,
});
if (response.items) {
docs.push(
...response.items.map((doc) => ({
label: doc.name,
value: doc.id,
})),
);
}
nextPageToken = response.nextPageToken;
} while (nextPageToken);
return {
disabled: false,
options: docs,
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Error listing docs, please check connection or API key permissions.',
};
}
},
});
export const tableIdDropdown = Property.Dropdown({
auth: codaAuth,
displayName: 'Table',
required: true,
refreshers: ['docId'],
options: async ({ auth, docId }) => {
if (!auth || !docId) {
return {
disabled: true,
placeholder: !auth ? 'Connect your Coda account first.' : 'Select a document first.',
options: [],
};
}
const client = codaClient(auth);
const tables: DropdownOption<string>[] = [];
let nextPageToken: string | undefined = undefined;
try {
do {
const response = await client.listTables(docId as unknown as string, {
limit: 100,
pageToken: nextPageToken,
tableTypes: 'table',
});
if (response.items) {
tables.push(
...response.items.map((table) => ({
label: table.name,
value: table.id,
})),
);
}
nextPageToken = response.nextPageToken;
} while (nextPageToken);
return {
disabled: false,
options: tables,
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Error listing tables. Check document ID or permissions.',
};
}
},
});
export const tableRowsDynamicProps = Property.DynamicProperties({
auth: codaAuth,
displayName: 'Row Data',
description: 'Define the data for the new row based on table columns.',
required: true,
refreshers: ['docId', 'tableId'],
props: async ({ tableId, auth, docId }) => {
if (!auth || !docId || !tableId) {
return {};
}
const client = codaClient(auth);
const fields: DynamicPropsValue = {};
try {
const columns: CodaTableColumn[] = [];
let nextPageToken: string | undefined = undefined;
do {
const columnsResponse = await client.listColumns(
docId as unknown as string,
tableId as unknown as string,
{
limit: 100,
pageToken: nextPageToken,
},
);
if (columnsResponse.items) {
columns.push(...columnsResponse.items);
}
nextPageToken = columnsResponse.nextPageToken;
} while (nextPageToken);
if (columns.length > 0) {
for (const column of columns) {
if (column.calculated) {
continue;
}
switch (column.format.type.toLowerCase()) {
case 'text':
case 'link':
case 'email':
fields[column.id] = Property.ShortText({
displayName: column.name,
required: false,
});
break;
case 'select':
case 'lookup':
fields[column.id] = Property.ShortText({
displayName: column.name,
required: false,
description: column.format.isArray
? 'Provide options as comma seprated values.'
: '',
});
break;
case 'number':
case 'currency':
case 'percent':
case 'slider':
case 'scale':
case 'duration':
fields[column.id] = Property.Number({
displayName: column.name,
required: false,
});
break;
case 'date':
case 'dateTime':
case 'time':
fields[column.id] = Property.DateTime({
displayName: column.name,
required: false,
});
break;
case 'checkbox':
fields[column.id] = Property.Checkbox({
displayName: column.name,
required: false,
});
break;
default:
break;
}
}
}
return fields;
} catch (error) {
console.error('Coda: Failed to fetch table columns for dynamic properties:', error);
return {};
}
},
});
export const columnIdsDropdown = (displayName: string, singleSelect = true) => {
const dropdownType = singleSelect ? Property.Dropdown : Property.MultiSelectDropdown;
return dropdownType({
auth: codaAuth,
displayName,
required: true,
refreshers: ['docId', 'tableId'],
options: async ({ auth, docId, tableId }) => {
if (!auth || !docId || !tableId) {
return {
disabled: true,
placeholder: 'Connect your Coda account first.',
options: [],
};
}
const client = codaClient(auth);
const columns: DropdownOption<string>[] = [];
let nextPageToken: string | undefined = undefined;
try {
do {
const response = await client.listColumns(
docId as unknown as string,
tableId as unknown as string,
{
limit: 100,
pageToken: nextPageToken,
},
);
if (response.items) {
columns.push(
...response.items.map((column) => ({
label: column.name,
value: column.id,
})),
);
}
nextPageToken = response.nextPageToken;
} while (nextPageToken);
return {
disabled: false,
options: columns,
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Error listing docs, please check connection or API key permissions.',
};
}
},
});
};

View File

@@ -0,0 +1,366 @@
import { HttpMethod, httpClient, HttpRequest, AuthenticationType } from "@activepieces/pieces-common";
import { AppConnectionValueForAuthProperty } from "@activepieces/pieces-framework";
import { codaAuth } from "../..";
export const CODA_BASE_URL = "https://coda.io/apis/v1";
// --- Common Reference Types ---
export interface CodaObjectReference {
id: string;
type: string;
href: string;
name?: string; // Common but not always present in all reference types
}
export interface CodaPageReference extends CodaObjectReference {
type: 'page'; // More specific type if known
// Add other page-specific reference fields if needed
}
export interface CodaColumnReference extends CodaObjectReference {
type: 'column'; // More specific type if known
// Add other column-specific reference fields if needed
}
// --- Table Related Interfaces ---
export interface CodaTableReference extends CodaObjectReference {
type: 'table' | 'view'; // More specific, can be table or view reference
name: string; // Name is required for table reference as per GetTable response
}
export interface CodaListTablesResponse {
items: CodaTableReference[];
href?: string;
nextPageToken?: string;
nextPageLink?: string;
}
export interface CodaSort {
column: CodaColumnReference | string; // API might return ID or full reference
direction: 'ascending' | 'descending';
}
// Interface for the format of a column
export interface CodaColumnFormat {
type: string; // e.g., "text", "number", "date", "person", "lookup", "checkbox", "currency", "percent", "slider", "scale", "selectList", "multiSelectList", "button"
// Other format-specific properties can be added here if needed for dynamic prop generation
// For example, for selectList:
// options?: { name: string, id?: string }[];
// For lookup:
// table?: CodaTableReference;
isArray?:boolean
}
// Interface for a single column in the getTableDetails response
export interface CodaTableColumn {
id: string; // Column ID, e.g., "c-123abcDEF"
type: "column";
href: string;
name: string; // User-visible name of the column
format: CodaColumnFormat;
display?: boolean; // As per docs, optional
calculated?: boolean; // Whether this is a calculated column
formula?: string; // The formula if it's a calculated column
defaultValue?: string; // As per docs, it's a formula string
// Add other relevant column properties if necessary
}
export interface CodaListColumnsResponse {
items: CodaTableColumn[];
href?: string;
nextPageToken?: string;
nextPageLink?: string;
}
export interface CodaGetTableDetailsResponse {
id: string;
type: "table"; // This specific endpoint returns "table"
tableType: "table" | "view";
href: string;
name: string;
parent: CodaPageReference;
browserLink: string;
displayColumn: CodaColumnReference; // This is a reference, not the full column object
rowCount: number;
sorts: CodaSort[];
layout: string; // Enum of layout types, string for simplicity
createdAt: string; // date-time
updatedAt: string; // date-time
parentTable?: CodaTableReference; // Optional, for views
filter?: any; // object, structure can be complex
}
// --- Row Related Interfaces ---
export interface CodaRow {
id: string;
type: "row";
href: string;
name: string;
index: number;
browserLink: string;
createdAt: string;
updatedAt: string;
values: Record<string, any>;
parentTable?: CodaTableReference;
}
export interface CodaGetRowResponse extends CodaRow {
parent: CodaTableReference;
}
export interface CodaListRowsResponse {
items: CodaRow[];
href?: string;
nextPageToken?: string;
nextPageLink?: string;
nextSyncToken?: string;
}
// For creating/updating rows
export interface CodaCellEdit {
column: string; // Column ID or Name
value: any;
}
export interface CodaRowEdit {
cells: CodaCellEdit[];
}
export interface CodaMutateRowsPayload {
rows: CodaRowEdit[];
keyColumns?: string[]; // Column IDs or Names for upsert
}
export interface CodaMutateRowsResponse {
requestId: string;
addedRowIds?: string[];
updatedRowIds?: string[]; // API docs for POST say addedRowIds, but PUT might have updatedRowIds. Let's be broad.
}
export interface CodaUpdateRowPayload { // Used for PUT (update single row)
row: CodaRowEdit;
}
export interface CodaUpdateRowResponse {
requestId: string;
id: string; // ID of the updated row
}
// --- Document Related Interfaces ---
export interface CodaDocIcon {
name: string;
type: string;
browserLink: string;
}
export interface CodaDocSize {
totalRowCount: number;
tableAndViewCount: number;
pageCount: number;
overApiSizeLimit: boolean;
}
export interface CodaDocSourceDocReference {
id: string;
type: "doc";
browserLink: string;
href: string;
}
export interface CodaDocPublished {
browserLink: string;
discoverable: boolean;
earnCredit: boolean;
mode: "view" | "play" | "edit";
categories: { name: string }[]; // Simplified, assuming only name is needed for now
description?: string;
imageLink?: string;
}
export interface CodaDoc {
id: string;
type: "doc";
href: string;
browserLink: string;
name: string;
owner: string; // email
ownerName: string;
createdAt: string; // date-time
updatedAt: string; // date-time
workspaceId: string; // Deprecated but present
folderId: string; // Deprecated but present
workspace: CodaObjectReference; // WorkspaceReference
folder: CodaObjectReference; // FolderReference
icon?: CodaDocIcon;
docSize?: CodaDocSize;
sourceDoc?: CodaDocSourceDocReference;
published?: CodaDocPublished;
}
export interface CodaListDocsResponse {
items: CodaDoc[];
href?: string;
nextPageToken?: string;
nextPageLink?: string;
}
// --- API Client ---
export interface CodaAPIClient {
listTables: (docId: string, params?: { limit?: number; sortBy?: string; tableTypes?: string, pageToken?: string }) => Promise<CodaListTablesResponse>;
getTableDetails: (docId: string, tableIdOrName: string, params?: { useUpdatedTableLayouts?: boolean }) => Promise<CodaGetTableDetailsResponse>;
listColumns: (docId: string, tableIdOrName: string, params?: { limit?: number; pageToken?: string; visibleOnly?: boolean; }) => Promise<CodaListColumnsResponse>;
getRow: (docId: string, tableIdOrName: string, rowIdOrName: string, params?: { useColumnNames?: boolean; valueFormat?: string }) => Promise<CodaGetRowResponse>;
listRows: (docId: string, tableIdOrName: string, params?: {
query?: string;
sortBy?: string;
useColumnNames?: boolean;
valueFormat?: string;
visibleOnly?: boolean;
limit?: number;
pageToken?: string;
syncToken?: string;
}) => Promise<CodaListRowsResponse>;
mutateRows: (docId: string, tableIdOrName: string, payload: CodaMutateRowsPayload, params?: { disableParsing?: boolean }) => Promise<CodaMutateRowsResponse>;
updateRow: (docId: string, tableIdOrName: string, rowIdOrName: string, payload: CodaUpdateRowPayload, params?: { disableParsing?: boolean }) => Promise<CodaUpdateRowResponse>;
listDocs: (params?: {
isOwner?: boolean;
isPublished?: boolean;
query?: string;
sourceDoc?: string;
isStarred?: boolean;
inGallery?: boolean;
workspaceId?: string;
folderId?: string;
limit?: number;
pageToken?: string;
}) => Promise<CodaListDocsResponse>;
}
export const codaClient = ({secret_text}: AppConnectionValueForAuthProperty<typeof codaAuth>): CodaAPIClient => {
const makeRequest = async <T>(request: Omit<HttpRequest, 'authentication'> & { body?: any }): Promise<T> => {
const response = await httpClient.sendRequest<T>({
...request,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: secret_text,
}
});
return response.body;
}
return {
listTables: async (docId, params) => {
const queryParams: Record<string, string | number | boolean> = {};
if (params?.limit) queryParams['limit'] = params.limit.toString();
if (params?.sortBy) queryParams['sortBy'] = params.sortBy;
if (params?.tableTypes) queryParams['tableTypes'] = params.tableTypes;
if (params?.pageToken) queryParams['pageToken'] = params.pageToken;
return makeRequest<CodaListTablesResponse>({
method: HttpMethod.GET,
url: `${CODA_BASE_URL}/docs/${docId}/tables`,
queryParams: Object.fromEntries(Object.entries(queryParams).map(([k, v]) => [k, String(v)])),
});
},
getTableDetails: async (docId, tableIdOrName, params) => {
const queryParams: Record<string, string | boolean> = {};
if (params?.useUpdatedTableLayouts !== undefined) queryParams['useUpdatedTableLayouts'] = params.useUpdatedTableLayouts;
return makeRequest<CodaGetTableDetailsResponse>({
method: HttpMethod.GET,
url: `${CODA_BASE_URL}/docs/${docId}/tables/${encodeURIComponent(tableIdOrName)}`,
queryParams: Object.fromEntries(Object.entries(queryParams).map(([k, v]) => [k, String(v)])),
});
},
listColumns: async (docId, tableIdOrName, params) => {
const queryParams: Record<string, string | number | boolean> = {};
if (params?.limit) queryParams['limit'] = params.limit;
if (params?.pageToken) queryParams['pageToken'] = params.pageToken;
if (params?.visibleOnly !== undefined) queryParams['visibleOnly'] = params.visibleOnly;
return makeRequest<CodaListColumnsResponse>({
method: HttpMethod.GET,
url: `${CODA_BASE_URL}/docs/${docId}/tables/${encodeURIComponent(tableIdOrName)}/columns`,
queryParams: Object.fromEntries(Object.entries(queryParams).map(([k,v])=>[k,String(v)])),
});
},
getRow: async (docId, tableIdOrName, rowIdOrName, params) => {
const queryParams: Record<string, string | boolean> = {};
if (params?.useColumnNames !== undefined) queryParams['useColumnNames'] = params.useColumnNames;
if (params?.valueFormat) queryParams['valueFormat'] = params.valueFormat;
return makeRequest<CodaGetRowResponse>({
method: HttpMethod.GET,
url: `${CODA_BASE_URL}/docs/${docId}/tables/${encodeURIComponent(tableIdOrName)}/rows/${encodeURIComponent(rowIdOrName)}`,
queryParams: Object.fromEntries(Object.entries(queryParams).map(([k, v]) => [k, String(v)])),
});
},
listRows: async (docId, tableIdOrName, params) => {
const queryParams: Record<string, string | number | boolean> = {};
if (params?.query) queryParams['query'] = params.query;
if (params?.sortBy) queryParams['sortBy'] = params.sortBy;
if (params?.useColumnNames !== undefined) queryParams['useColumnNames'] = params.useColumnNames;
if (params?.valueFormat) queryParams['valueFormat'] = params.valueFormat;
if (params?.visibleOnly !== undefined) queryParams['visibleOnly'] = params.visibleOnly;
if (params?.limit) queryParams['limit'] = params.limit;
if (params?.pageToken) queryParams['pageToken'] = params.pageToken;
if (params?.syncToken) queryParams['syncToken'] = params.syncToken;
return makeRequest<CodaListRowsResponse>({
method: HttpMethod.GET,
url: `${CODA_BASE_URL}/docs/${docId}/tables/${encodeURIComponent(tableIdOrName)}/rows`,
queryParams: Object.fromEntries(
Object.entries(queryParams).map(([key, value]) => [key, String(value)])
),
});
},
mutateRows: async (docId, tableIdOrName, payload, params) => {
const queryParams: Record<string, string | boolean> = {};
if (params?.disableParsing !== undefined) queryParams['disableParsing'] = params.disableParsing;
return makeRequest<CodaMutateRowsResponse>({
method: HttpMethod.POST,
url: `${CODA_BASE_URL}/docs/${docId}/tables/${encodeURIComponent(tableIdOrName)}/rows`,
body: payload,
queryParams: Object.fromEntries(Object.entries(queryParams).map(([k, v]) => [k, String(v)])),
headers: {
'Content-Type': 'application/json'
}
});
},
updateRow: async (docId, tableIdOrName, rowIdOrName, payload, params) => {
const queryParams: Record<string, string | boolean> = {};
if (params?.disableParsing !== undefined) queryParams['disableParsing'] = params.disableParsing;
return makeRequest<CodaUpdateRowResponse>({
method: HttpMethod.PUT,
url: `${CODA_BASE_URL}/docs/${docId}/tables/${encodeURIComponent(tableIdOrName)}/rows/${encodeURIComponent(rowIdOrName)}`,
body: payload,
queryParams: Object.fromEntries(Object.entries(queryParams).map(([k, v]) => [k, String(v)])),
headers: {
'Content-Type': 'application/json'
}
});
},
listDocs: async (params) => {
const queryParams: Record<string, string | number | boolean> = {};
if (params?.isOwner !== undefined) queryParams['isOwner'] = params.isOwner;
if (params?.isPublished !== undefined) queryParams['isPublished'] = params.isPublished;
if (params?.query) queryParams['query'] = params.query;
if (params?.sourceDoc) queryParams['sourceDoc'] = params.sourceDoc;
if (params?.isStarred !== undefined) queryParams['isStarred'] = params.isStarred;
if (params?.inGallery !== undefined) queryParams['inGallery'] = params.inGallery;
if (params?.workspaceId) queryParams['workspaceId'] = params.workspaceId;
if (params?.folderId) queryParams['folderId'] = params.folderId;
if (params?.limit) queryParams['limit'] = params.limit;
if (params?.pageToken) queryParams['pageToken'] = params.pageToken;
return makeRequest<CodaListDocsResponse>({
method: HttpMethod.GET,
url: `${CODA_BASE_URL}/docs`,
queryParams: Object.fromEntries(
Object.entries(queryParams).map(([key, value]) => [key, String(value)])
),
});
}
};
};

View File

@@ -0,0 +1,102 @@
import {
AppConnectionValueForAuthProperty,
TriggerStrategy,
createTrigger,
} from '@activepieces/pieces-framework';
import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common';
import { codaAuth } from '../..';
import { CodaRow, codaClient } from '../common/types';
import dayjs from 'dayjs';
import { docIdDropdown, tableIdDropdown } from '../common/props';
type Props = {
tableId: string;
docId: string;
};
const polling: Polling<AppConnectionValueForAuthProperty<typeof codaAuth>, Props> = {
strategy: DedupeStrategy.TIMEBASED,
items: async ({ auth, propsValue, lastFetchEpochMS }) => {
const { tableId, docId } = propsValue;
const isTest = lastFetchEpochMS === 0;
const client = codaClient(auth);
const rows: CodaRow[] = [];
let nextPageToken: string | undefined = undefined;
// We will sort by createdAt to process in order. The API default is ascending.
do {
const response = await client.listRows(docId, tableId, {
sortBy: 'createdAt', // Default is ascending
valueFormat: 'simpleWithArrays',
useColumnNames: true,
limit: isTest ? 5 : 100,
pageToken: nextPageToken,
});
if (response.items) {
for (const row of response.items) {
rows.push(row);
}
}
if (isTest) break;
nextPageToken = response.nextPageToken;
} while (nextPageToken);
return rows.map((row) => {
return {
epochMilliSeconds: dayjs(row.createdAt).valueOf(),
data: row,
};
});
},
};
export const newRowCreatedTrigger = createTrigger({
auth: codaAuth,
name: 'new-row-created',
displayName: 'New Row Created',
description: 'Triggers when a new row is added to the selected table.',
props: {
docId: docIdDropdown,
tableId: tableIdDropdown,
},
type: TriggerStrategy.POLLING,
async onEnable(context) {
await pollingHelper.onEnable(polling, {
auth: context.auth,
store: context.store,
propsValue: context.propsValue,
});
},
async onDisable(context) {
await pollingHelper.onDisable(polling, {
auth: context.auth,
store: context.store,
propsValue: context.propsValue,
});
},
async test(context) {
return await pollingHelper.test(polling, context);
},
async run(context) {
return await pollingHelper.poll(polling, context);
},
sampleData: {
id: 'i-xxxxxxx',
type: 'row',
href: 'https://coda.io/apis/v1/docs/docId/tables/tableId/rows/rowId',
name: 'Sample Row Name',
index: 1,
browserLink: 'https://coda.io/d/docId/tableId#_rui-xxxxxxx',
createdAt: '2023-01-01T12:00:00.000Z',
updatedAt: '2023-01-01T12:00:00.000Z',
values: { 'c-columnId1': 'Sample Value', 'Column Name 2': 123 },
parentTable: {
id: 'grid-parentTableId123',
type: 'table',
name: 'Parent Table Name',
href: 'https://coda.io/apis/v1/docs/docId/tables/grid-parentTableId123',
},
},
});