Add Activepieces integration for workflow automation
- Add Activepieces fork with SmoothSchedule custom piece - Create integrations app with Activepieces service layer - Add embed token endpoint for iframe integration - Create Automations page with embedded workflow builder - Add sidebar visibility fix for embed mode - Add list inactive customers endpoint to Public API - Include SmoothSchedule triggers: event created/updated/cancelled - Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"extends": [
|
||||
"../../../../.eslintrc.base.json"
|
||||
],
|
||||
"ignorePatterns": [
|
||||
"!**/*"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"*.ts",
|
||||
"*.tsx",
|
||||
"*.js",
|
||||
"*.jsx"
|
||||
],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.ts",
|
||||
"*.tsx"
|
||||
],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.js",
|
||||
"*.jsx"
|
||||
],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# pieces-quickbase
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Building
|
||||
|
||||
Run `nx build pieces-quickbase` to build the library.
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "@activepieces/piece-quickbase",
|
||||
"version": "0.0.2",
|
||||
"type": "commonjs",
|
||||
"main": "./src/index.js",
|
||||
"types": "./src/index.d.ts",
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "pieces-quickbase",
|
||||
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "packages/pieces/community/quickbase/src",
|
||||
"projectType": "library",
|
||||
"release": {
|
||||
"version": {
|
||||
"manifestRootsToUpdate": [
|
||||
"dist/{projectRoot}"
|
||||
],
|
||||
"currentVersionResolver": "git-tag",
|
||||
"fallbackCurrentVersionResolver": "disk"
|
||||
}
|
||||
},
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/js:tsc",
|
||||
"outputs": [
|
||||
"{options.outputPath}"
|
||||
],
|
||||
"options": {
|
||||
"outputPath": "dist/packages/pieces/community/quickbase",
|
||||
"tsConfig": "packages/pieces/community/quickbase/tsconfig.lib.json",
|
||||
"packageJson": "packages/pieces/community/quickbase/package.json",
|
||||
"main": "packages/pieces/community/quickbase/src/index.ts",
|
||||
"assets": [
|
||||
"packages/pieces/community/quickbase/*.md",
|
||||
{
|
||||
"input": "packages/pieces/community/quickbase/src/i18n",
|
||||
"output": "./src/i18n",
|
||||
"glob": "**/!(i18n.json)"
|
||||
}
|
||||
],
|
||||
"buildableProjectDepsInPackageJsonType": "dependencies",
|
||||
"updateBuildableProjectDepsInPackageJson": true
|
||||
}
|
||||
},
|
||||
"nx-release-publish": {
|
||||
"options": {
|
||||
"packageRoot": "dist/{projectRoot}"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint",
|
||||
"outputs": [
|
||||
"{options.outputFile}"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"Realm Hostname": "Realm Hostname",
|
||||
"User Token": "Benutzer-Token",
|
||||
"Enter your Quickbase Realm Hostname (e.g., yourrealm.quickbase.com)": "Geben Sie Ihren Quickbase Realm Hostnamen ein (z.B. deinrealm.quickbase.com)",
|
||||
"Enter your Quickbase User Token": "Geben Sie Ihren Quickbase User Token ein",
|
||||
"\n## Quickbase Authentication Setup\n\n### 1. Get Your User Token\n- Log in to your Quickbase account\n- Go to **My Preferences** → **My User Information**\n- Click on **Manage User Tokens**\n- Click **New User Token**\n- Enter a name for your token and click **Create**\n- Copy the generated token (it will only be shown once)\n\n### 2. Required Permissions\nYour user token needs access to:\n- Read/write permissions for the apps and tables you want to use\n- Admin permissions for creating/deleting records (if needed)\n\n**S": "\n## Schnellbase-Authentifizierung einrichten\n\n### 1. Holen Sie sich Ihr Benutzertoken\n- Einloggen in Ihr Quickbase-Konto\n- Gehen Sie zu **Meine Einstellungen** → **Meine Benutzerinformationen**\n- Klicken Sie auf **Benutzertoken verwalten**\n- Klicken Sie auf **Neues Benutzerzeichen**\n- Geben Sie einen Namen für Ihr Token ein und klicken Sie auf **Erstellen**\n- Kopieren Sie das generierte Token (es wird nur einmal angezeigt)\n\n### 2. Benötigte Berechtigungen\nIhr Benutzertoken benötigt Zugriff auf:\n- Lese-/Schreibrechte für die Apps und Tabellen, die Sie verwenden möchten\n- Administratorrechte für das Erstellen/Löschen von Datensätzen (falls erforderlich)\n\n**Sicherheits-Hinweis:** Bewahren Sie Ihr Benutzertoken sicher - es bietet Zugriff auf Ihre Quickbase-Daten.\n",
|
||||
"Create Record": "Datensatz erstellen",
|
||||
"Update Record": "Datensatz aktualisieren",
|
||||
"Delete Record": "Datensatz löschen",
|
||||
"Find Record": "Datensatz finden",
|
||||
"Find or Create Record": "Datensatz suchen oder erstellen",
|
||||
"Create / Update Records From Array": "Datensätze aus Array erstellen / aktualisieren",
|
||||
"Custom API Call": "Eigener API-Aufruf",
|
||||
"Create a new record in a Quickbase table": "Neuen Datensatz in einer Quickbase-Tabelle erstellen",
|
||||
"Update an existing record in a Quickbase table": "Aktualisiere einen vorhandenen Datensatz in einer Quickbase-Tabelle",
|
||||
"Delete a record from a Quickbase table": "Datensatz aus einer Quickbase-Tabelle löschen",
|
||||
"Search for records in a Quickbase table using filters": "Suchen Sie nach Datensätzen in einer Quickbase-Tabelle mit Filtern",
|
||||
"Find an existing record or create a new one if not found": "Finde einen vorhandenen Eintrag oder erstelle einen neuen wenn nicht gefunden",
|
||||
"Bulk create or update multiple records based on a merge key": "Mehrere Datensätze erstellen oder aktualisieren basierend auf einem Merge Key",
|
||||
"Make a custom API call to a specific endpoint": "Einen benutzerdefinierten API-Aufruf an einen bestimmten Endpunkt machen",
|
||||
"App": "App",
|
||||
"Table": "Tisch",
|
||||
"Field Values": "Feldwerte",
|
||||
"Record": "Datensatz",
|
||||
"Filters": "Filter",
|
||||
"Sort Field": "Sortierfeld",
|
||||
"Sort Order": "Sortierung",
|
||||
"Maximum Records": "Maximale Datensätze",
|
||||
"Merge Field": "Merge Feld",
|
||||
"Fields": "Felder",
|
||||
"Records": "Datensätze",
|
||||
"Merge Behavior": "Merge Verhalten",
|
||||
"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)",
|
||||
"Select the Quickbase app": "Wählen Sie die Quickbase-App",
|
||||
"Select the table": "Tabelle auswählen",
|
||||
"Select and set values for table fields": "Wählen und setzen Sie Werte für Tabellenfelder",
|
||||
"Select a record from the table": "Wählen Sie einen Datensatz aus der Tabelle",
|
||||
"Filter criteria to find records. Use field names or field IDs as keys.": "Kriterien filtern, um Datensätze zu finden. Feldnamen oder Feld-IDs als Schlüssel verwenden.",
|
||||
"Field to sort records by (optional)": "Feld zum Sortieren der Datensätze nach (optional)",
|
||||
"Order to sort records": "Sortieren von Datensätzen",
|
||||
"Maximum number of records to return": "Maximale Anzahl der zurückzusenden Datensätze",
|
||||
"Field to use for matching existing records (for upsert operations)": "Feld für die Übereinstimmung mit existierenden Datensätzen (für Upsert-Operationen)",
|
||||
"Map the fields to update. Use field names or field IDs.": "Die zu aktualisierenden Felder zuordnen. Feldnamen oder Feld-IDs verwenden.",
|
||||
"Array of records to create or update": "Anordnung der zu erstellenden oder aktualisierenden Datensätze",
|
||||
"How to handle existing records when upserting": "Umgang mit existierenden Datensätzen beim Hochladen",
|
||||
"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..",
|
||||
"Ascending (A-Z, 1-9)": "Aufsteigend (A-Z, 1-9)",
|
||||
"Descending (Z-A, 9-1)": "Absteigend (Z-A, 9-1)",
|
||||
"Merge and overwrite all fields": "Alle Felder zusammenführen und überschreiben",
|
||||
"Merge and update only provided fields": "Nur angegebene Felder zusammenführen und aktualisieren",
|
||||
"Always create new records (no merge)": "Immer neue Datensätze erstellen (keine Zusammenführung)",
|
||||
"GET": "ERHALTEN",
|
||||
"POST": "POST",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "LÖSCHEN",
|
||||
"HEAD": "HEAD",
|
||||
"New Record": "Neuer Datensatz",
|
||||
"New or Updated Record": "Neuer oder aktualisierter Datensatz",
|
||||
"Triggers when a new record is created in a Quickbase table": "Löst aus, wenn ein neuer Datensatz in einer Quickbase-Tabelle erstellt wird",
|
||||
"Triggers when a record is created or updated in a Quickbase table": "Löst aus, wenn ein Datensatz in einer Quickbase-Tabelle erstellt oder aktualisiert wird"
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"Realm Hostname": "Realm Hostname",
|
||||
"User Token": "Token de usuario",
|
||||
"Enter your Quickbase Realm Hostname (e.g., yourrealm.quickbase.com)": "Introduzca su nombre de host de Realm de Quickbase (por ejemplo, turealm.quickbase.com)",
|
||||
"Enter your Quickbase User Token": "Introduzca su Token de usuario de Quickbase",
|
||||
"\n## Quickbase Authentication Setup\n\n### 1. Get Your User Token\n- Log in to your Quickbase account\n- Go to **My Preferences** → **My User Information**\n- Click on **Manage User Tokens**\n- Click **New User Token**\n- Enter a name for your token and click **Create**\n- Copy the generated token (it will only be shown once)\n\n### 2. Required Permissions\nYour user token needs access to:\n- Read/write permissions for the apps and tables you want to use\n- Admin permissions for creating/deleting records (if needed)\n\n**S": "\n## Quickbase Authentication Setup\n\n### 1. Get Your User Token\n- Log in to your Quickbase account\n- Go to **My Preferences** → **My User Information**\n- Click on **Manage User Tokens**\n- Click **New User Token**\n- Enter a name for your token and click **Create**\n- Copy the generated token (it will only be shown once)\n\n### 2. Required Permissions\nYour user token needs access to:\n- Read/write permissions for the apps and tables you want to use\n- Admin permissions for creating/deleting records (if needed)\n\n**Security Note:** Keep your user token secure - it provides access to your Quickbase data.\n",
|
||||
"Create Record": "Crear registro",
|
||||
"Update Record": "Actualizar registro",
|
||||
"Delete Record": "Eliminar registro",
|
||||
"Find Record": "Buscar registro",
|
||||
"Find or Create Record": "Buscar o crear registro",
|
||||
"Create / Update Records From Array": "Crear / Actualizar registros desde matriz",
|
||||
"Custom API Call": "Llamada API personalizada",
|
||||
"Create a new record in a Quickbase table": "Crear un nuevo registro en una tabla de Quickbase",
|
||||
"Update an existing record in a Quickbase table": "Actualizar un registro existente en una tabla de Quickbase",
|
||||
"Delete a record from a Quickbase table": "Eliminar un registro de una tabla de Quickbase",
|
||||
"Search for records in a Quickbase table using filters": "Buscar registros en una tabla de Quickbase usando filtros",
|
||||
"Find an existing record or create a new one if not found": "Encontrar un registro existente o crear uno nuevo si no se encuentra",
|
||||
"Bulk create or update multiple records based on a merge key": "Crear o actualizar múltiples registros en masa basándose en una clave de fusión",
|
||||
"Make a custom API call to a specific endpoint": "Hacer una llamada API personalizada a un extremo específico",
|
||||
"App": "App",
|
||||
"Table": "Tabla",
|
||||
"Field Values": "Valores de campo",
|
||||
"Record": "Grabar",
|
||||
"Filters": "Filtros",
|
||||
"Sort Field": "Ordenar campo",
|
||||
"Sort Order": "Ordenar",
|
||||
"Maximum Records": "Máximo de registros",
|
||||
"Merge Field": "Fusionar Campo",
|
||||
"Fields": "Campos",
|
||||
"Records": "Registros",
|
||||
"Merge Behavior": "Combinar comportamiento",
|
||||
"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)",
|
||||
"Select the Quickbase app": "Selecciona la aplicación de Quickbase",
|
||||
"Select the table": "Seleccione la tabla",
|
||||
"Select and set values for table fields": "Seleccionar y establecer valores para los campos de tabla",
|
||||
"Select a record from the table": "Seleccione un registro de la tabla",
|
||||
"Filter criteria to find records. Use field names or field IDs as keys.": "Filtrar criterios para encontrar registros. Utilice nombres de campos o identificadores de campo como claves.",
|
||||
"Field to sort records by (optional)": "Campo para ordenar registros por (opcional)",
|
||||
"Order to sort records": "Ordenar registros",
|
||||
"Maximum number of records to return": "Número máximo de registros a devolver",
|
||||
"Field to use for matching existing records (for upsert operations)": "Campo a usar para coincidir registros existentes (para operaciones de actualización)",
|
||||
"Map the fields to update. Use field names or field IDs.": "Mapear los campos a actualizar. Utilice nombres de campos o ID de campos.",
|
||||
"Array of records to create or update": "Arreglo de registros para crear o actualizar",
|
||||
"How to handle existing records when upserting": "Cómo manejar registros existentes al actualizar",
|
||||
"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 PDF, imágenes, etc.",
|
||||
"Ascending (A-Z, 1-9)": "Ascendente (A-Z, 1-9)",
|
||||
"Descending (Z-A, 9-1)": "Descendente (Z-A, 9-1)",
|
||||
"Merge and overwrite all fields": "Fusionar y sobrescribir todos los campos",
|
||||
"Merge and update only provided fields": "Fusionar y actualizar sólo los campos proporcionados",
|
||||
"Always create new records (no merge)": "Crear siempre nuevos registros (sin fusionar)",
|
||||
"GET": "RECOGER",
|
||||
"POST": "POST",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "BORRAR",
|
||||
"HEAD": "LIMPIO",
|
||||
"New Record": "Nuevo registro",
|
||||
"New or Updated Record": "Registro nuevo o actualizado",
|
||||
"Triggers when a new record is created in a Quickbase table": "Dispara cuando se crea un nuevo registro en una tabla de Quickbase",
|
||||
"Triggers when a record is created or updated in a Quickbase table": "Dispara cuando un registro es creado o actualizado en una tabla de Quickbase"
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"Realm Hostname": "Realm Hostname",
|
||||
"User Token": "Jeton d'utilisateur",
|
||||
"Enter your Quickbase Realm Hostname (e.g., yourrealm.quickbase.com)": "Entrez votre nom d'hôte du Realm Quickbase (par exemple, votrerealm.quickbase.com)",
|
||||
"Enter your Quickbase User Token": "Entrez votre jeton d'utilisateur Quickbase",
|
||||
"\n## Quickbase Authentication Setup\n\n### 1. Get Your User Token\n- Log in to your Quickbase account\n- Go to **My Preferences** → **My User Information**\n- Click on **Manage User Tokens**\n- Click **New User Token**\n- Enter a name for your token and click **Create**\n- Copy the generated token (it will only be shown once)\n\n### 2. Required Permissions\nYour user token needs access to:\n- Read/write permissions for the apps and tables you want to use\n- Admin permissions for creating/deleting records (if needed)\n\n**S": "\n## Quickbase Authentication Setup\n\n### 1. Get Your User Token\n- Log in to your Quickbase account\n- Go to **My Preferences** → **My User Information**\n- Click on **Manage User Tokens**\n- Click **New User Token**\n- Enter a name for your token and click **Create**\n- Copy the generated token (it will only be shown once)\n\n### 2. Required Permissions\nYour user token needs access to:\n- Read/write permissions for the apps and tables you want to use\n- Admin permissions for creating/deleting records (if needed)\n\n**Security Note:** Keep your user token secure - it provides access to your Quickbase data.\n",
|
||||
"Create Record": "Créer un enregistrement",
|
||||
"Update Record": "Mettre à jour l'enregistrement",
|
||||
"Delete Record": "Supprimer l'enregistrement",
|
||||
"Find Record": "Rechercher un enregistrement",
|
||||
"Find or Create Record": "Trouver ou créer un enregistrement",
|
||||
"Create / Update Records From Array": "Créer / Mettre à jour les enregistrements depuis un tableau",
|
||||
"Custom API Call": "Appel d'API personnalisé",
|
||||
"Create a new record in a Quickbase table": "Créer un nouvel enregistrement dans un tableau de base rapide",
|
||||
"Update an existing record in a Quickbase table": "Mettre à jour un enregistrement existant dans une table Quickbase",
|
||||
"Delete a record from a Quickbase table": "Supprimer un enregistrement d'une table de base rapide",
|
||||
"Search for records in a Quickbase table using filters": "Rechercher des enregistrements dans une table Quickbase à l'aide de filtres",
|
||||
"Find an existing record or create a new one if not found": "Trouver un enregistrement existant ou en créer un nouveau s'il n'est pas trouvé",
|
||||
"Bulk create or update multiple records based on a merge key": "Créer ou mettre à jour en bloc plusieurs enregistrements basés sur une clé de fusion",
|
||||
"Make a custom API call to a specific endpoint": "Passer un appel API personnalisé à un endpoint spécifique",
|
||||
"App": "Application",
|
||||
"Table": "Tableau",
|
||||
"Field Values": "Valeurs du champ",
|
||||
"Record": "Enregistrements",
|
||||
"Filters": "Filtres",
|
||||
"Sort Field": "Champ de tri",
|
||||
"Sort Order": "Ordre de tri",
|
||||
"Maximum Records": "Nombre maximum d'enregistrements",
|
||||
"Merge Field": "Champ de fusion",
|
||||
"Fields": "Champs",
|
||||
"Records": "Enregistrements",
|
||||
"Merge Behavior": "Comportement de fusion",
|
||||
"Method": "Méthode",
|
||||
"Headers": "Headers",
|
||||
"Query Parameters": "Paramètres de requête",
|
||||
"Body": "Body",
|
||||
"Response is Binary ?": "La réponse est Binaire ?",
|
||||
"No Error on Failure": "Aucune erreur en cas d'échec",
|
||||
"Timeout (in seconds)": "Délai d'expiration (en secondes)",
|
||||
"Select the Quickbase app": "Sélectionnez l'application Quickbase",
|
||||
"Select the table": "Sélectionnez la table",
|
||||
"Select and set values for table fields": "Sélectionner et définir des valeurs pour les champs du tableau",
|
||||
"Select a record from the table": "Sélectionnez un enregistrement dans la table",
|
||||
"Filter criteria to find records. Use field names or field IDs as keys.": "Filtrer les critères pour trouver les enregistrements. Utiliser les noms des champs ou les identifiants des champs comme clés.",
|
||||
"Field to sort records by (optional)": "Champ à trier les enregistrements par (optionnel)",
|
||||
"Order to sort records": "Ordre de tri des enregistrements",
|
||||
"Maximum number of records to return": "Nombre maximum d'enregistrements à retourner",
|
||||
"Field to use for matching existing records (for upsert operations)": "Champ à utiliser pour les enregistrements existants correspondants (pour les opérations de mise à jour)",
|
||||
"Map the fields to update. Use field names or field IDs.": "Mappez les champs à mettre à jour. Utilisez les noms de champs ou les identifiants de champs.",
|
||||
"Array of records to create or update": "Tableau des enregistrements à créer ou à mettre à jour",
|
||||
"How to handle existing records when upserting": "Comment gérer les enregistrements existants lors de l'insertion",
|
||||
"Authorization headers are injected automatically from your connection.": "Les Headers 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.",
|
||||
"Ascending (A-Z, 1-9)": "Ascendant (A-Z, 1-9)",
|
||||
"Descending (Z-A, 9-1)": "Décroissant (Z-A, 9-1)",
|
||||
"Merge and overwrite all fields": "Fusionner et écraser tous les champs",
|
||||
"Merge and update only provided fields": "Fusionner et mettre à jour uniquement les champs fournis",
|
||||
"Always create new records (no merge)": "Toujours créer de nouveaux enregistrements (sans fusion)",
|
||||
"GET": "GET",
|
||||
"POST": "POST",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "DELETE",
|
||||
"HEAD": "HEAD",
|
||||
"New Record": "Nouvel enregistrement",
|
||||
"New or Updated Record": "Nouvel enregistrement ou mis à jour",
|
||||
"Triggers when a new record is created in a Quickbase table": "Déclenche lorsqu'un nouvel enregistrement est créé dans une table de base rapide",
|
||||
"Triggers when a record is created or updated in a Quickbase table": "Déclenche lorsqu'un enregistrement est créé ou mis à jour dans une table de base rapide"
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"Realm Hostname": "Realm Hostname",
|
||||
"User Token": "User Token",
|
||||
"Enter your Quickbase Realm Hostname (e.g., yourrealm.quickbase.com)": "Quickbase Realm のホスト名を入力してください(例:yourrealm.quickbase.com)",
|
||||
"Enter your Quickbase User Token": "Quickbaseのユーザートークンを入力してください",
|
||||
"\n## Quickbase Authentication Setup\n\n### 1. Get Your User Token\n- Log in to your Quickbase account\n- Go to **My Preferences** → **My User Information**\n- Click on **Manage User Tokens**\n- Click **New User Token**\n- Enter a name for your token and click **Create**\n- Copy the generated token (it will only be shown once)\n\n### 2. Required Permissions\nYour user token needs access to:\n- Read/write permissions for the apps and tables you want to use\n- Admin permissions for creating/deleting records (if needed)\n\n**S": "\n## Quickbase Authentication Setup\n\n### 1. Get Your User Token\n- Log in to your Quickbase account\n- Go to **My Preferences** → **My User Information**\n- Click on **Manage User Tokens**\n- Click **New User Token**\n- Enter a name for your token and click **Create**\n- Copy the generated token (it will only be shown once)\n\n### 2. Required Permissions\nYour user token needs access to:\n- Read/write permissions for the apps and tables you want to use\n- Admin permissions for creating/deleting records (if needed)\n\n**Security Note:** Keep your user token secure - it provides access to your Quickbase data.\n",
|
||||
"Create Record": "レコードを作成",
|
||||
"Update Record": "更新記録",
|
||||
"Delete Record": "レコードを削除",
|
||||
"Find Record": "レコードを検索",
|
||||
"Find or Create Record": "レコードの検索または作成",
|
||||
"Create / Update Records From Array": "配列からレコードを作成/更新",
|
||||
"Custom API Call": "カスタムAPI通話",
|
||||
"Create a new record in a Quickbase table": "クイックベースのテーブルに新しいレコードを作成します",
|
||||
"Update an existing record in a Quickbase table": "Quickbase テーブル内の既存のレコードを更新",
|
||||
"Delete a record from a Quickbase table": "クイックベーステーブルからレコードを削除します",
|
||||
"Search for records in a Quickbase table using filters": "フィルタを使用してクイックベーステーブル内のレコードを検索",
|
||||
"Find an existing record or create a new one if not found": "既存のレコードを見つけるか、見つからない場合は新しいレコードを作成します",
|
||||
"Bulk create or update multiple records based on a merge key": "マージキーに基づいて複数のレコードを一括作成または更新します",
|
||||
"Make a custom API call to a specific endpoint": "特定のエンドポイントへのカスタム API コールを実行します。",
|
||||
"App": "App",
|
||||
"Table": "表",
|
||||
"Field Values": "フィールド値",
|
||||
"Record": "レコード",
|
||||
"Filters": "絞り込み",
|
||||
"Sort Field": "ソートフィールド",
|
||||
"Sort Order": "並び順",
|
||||
"Maximum Records": "最大レコード",
|
||||
"Merge Field": "統合フィールド",
|
||||
"Fields": "フィールド",
|
||||
"Records": "レコード",
|
||||
"Merge Behavior": "統合の動作",
|
||||
"Method": "方法",
|
||||
"Headers": "ヘッダー",
|
||||
"Query Parameters": "クエリパラメータ",
|
||||
"Body": "本文",
|
||||
"Response is Binary ?": "応答はバイナリですか?",
|
||||
"No Error on Failure": "失敗時にエラーはありません",
|
||||
"Timeout (in seconds)": "タイムアウト(秒)",
|
||||
"Select the Quickbase app": "Quickbaseアプリを選択",
|
||||
"Select the table": "テーブルを選択",
|
||||
"Select and set values for table fields": "テーブルフィールドの値の選択と設定",
|
||||
"Select a record from the table": "テーブルからレコードを選択",
|
||||
"Filter criteria to find records. Use field names or field IDs as keys.": "レコードを検索するために条件をフィルタします。フィールド名またはフィールドIDをキーとして使用します。",
|
||||
"Field to sort records by (optional)": "レコードをソートするフィールド (任意)",
|
||||
"Order to sort records": "レコードを並べ替える注文",
|
||||
"Maximum number of records to return": "Maximum number of records to return",
|
||||
"Field to use for matching existing records (for upsert operations)": "既存のレコードの一致に使用するフィールド (アップサート操作用)",
|
||||
"Map the fields to update. Use field names or field IDs.": "更新するフィールドをマップします。フィールド名またはフィールドIDを使用します。",
|
||||
"Array of records to create or update": "作成または更新するレコードの配列",
|
||||
"How to handle existing records when upserting": "アップサート時に既存のレコードを処理する方法",
|
||||
"Authorization headers are injected automatically from your connection.": "認証ヘッダは接続から自動的に注入されます。",
|
||||
"Enable for files like PDFs, images, etc..": "PDF、画像などのファイルを有効にします。",
|
||||
"Ascending (A-Z, 1-9)": "昇順 (A-Z, 1-9)",
|
||||
"Descending (Z-A, 9-1)": "降順",
|
||||
"Merge and overwrite all fields": "すべてのフィールドをマージして上書きする",
|
||||
"Merge and update only provided fields": "指定されたフィールドのみをマージして更新",
|
||||
"Always create new records (no merge)": "常に新しいレコードを作成(マージなし)",
|
||||
"GET": "取得",
|
||||
"POST": "POST",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "削除",
|
||||
"HEAD": "頭",
|
||||
"New Record": "新しいレコード",
|
||||
"New or Updated Record": "新規または更新されたレコード",
|
||||
"Triggers when a new record is created in a Quickbase table": "Quickbaseテーブルに新しいレコードが作成されたときにトリガーします",
|
||||
"Triggers when a record is created or updated in a Quickbase table": "Quickbaseテーブルでレコードが作成または更新されたときにトリガーします"
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"Realm Hostname": "Realm Hostname",
|
||||
"User Token": "Gebruiker Token",
|
||||
"Enter your Quickbase Realm Hostname (e.g., yourrealm.quickbase.com)": "Voer uw Quickbase Realm Hostname in (bijv. uwrealm.quickbase.com)",
|
||||
"Enter your Quickbase User Token": "Voer uw Quickbase User Token in",
|
||||
"\n## Quickbase Authentication Setup\n\n### 1. Get Your User Token\n- Log in to your Quickbase account\n- Go to **My Preferences** → **My User Information**\n- Click on **Manage User Tokens**\n- Click **New User Token**\n- Enter a name for your token and click **Create**\n- Copy the generated token (it will only be shown once)\n\n### 2. Required Permissions\nYour user token needs access to:\n- Read/write permissions for the apps and tables you want to use\n- Admin permissions for creating/deleting records (if needed)\n\n**S": "\n## Quickbase Authentication Setup\n\n### 1. Get Your User Token\n- Log in to your Quickbase account\n- Go to **My Preferences** → **My User Information**\n- Click on **Manage User Tokens**\n- Click **New User Token**\n- Enter a name for your token and click **Create**\n- Copy the generated token (it will only be shown once)\n\n### 2. Required Permissions\nYour user token needs access to:\n- Read/write permissions for the apps and tables you want to use\n- Admin permissions for creating/deleting records (if needed)\n\n**Security Note:** Keep your user token secure - it provides access to your Quickbase data.\n",
|
||||
"Create Record": "Record Maken",
|
||||
"Update Record": "Update Record",
|
||||
"Delete Record": "Record verwijderen",
|
||||
"Find Record": "Vind Record",
|
||||
"Find or Create Record": "Zoek of creëer Record",
|
||||
"Create / Update Records From Array": "Maak / Update Records Uit Array",
|
||||
"Custom API Call": "Custom API Call",
|
||||
"Create a new record in a Quickbase table": "Maak een nieuw record in een Quickbase tabel",
|
||||
"Update an existing record in a Quickbase table": "Een bestaand record in een Quickbase tabel bijwerken",
|
||||
"Delete a record from a Quickbase table": "Verwijder een record uit een Quickbase tabel",
|
||||
"Search for records in a Quickbase table using filters": "Zoek naar records in een Quickbase tabel met behulp van filters",
|
||||
"Find an existing record or create a new one if not found": "Zoek een bestaand record of maak een nieuw record indien niet gevonden",
|
||||
"Bulk create or update multiple records based on a merge key": "Bulk maken of bijwerken van meerdere records op basis van een samenvoeg-sleutel",
|
||||
"Make a custom API call to a specific endpoint": "Maak een aangepaste API call naar een specifiek eindpunt",
|
||||
"App": "App",
|
||||
"Table": "Tabel",
|
||||
"Field Values": "Veld Waarden",
|
||||
"Record": "Opnemen",
|
||||
"Filters": "Filters",
|
||||
"Sort Field": "Sorteren op veld",
|
||||
"Sort Order": "Sorteren bestelling",
|
||||
"Maximum Records": "Maximum Records",
|
||||
"Merge Field": "Veld samenvoegen",
|
||||
"Fields": "Velden",
|
||||
"Records": "Records",
|
||||
"Merge Behavior": "Samenvoegen van gedrag",
|
||||
"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)",
|
||||
"Select the Quickbase app": "Selecteer de Quickbase app",
|
||||
"Select the table": "Selecteer de tabel",
|
||||
"Select and set values for table fields": "Selecteer en stel waarden in voor de tabelvelden",
|
||||
"Select a record from the table": "Selecteer een record uit de tabel",
|
||||
"Filter criteria to find records. Use field names or field IDs as keys.": "Filter criteria om records te vinden. Gebruik veldnamen of veldIDs als sleutels.",
|
||||
"Field to sort records by (optional)": "Veld voor het sorteren van records op (optioneel)",
|
||||
"Order to sort records": "Orden om records te sorteren",
|
||||
"Maximum number of records to return": "Maximum aantal records om te retourneren",
|
||||
"Field to use for matching existing records (for upsert operations)": "Te gebruiken veld voor overeenkomende bestaande records (voor upsert bewerkingen)",
|
||||
"Map the fields to update. Use field names or field IDs.": "Kaart van de velden om bij te werken. Gebruik veldnamen of veldID's.",
|
||||
"Array of records to create or update": "Array van records om te maken of bij te werken",
|
||||
"How to handle existing records when upserting": "Hoe om te gaan met bestaande records bij upserting",
|
||||
"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..",
|
||||
"Ascending (A-Z, 1-9)": "Oplopend (A-Z, 1-9)",
|
||||
"Descending (Z-A, 9-1)": "Aflopend (Z-A, 9-1)",
|
||||
"Merge and overwrite all fields": "Alle velden samenvoegen en overschrijven",
|
||||
"Merge and update only provided fields": "Alleen verstrekte velden samenvoegen en bijwerken",
|
||||
"Always create new records (no merge)": "Altijd nieuwe records maken (geen samenvoegen)",
|
||||
"GET": "KRIJG",
|
||||
"POST": "POSTE",
|
||||
"PATCH": "BEKIJK",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "VERWIJDEREN",
|
||||
"HEAD": "HOOFD",
|
||||
"New Record": "Nieuwe Record",
|
||||
"New or Updated Record": "Nieuwe of bijgewerkte record",
|
||||
"Triggers when a new record is created in a Quickbase table": "Triggert wanneer een nieuw record wordt gemaakt in een Quickbase tabel",
|
||||
"Triggers when a record is created or updated in a Quickbase table": "Triggert wanneer een record wordt aangemaakt of bijgewerkt in een Quickbase tabel"
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"Realm Hostname": "Realm Hostname",
|
||||
"User Token": "Token do usuário",
|
||||
"Enter your Quickbase Realm Hostname (e.g., yourrealm.quickbase.com)": "Digite seu nome de Host do Realm Quickbase (por exemplo, seurealm.quickbase.com)",
|
||||
"Enter your Quickbase User Token": "Digite seu Token de usuário Quickbase",
|
||||
"\n## Quickbase Authentication Setup\n\n### 1. Get Your User Token\n- Log in to your Quickbase account\n- Go to **My Preferences** → **My User Information**\n- Click on **Manage User Tokens**\n- Click **New User Token**\n- Enter a name for your token and click **Create**\n- Copy the generated token (it will only be shown once)\n\n### 2. Required Permissions\nYour user token needs access to:\n- Read/write permissions for the apps and tables you want to use\n- Admin permissions for creating/deleting records (if needed)\n\n**S": "\n## Quickbase Authentication Setup\n\n### 1. Get Your User Token\n- Log in to your Quickbase account\n- Go to **My Preferences** → **My User Information**\n- Click on **Manage User Tokens**\n- Click **New User Token**\n- Enter a name for your token and click **Create**\n- Copy the generated token (it will only be shown once)\n\n### 2. Required Permissions\nYour user token needs access to:\n- Read/write permissions for the apps and tables you want to use\n- Admin permissions for creating/deleting records (if needed)\n\n**Security Note:** Keep your user token secure - it provides access to your Quickbase data.\n",
|
||||
"Create Record": "Criar Registro",
|
||||
"Update Record": "Atualizar Registro",
|
||||
"Delete Record": "Excluir registro",
|
||||
"Find Record": "Localizar Registro",
|
||||
"Find or Create Record": "Localizar ou Criar Registro",
|
||||
"Create / Update Records From Array": "Criar / Atualizar Registros da Matriz",
|
||||
"Custom API Call": "Chamada de API personalizada",
|
||||
"Create a new record in a Quickbase table": "Criar um novo registro em uma tabela de base rápida",
|
||||
"Update an existing record in a Quickbase table": "Atualizar um registro existente em uma tabela de base rápida",
|
||||
"Delete a record from a Quickbase table": "Excluir um registro de uma tabela de base rápida",
|
||||
"Search for records in a Quickbase table using filters": "Pesquisa por registros em uma tabela de base rápida usando filtros",
|
||||
"Find an existing record or create a new one if not found": "Localizar um registro existente ou criar um novo se não for encontrado",
|
||||
"Bulk create or update multiple records based on a merge key": "Criar ou atualizar vários registros com base em uma chave de mesclagem",
|
||||
"Make a custom API call to a specific endpoint": "Faça uma chamada de API personalizada para um ponto de extremidade específico",
|
||||
"App": "Aplicativo",
|
||||
"Table": "Classificações",
|
||||
"Field Values": "Valores do campo",
|
||||
"Record": "Gravar",
|
||||
"Filters": "Filtros",
|
||||
"Sort Field": "Classificar Campo",
|
||||
"Sort Order": "Ordem de classificação",
|
||||
"Maximum Records": "Máximo de Registros",
|
||||
"Merge Field": "Mesclar campo",
|
||||
"Fields": "campos",
|
||||
"Records": "registros",
|
||||
"Merge Behavior": "Comportamento de merge",
|
||||
"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)",
|
||||
"Select the Quickbase app": "Selecione o aplicativo Quickbase",
|
||||
"Select the table": "Selecione a tabela",
|
||||
"Select and set values for table fields": "Selecionar e definir valores para campos de tabela",
|
||||
"Select a record from the table": "Selecione um registro da tabela",
|
||||
"Filter criteria to find records. Use field names or field IDs as keys.": "Critérios de filtro para encontrar registros. Use os nomes dos campos ou IDs de campo como chaves.",
|
||||
"Field to sort records by (optional)": "Campo para ordenar os registros por (opcional)",
|
||||
"Order to sort records": "Ordenar os registros",
|
||||
"Maximum number of records to return": "Número máximo de registros para retornar",
|
||||
"Field to use for matching existing records (for upsert operations)": "Campo a ser usado para corresponder a registros existentes (para operações de upsert)",
|
||||
"Map the fields to update. Use field names or field IDs.": "Mapear os campos para atualizar. Use nomes de campos ou IDs de campo.",
|
||||
"Array of records to create or update": "Array de registros para criar ou atualizar",
|
||||
"How to handle existing records when upserting": "Como lidar com registros existentes ao upsering",
|
||||
"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..",
|
||||
"Ascending (A-Z, 1-9)": "Crescente (A-Z, 1-9)",
|
||||
"Descending (Z-A, 9-1)": "Decrescente (Z-A, 9-1)",
|
||||
"Merge and overwrite all fields": "Mesclar e substituir todos os campos",
|
||||
"Merge and update only provided fields": "Mesclar e atualizar somente os campos fornecidos",
|
||||
"Always create new records (no merge)": "Sempre criar novos registros (sem mesclagem)",
|
||||
"GET": "OBTER",
|
||||
"POST": "POSTAR",
|
||||
"PATCH": "COMPRAR",
|
||||
"PUT": "COLOCAR",
|
||||
"DELETE": "EXCLUIR",
|
||||
"HEAD": "CABEÇA",
|
||||
"New Record": "Novo Registro",
|
||||
"New or Updated Record": "Registro novo ou atualizado",
|
||||
"Triggers when a new record is created in a Quickbase table": "Aciona quando um novo registro é criado em uma tabela de base rápida",
|
||||
"Triggers when a record is created or updated in a Quickbase table": "Dispara quando um registro é criado ou atualizado em uma tabela de base rápida"
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"Realm Hostname": "Realm Hostname",
|
||||
"User Token": "User Token",
|
||||
"Enter your Quickbase Realm Hostname (e.g., yourrealm.quickbase.com)": "Enter your Quickbase Realm Hostname (e.g., yourrealm.quickbase.com)",
|
||||
"Enter your Quickbase User Token": "Enter your Quickbase User Token",
|
||||
"\n## Quickbase Authentication Setup\n\n### 1. Get Your User Token\n- Log in to your Quickbase account\n- Go to **My Preferences** → **My User Information**\n- Click on **Manage User Tokens**\n- Click **New User Token**\n- Enter a name for your token and click **Create**\n- Copy the generated token (it will only be shown once)\n\n### 2. Required Permissions\nYour user token needs access to:\n- Read/write permissions for the apps and tables you want to use\n- Admin permissions for creating/deleting records (if needed)\n\n**S": "\n## Quickbase Authentication Setup\n\n### 1. Get Your User Token\n- Log in to your Quickbase account\n- Go to **My Preferences** → **My User Information**\n- Click on **Manage User Tokens**\n- Click **New User Token**\n- Enter a name for your token and click **Create**\n- Copy the generated token (it will only be shown once)\n\n### 2. Required Permissions\nYour user token needs access to:\n- Read/write permissions for the apps and tables you want to use\n- Admin permissions for creating/deleting records (if needed)\n\n**Security Note:** Keep your user token secure - it provides access to your Quickbase data.\n",
|
||||
"Create Record": "Create Record",
|
||||
"Update Record": "Update Record",
|
||||
"Delete Record": "Delete Record",
|
||||
"Find Record": "Find Record",
|
||||
"Find or Create Record": "Find or Create Record",
|
||||
"Create / Update Records From Array": "Create / Update Records From Array",
|
||||
"Custom API Call": "Custom API Call",
|
||||
"Create a new record in a Quickbase table": "Create a new record in a Quickbase table",
|
||||
"Update an existing record in a Quickbase table": "Update an existing record in a Quickbase table",
|
||||
"Delete a record from a Quickbase table": "Delete a record from a Quickbase table",
|
||||
"Search for records in a Quickbase table using filters": "Search for records in a Quickbase table using filters",
|
||||
"Find an existing record or create a new one if not found": "Find an existing record or create a new one if not found",
|
||||
"Bulk create or update multiple records based on a merge key": "Bulk create or update multiple records based on a merge key",
|
||||
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
|
||||
"App": "App",
|
||||
"Table": "Table",
|
||||
"Field Values": "Field Values",
|
||||
"Record": "Record",
|
||||
"Filters": "Filters",
|
||||
"Sort Field": "Sort Field",
|
||||
"Sort Order": "Sort Order",
|
||||
"Maximum Records": "Maximum Records",
|
||||
"Merge Field": "Merge Field",
|
||||
"Fields": "Fields",
|
||||
"Records": "Records",
|
||||
"Merge Behavior": "Merge Behavior",
|
||||
"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)",
|
||||
"Select the Quickbase app": "Select the Quickbase app",
|
||||
"Select the table": "Select the table",
|
||||
"Select and set values for table fields": "Select and set values for table fields",
|
||||
"Select a record from the table": "Select a record from the table",
|
||||
"Filter criteria to find records. Use field names or field IDs as keys.": "Filter criteria to find records. Use field names or field IDs as keys.",
|
||||
"Field to sort records by (optional)": "Field to sort records by (optional)",
|
||||
"Order to sort records": "Order to sort records",
|
||||
"Maximum number of records to return": "Maximum number of records to return",
|
||||
"Field to use for matching existing records (for upsert operations)": "Field to use for matching existing records (for upsert operations)",
|
||||
"Map the fields to update. Use field names or field IDs.": "Map the fields to update. Use field names or field IDs.",
|
||||
"Array of records to create or update": "Array of records to create or update",
|
||||
"How to handle existing records when upserting": "How to handle existing records when upserting",
|
||||
"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..",
|
||||
"Ascending (A-Z, 1-9)": "Ascending (A-Z, 1-9)",
|
||||
"Descending (Z-A, 9-1)": "Descending (Z-A, 9-1)",
|
||||
"Merge and overwrite all fields": "Merge and overwrite all fields",
|
||||
"Merge and update only provided fields": "Merge and update only provided fields",
|
||||
"Always create new records (no merge)": "Always create new records (no merge)",
|
||||
"GET": "GET",
|
||||
"POST": "POST",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "DELETE",
|
||||
"HEAD": "HEAD",
|
||||
"New Record": "New Record",
|
||||
"New or Updated Record": "New or Updated Record",
|
||||
"Triggers when a new record is created in a Quickbase table": "Triggers when a new record is created in a Quickbase table",
|
||||
"Triggers when a record is created or updated in a Quickbase table": "Triggers when a record is created or updated in a Quickbase table"
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"Realm Hostname": "Realm Hostname",
|
||||
"User Token": "User Token",
|
||||
"Enter your Quickbase Realm Hostname (e.g., yourrealm.quickbase.com)": "Enter your Quickbase Realm Hostname (e.g., yourrealm.quickbase.com)",
|
||||
"Enter your Quickbase User Token": "Enter your Quickbase User Token",
|
||||
"\n## Quickbase Authentication Setup\n\n### 1. Get Your User Token\n- Log in to your Quickbase account\n- Go to **My Preferences** → **My User Information**\n- Click on **Manage User Tokens**\n- Click **New User Token**\n- Enter a name for your token and click **Create**\n- Copy the generated token (it will only be shown once)\n\n### 2. Required Permissions\nYour user token needs access to:\n- Read/write permissions for the apps and tables you want to use\n- Admin permissions for creating/deleting records (if needed)\n\n**S": "\n## Quickbase Authentication Setup\n\n### 1. Get Your User Token\n- Log in to your Quickbase account\n- Go to **My Preferences** → **My User Information**\n- Click on **Manage User Tokens**\n- Click **New User Token**\n- Enter a name for your token and click **Create**\n- Copy the generated token (it will only be shown once)\n\n### 2. Required Permissions\nYour user token needs access to:\n- Read/write permissions for the apps and tables you want to use\n- Admin permissions for creating/deleting records (if needed)\n\n**Security Note:** Keep your user token secure - it provides access to your Quickbase data.\n",
|
||||
"Create Record": "Create Record",
|
||||
"Update Record": "Update Record",
|
||||
"Delete Record": "Delete Record",
|
||||
"Find Record": "Find Record",
|
||||
"Find or Create Record": "Find or Create Record",
|
||||
"Create / Update Records From Array": "Create / Update Records From Array",
|
||||
"Custom API Call": "自定义 API 呼叫",
|
||||
"Create a new record in a Quickbase table": "Create a new record in a Quickbase table",
|
||||
"Update an existing record in a Quickbase table": "Update an existing record in a Quickbase table",
|
||||
"Delete a record from a Quickbase table": "Delete a record from a Quickbase table",
|
||||
"Search for records in a Quickbase table using filters": "Search for records in a Quickbase table using filters",
|
||||
"Find an existing record or create a new one if not found": "Find an existing record or create a new one if not found",
|
||||
"Bulk create or update multiple records based on a merge key": "Bulk create or update multiple records based on a merge key",
|
||||
"Make a custom API call to a specific endpoint": "将一个自定义 API 调用到一个特定的终点",
|
||||
"App": "App",
|
||||
"Table": "表",
|
||||
"Field Values": "Field Values",
|
||||
"Record": "Record",
|
||||
"Filters": "篩選條件",
|
||||
"Sort Field": "Sort Field",
|
||||
"Sort Order": "Sort Order",
|
||||
"Maximum Records": "Maximum Records",
|
||||
"Merge Field": "Merge Field",
|
||||
"Fields": "Fields",
|
||||
"Records": "Records",
|
||||
"Merge Behavior": "Merge Behavior",
|
||||
"Method": "方法",
|
||||
"Headers": "信头",
|
||||
"Query Parameters": "查询参数",
|
||||
"Body": "正文内容",
|
||||
"Response is Binary ?": "Response is Binary ?",
|
||||
"No Error on Failure": "失败时没有错误",
|
||||
"Timeout (in seconds)": "超时(秒)",
|
||||
"Select the Quickbase app": "Select the Quickbase app",
|
||||
"Select the table": "Select the table",
|
||||
"Select and set values for table fields": "Select and set values for table fields",
|
||||
"Select a record from the table": "Select a record from the table",
|
||||
"Filter criteria to find records. Use field names or field IDs as keys.": "Filter criteria to find records. Use field names or field IDs as keys.",
|
||||
"Field to sort records by (optional)": "Field to sort records by (optional)",
|
||||
"Order to sort records": "Order to sort records",
|
||||
"Maximum number of records to return": "Maximum number of records to return",
|
||||
"Field to use for matching existing records (for upsert operations)": "Field to use for matching existing records (for upsert operations)",
|
||||
"Map the fields to update. Use field names or field IDs.": "Map the fields to update. Use field names or field IDs.",
|
||||
"Array of records to create or update": "Array of records to create or update",
|
||||
"How to handle existing records when upserting": "How to handle existing records when upserting",
|
||||
"Authorization headers are injected automatically from your connection.": "授权头自动从您的连接中注入。",
|
||||
"Enable for files like PDFs, images, etc..": "Enable for files like PDFs, images, etc..",
|
||||
"Ascending (A-Z, 1-9)": "Ascending (A-Z, 1-9)",
|
||||
"Descending (Z-A, 9-1)": "Descending (Z-A, 9-1)",
|
||||
"Merge and overwrite all fields": "Merge and overwrite all fields",
|
||||
"Merge and update only provided fields": "Merge and update only provided fields",
|
||||
"Always create new records (no merge)": "Always create new records (no merge)",
|
||||
"GET": "获取",
|
||||
"POST": "帖子",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "弹出",
|
||||
"DELETE": "删除",
|
||||
"HEAD": "黑色",
|
||||
"New Record": "New Record",
|
||||
"New or Updated Record": "New or Updated Record",
|
||||
"Triggers when a new record is created in a Quickbase table": "Triggers when a new record is created in a Quickbase table",
|
||||
"Triggers when a record is created or updated in a Quickbase table": "Triggers when a record is created or updated in a Quickbase table"
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import { createPiece, PieceAuth, Property } from '@activepieces/pieces-framework';
|
||||
import { PieceCategory } from '@activepieces/shared';
|
||||
import { createCustomApiCallAction, httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
import { createRecord } from './lib/actions/create-record';
|
||||
import { updateRecord } from './lib/actions/update-record';
|
||||
import { deleteRecord } from './lib/actions/delete-record';
|
||||
import { findRecord } from './lib/actions/find-record';
|
||||
import { findOrCreateRecord } from './lib/actions/find-or-create-record';
|
||||
import { createUpdateRecordsBulk } from './lib/actions/create-update-records-bulk';
|
||||
import { newRecord } from './lib/triggers/new-record';
|
||||
import { newOrUpdatedRecord } from './lib/triggers/new-or-updated-record';
|
||||
|
||||
const markdown = `
|
||||
## Quickbase Authentication Setup
|
||||
|
||||
### 1. Get Your User Token
|
||||
- Log in to your Quickbase account
|
||||
- Go to **My Preferences** → **My User Information**
|
||||
- Click on **Manage User Tokens**
|
||||
- Click **New User Token**
|
||||
- Enter a name for your token and click **Create**
|
||||
- Copy the generated token (it will only be shown once)
|
||||
|
||||
### 2. Required Permissions
|
||||
Your user token needs access to:
|
||||
- Read/write permissions for the apps and tables you want to use
|
||||
- Admin permissions for creating/deleting records (if needed)
|
||||
|
||||
**Security Note:** Keep your user token secure - it provides access to your Quickbase data.
|
||||
`;
|
||||
|
||||
export const quickbaseAuth = PieceAuth.CustomAuth({
|
||||
description: markdown,
|
||||
required: true,
|
||||
props: {
|
||||
realmHostname: Property.ShortText({
|
||||
displayName: 'Realm Hostname',
|
||||
description: 'Enter your Quickbase Realm Hostname (e.g., yourrealm.quickbase.com)',
|
||||
required: true,
|
||||
}),
|
||||
userToken: Property.ShortText({
|
||||
displayName: 'User Token',
|
||||
description: 'Enter your Quickbase User Token',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
export const quickbase = createPiece({
|
||||
displayName: 'Quickbase',
|
||||
auth: quickbaseAuth,
|
||||
minimumSupportedRelease: '0.36.1',
|
||||
logoUrl: 'https://cdn.activepieces.com/pieces/quickbase.png',
|
||||
categories: [PieceCategory.PRODUCTIVITY],
|
||||
authors: ['sparkybug','sanket-a11y'],
|
||||
actions: [
|
||||
createRecord,
|
||||
updateRecord,
|
||||
deleteRecord,
|
||||
findRecord,
|
||||
findOrCreateRecord,
|
||||
createUpdateRecordsBulk,
|
||||
createCustomApiCallAction({
|
||||
auth: quickbaseAuth,
|
||||
baseUrl: (auth) => {
|
||||
return `https://api.quickbase.com/v1`;
|
||||
},
|
||||
authMapping: async (auth) => {
|
||||
return {
|
||||
'QB-Realm-Hostname': (auth).props.realmHostname,
|
||||
'Authorization': `QB-USER-TOKEN ${(auth).props.userToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
},
|
||||
})
|
||||
],
|
||||
triggers: [newRecord, newOrUpdatedRecord],
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { quickbaseAuth } from '../../index';
|
||||
import { appIdProp, tableIdProp, fieldsMapperProp, dynamicFieldsMapperProp } from '../common/props';
|
||||
import { QuickbaseClient } from '../common/client';
|
||||
import { QuickbaseCreateRecordResponse, QuickbaseField } from '../common/types';
|
||||
import { mapFieldsToRecord, validateRequiredFields } from '../common/utils';
|
||||
|
||||
export const createRecord = createAction({
|
||||
name: 'create_record',
|
||||
displayName: 'Create Record',
|
||||
description: 'Create a new record in a Quickbase table',
|
||||
auth: quickbaseAuth,
|
||||
props: {
|
||||
appId: appIdProp,
|
||||
tableId: tableIdProp,
|
||||
fields: dynamicFieldsMapperProp,
|
||||
},
|
||||
async run(context) {
|
||||
const { appId, tableId, fields } = context.propsValue;
|
||||
const client = new QuickbaseClient(context.auth.props.realmHostname, context.auth.props.userToken);
|
||||
|
||||
const tableFields = await client.get<QuickbaseField[]>(`/fields?tableId=${tableId}`);
|
||||
|
||||
|
||||
const recordData: Record<string, { value: any }> = {};
|
||||
|
||||
for (const [key, value] of Object.entries(fields)) {
|
||||
if (key.startsWith('field_') && value) {
|
||||
const fieldId = key.replace('field_', '');
|
||||
recordData[fieldId] = { value };
|
||||
}
|
||||
}
|
||||
|
||||
const response = await client.post<QuickbaseCreateRecordResponse>('/records', {
|
||||
to: tableId,
|
||||
data: [recordData],
|
||||
fieldsToReturn: tableFields.map(f => f.id),
|
||||
});
|
||||
|
||||
return {
|
||||
recordId: response.metadata.createdRecordIds[0],
|
||||
record: response.data[0],
|
||||
success: true,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,107 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { quickbaseAuth } from '../../index';
|
||||
import { appIdProp, tableIdProp, mergeFieldProp } from '../common/props';
|
||||
import { QuickbaseClient } from '../common/client';
|
||||
import { QuickbaseCreateRecordResponse, QuickbaseField } from '../common/types';
|
||||
import {
|
||||
mapFieldsToRecord,
|
||||
chunkArray,
|
||||
validateRequiredFields,
|
||||
} from '../common/utils';
|
||||
|
||||
export const createUpdateRecordsBulk = createAction({
|
||||
name: 'create_update_records_bulk',
|
||||
displayName: 'Create / Update Records From Array',
|
||||
description: 'Bulk create or update multiple records based on a merge key',
|
||||
auth: quickbaseAuth,
|
||||
props: {
|
||||
appId: appIdProp,
|
||||
tableId: tableIdProp,
|
||||
mergeField: mergeFieldProp,
|
||||
records: Property.Array({
|
||||
displayName: 'Records',
|
||||
description: 'Array of records to create or update',
|
||||
required: true,
|
||||
}),
|
||||
mergeFieldBehavior: Property.StaticDropdown({
|
||||
displayName: 'Merge Behavior',
|
||||
description: 'How to handle existing records when upserting',
|
||||
required: true,
|
||||
defaultValue: 'merge-overwrite',
|
||||
options: {
|
||||
options: [
|
||||
{
|
||||
label: 'Merge and overwrite all fields',
|
||||
value: 'merge-overwrite',
|
||||
},
|
||||
{
|
||||
label: 'Merge and update only provided fields',
|
||||
value: 'merge-update',
|
||||
},
|
||||
{
|
||||
label: 'Always create new records (no merge)',
|
||||
value: 'always-create',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { appId, tableId, mergeField, records, mergeFieldBehavior } =
|
||||
context.propsValue;
|
||||
const client = new QuickbaseClient(context.auth.props.realmHostname, context.auth.props.userToken);
|
||||
|
||||
if (!Array.isArray(records) || records.length === 0) {
|
||||
throw new Error('Records array is required and cannot be empty');
|
||||
}
|
||||
|
||||
const tableFields = await client.get<QuickbaseField[]>(
|
||||
`/fields?tableId=${tableId}`
|
||||
);
|
||||
const requiredFields = tableFields
|
||||
.filter((f) => f.required)
|
||||
.map((f) => f.id.toString());
|
||||
|
||||
const processedRecords = records.map((record) => {
|
||||
if (mergeFieldBehavior !== 'always-create') {
|
||||
validateRequiredFields(record as Record<string, any>, requiredFields);
|
||||
}
|
||||
return mapFieldsToRecord(record as Record<string, any>, tableFields);
|
||||
});
|
||||
|
||||
const chunks = chunkArray(processedRecords, 1000);
|
||||
const results = {
|
||||
createdRecords: [] as number[],
|
||||
updatedRecords: [] as number[],
|
||||
unchangedRecords: [] as number[],
|
||||
totalProcessed: 0,
|
||||
success: true,
|
||||
};
|
||||
|
||||
for (const chunk of chunks) {
|
||||
const requestData: any = {
|
||||
to: tableId,
|
||||
data: chunk,
|
||||
fieldsToReturn: tableFields.map((f) => f.id),
|
||||
};
|
||||
|
||||
if (mergeFieldBehavior !== 'always-create') {
|
||||
requestData.mergeFieldId = parseInt(mergeField);
|
||||
requestData.upsert =
|
||||
mergeFieldBehavior === 'merge-overwrite' ? 'true' : 'false';
|
||||
}
|
||||
|
||||
const response = await client.post<QuickbaseCreateRecordResponse>(
|
||||
'/records',
|
||||
requestData
|
||||
);
|
||||
|
||||
results.createdRecords.push(...response.metadata.createdRecordIds);
|
||||
results.updatedRecords.push(...response.metadata.updatedRecordIds);
|
||||
results.unchangedRecords.push(...response.metadata.unchangedRecordIds);
|
||||
results.totalProcessed += response.metadata.totalNumberOfRecordsProcessed;
|
||||
}
|
||||
|
||||
return results;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { quickbaseAuth } from '../../index';
|
||||
import { appIdProp, tableIdProp, recordIdDropdownProp } from '../common/props';
|
||||
import { QuickbaseClient } from '../common/client';
|
||||
import { QuickbaseDeleteRecordResponse } from '../common/types';
|
||||
|
||||
export const deleteRecord = createAction({
|
||||
name: 'delete_record',
|
||||
displayName: 'Delete Record',
|
||||
description: 'Delete a record from a Quickbase table',
|
||||
auth: quickbaseAuth,
|
||||
props: {
|
||||
appId: appIdProp,
|
||||
tableId: tableIdProp,
|
||||
recordId: recordIdDropdownProp,
|
||||
},
|
||||
async run(context) {
|
||||
const { appId, tableId, recordId } = context.propsValue;
|
||||
const client = new QuickbaseClient(context.auth.props.realmHostname, context.auth.props.userToken);
|
||||
|
||||
const response = await client.delete<QuickbaseDeleteRecordResponse>('/records', {
|
||||
from: tableId,
|
||||
where: `{3.EX.${recordId}}`,
|
||||
});
|
||||
|
||||
return {
|
||||
recordId: recordId,
|
||||
deleted: response.numberDeleted > 0,
|
||||
numberDeleted: response.numberDeleted,
|
||||
success: true,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,100 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { quickbaseAuth } from '../../index';
|
||||
import {
|
||||
appIdProp,
|
||||
tableIdProp,
|
||||
fieldsMapperProp,
|
||||
mergeFieldProp,
|
||||
} from '../common/props';
|
||||
import { QuickbaseClient } from '../common/client';
|
||||
import {
|
||||
QuickbaseRecordResponse,
|
||||
QuickbaseCreateRecordResponse,
|
||||
QuickbaseField,
|
||||
} from '../common/types';
|
||||
import {
|
||||
mapFieldsToRecord,
|
||||
extractRecordValues,
|
||||
validateRequiredFields,
|
||||
} from '../common/utils';
|
||||
|
||||
export const findOrCreateRecord = createAction({
|
||||
name: 'find_or_create_record',
|
||||
displayName: 'Find or Create Record',
|
||||
description: 'Find an existing record or create a new one if not found',
|
||||
auth: quickbaseAuth,
|
||||
props: {
|
||||
appId: appIdProp,
|
||||
tableId: tableIdProp,
|
||||
mergeField: mergeFieldProp,
|
||||
fields: fieldsMapperProp,
|
||||
},
|
||||
async run(context) {
|
||||
const { appId, tableId, mergeField, fields } = context.propsValue;
|
||||
const client = new QuickbaseClient(context.auth.props.realmHostname, context.auth.props.userToken);
|
||||
|
||||
const tableFields = await client.get<QuickbaseField[]>(
|
||||
`/fields?tableId=${tableId}`
|
||||
);
|
||||
const mergeValue =
|
||||
fields[mergeField] ||
|
||||
fields[
|
||||
tableFields.find((f) => f.id.toString() === mergeField)?.label || ''
|
||||
];
|
||||
|
||||
if (!mergeValue) {
|
||||
throw new Error(`Merge field value is required`);
|
||||
}
|
||||
|
||||
const searchQuery = {
|
||||
from: tableId,
|
||||
select: tableFields.map((f) => f.id),
|
||||
where: `{${mergeField}.EX.'${mergeValue}'}`,
|
||||
options: { top: 1 },
|
||||
};
|
||||
|
||||
try {
|
||||
const searchResponse = await client.post<QuickbaseRecordResponse>(
|
||||
'/records/query',
|
||||
searchQuery
|
||||
);
|
||||
|
||||
if (searchResponse.data.length > 0) {
|
||||
const existingRecord = searchResponse.data[0];
|
||||
return {
|
||||
recordId: existingRecord['3']?.value,
|
||||
record: extractRecordValues(existingRecord),
|
||||
created: false,
|
||||
found: true,
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
|
||||
const requiredFields = tableFields
|
||||
.filter((f) => f.required)
|
||||
.map((f) => f.id.toString());
|
||||
validateRequiredFields(fields, requiredFields);
|
||||
|
||||
const recordData = mapFieldsToRecord(fields, tableFields);
|
||||
|
||||
const createResponse = await client.post<QuickbaseCreateRecordResponse>(
|
||||
'/records',
|
||||
{
|
||||
to: tableId,
|
||||
data: [recordData],
|
||||
fieldsToReturn: tableFields.map((f) => f.id),
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
recordId: createResponse.metadata.createdRecordIds[0],
|
||||
record: createResponse.data[0],
|
||||
created: true,
|
||||
found: false,
|
||||
success: true,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { quickbaseAuth } from '../../index';
|
||||
import { appIdProp, tableIdProp, filtersProp, maxRecordsProp, sortFieldProp, sortOrderProp } from '../common/props';
|
||||
import { QuickbaseClient } from '../common/client';
|
||||
import { QuickbaseRecordResponse, QuickbaseField } from '../common/types';
|
||||
import { buildWhereClause, extractRecordValues } from '../common/utils';
|
||||
|
||||
export const findRecord = createAction({
|
||||
name: 'find_record',
|
||||
displayName: 'Find Record',
|
||||
description: 'Search for records in a Quickbase table using filters',
|
||||
auth: quickbaseAuth,
|
||||
props: {
|
||||
appId: appIdProp,
|
||||
tableId: tableIdProp,
|
||||
filters: filtersProp,
|
||||
sortField: sortFieldProp,
|
||||
sortOrder: sortOrderProp,
|
||||
maxRecords: maxRecordsProp,
|
||||
},
|
||||
async run(context) {
|
||||
const { appId, tableId, filters, sortField, sortOrder, maxRecords } = context.propsValue;
|
||||
const client = new QuickbaseClient(context.auth.props.realmHostname, context.auth.props.userToken);
|
||||
|
||||
const tableFields = await client.get<QuickbaseField[]>(`/fields?tableId=${tableId}`);
|
||||
const whereClause = filters ? buildWhereClause(filters) : '';
|
||||
|
||||
const query: any = {
|
||||
from: tableId,
|
||||
select: tableFields.map(f => f.id),
|
||||
where: whereClause,
|
||||
options: {
|
||||
top: maxRecords || 100,
|
||||
},
|
||||
};
|
||||
|
||||
if (sortField) {
|
||||
query.sortBy = [{
|
||||
fieldId: parseInt(sortField),
|
||||
order: sortOrder || 'ASC',
|
||||
}];
|
||||
}
|
||||
|
||||
const response = await client.post<QuickbaseRecordResponse>('/records/query', query);
|
||||
|
||||
const records = response.data.map(record => ({
|
||||
id: record['3']?.value,
|
||||
displayName: record['3']?.value,
|
||||
raw: extractRecordValues(record),
|
||||
}));
|
||||
|
||||
return {
|
||||
records,
|
||||
totalRecords: response.metadata.totalRecords,
|
||||
success: true,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { quickbaseAuth } from '../../index';
|
||||
import { appIdProp, tableIdProp, recordIdDropdownProp, dynamicFieldsMapperProp } from '../common/props';
|
||||
import { QuickbaseClient } from '../common/client';
|
||||
import { QuickbaseUpdateRecordResponse, QuickbaseField } from '../common/types';
|
||||
import { mapFieldsToRecord } from '../common/utils';
|
||||
|
||||
export const updateRecord = createAction({
|
||||
name: 'update_record',
|
||||
displayName: 'Update Record',
|
||||
description: 'Update an existing record in a Quickbase table',
|
||||
auth: quickbaseAuth,
|
||||
props: {
|
||||
appId: appIdProp,
|
||||
tableId: tableIdProp,
|
||||
recordId: recordIdDropdownProp,
|
||||
fields: dynamicFieldsMapperProp,
|
||||
},
|
||||
async run(context) {
|
||||
const { appId, tableId, recordId, fields } = context.propsValue;
|
||||
const client = new QuickbaseClient(context.auth.props.realmHostname, context.auth.props.userToken);
|
||||
|
||||
const tableFields = await client.get<QuickbaseField[]>(`/fields?tableId=${tableId}`);
|
||||
|
||||
|
||||
const recordData: Record<string, { value: any }> = {
|
||||
'3': { value: recordId },
|
||||
};
|
||||
|
||||
for (const [key, value] of Object.entries(fields)) {
|
||||
if (key.startsWith('field_') && value) {
|
||||
const fieldId = key.replace('field_', '');
|
||||
recordData[fieldId] = { value };
|
||||
}
|
||||
}
|
||||
|
||||
const response = await client.post<QuickbaseUpdateRecordResponse>('/records', {
|
||||
to: tableId,
|
||||
data: [recordData],
|
||||
fieldsToReturn: tableFields.map(f => f.id),
|
||||
});
|
||||
|
||||
return {
|
||||
recordId: recordId,
|
||||
record: response.data[0],
|
||||
updated: response.metadata.updatedRecordIds.includes(Number(recordId)),
|
||||
success: true,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,121 @@
|
||||
import {
|
||||
httpClient,
|
||||
HttpMethod,
|
||||
HttpRequest,
|
||||
} from '@activepieces/pieces-common';
|
||||
import { QuickbaseApiError } from './types';
|
||||
|
||||
export class QuickbaseClient {
|
||||
private readonly baseUrl = 'https://api.quickbase.com/v1';
|
||||
private readonly userToken: string;
|
||||
private readonly realmHostname: string;
|
||||
|
||||
constructor(realmHostname: string, userToken: string) {
|
||||
this.realmHostname = realmHostname;
|
||||
this.userToken = userToken;
|
||||
}
|
||||
|
||||
private async makeRequest<T>(
|
||||
endpoint: string,
|
||||
method: HttpMethod,
|
||||
data?: any
|
||||
): Promise<T> {
|
||||
const url = `${this.baseUrl}${endpoint}`;
|
||||
|
||||
const request: HttpRequest = {
|
||||
method,
|
||||
url,
|
||||
headers: {
|
||||
'QB-Realm-Hostname': this.realmHostname,
|
||||
'Authorization': `QB-USER-TOKEN ${this.userToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: data ? data : undefined,
|
||||
};
|
||||
|
||||
let lastError: Error;
|
||||
|
||||
for (let attempt = 1; attempt <= 3; attempt++) {
|
||||
try {
|
||||
const response = await httpClient.sendRequest<T>(request);
|
||||
|
||||
if (response.status === 429) {
|
||||
const retryAfter = response.headers?.['retry-after'];
|
||||
const retryAfterValue = Array.isArray(retryAfter)
|
||||
? retryAfter[0]
|
||||
: retryAfter;
|
||||
const delay = retryAfterValue
|
||||
? parseInt(retryAfterValue) * 1000
|
||||
: Math.pow(2, attempt) * 1000;
|
||||
await this.sleep(delay);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (response.status >= 500) {
|
||||
if (attempt === 3) {
|
||||
throw new Error(`Server error: ${response.status}`);
|
||||
}
|
||||
await this.sleep(Math.pow(2, attempt) * 1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (response.status >= 400) {
|
||||
let errorMessage = `HTTP ${response.status}`;
|
||||
|
||||
try {
|
||||
const errorData = response.body as QuickbaseApiError;
|
||||
if (errorData.errors && errorData.errors.length > 0) {
|
||||
errorMessage = errorData.errors[0].message;
|
||||
if (errorData.errors[0].description) {
|
||||
errorMessage += ` - ${errorData.errors[0].description}`;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
errorMessage = response.body ? String(response.body) : errorMessage;
|
||||
}
|
||||
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
return response.body;
|
||||
} catch (error) {
|
||||
lastError = error instanceof Error ? error : new Error(String(error));
|
||||
|
||||
if (attempt === 3 || !this.isRetryableError(error)) {
|
||||
throw lastError;
|
||||
}
|
||||
|
||||
await this.sleep(Math.pow(2, attempt) * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
throw lastError!;
|
||||
}
|
||||
|
||||
private isRetryableError(error: unknown): boolean {
|
||||
if (error instanceof Error && error.message.includes('network')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async get<T>(endpoint: string): Promise<T> {
|
||||
return this.makeRequest<T>(endpoint, HttpMethod.GET);
|
||||
}
|
||||
|
||||
async post<T>(endpoint: string, data?: any): Promise<T> {
|
||||
return this.makeRequest<T>(endpoint, HttpMethod.POST, data);
|
||||
}
|
||||
|
||||
async patch<T>(endpoint: string, data: any): Promise<T> {
|
||||
return this.makeRequest<T>(endpoint, HttpMethod.PATCH, data);
|
||||
}
|
||||
|
||||
async delete<T>(endpoint: string, data?: any): Promise<T> {
|
||||
return this.makeRequest<T>(endpoint, HttpMethod.DELETE, data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
import { Property } from '@activepieces/pieces-framework';
|
||||
import { QuickbaseClient } from './client';
|
||||
import { QuickbaseApp, QuickbaseTable, QuickbaseField } from './types';
|
||||
import { quickbaseAuth } from '../..';
|
||||
|
||||
|
||||
export const recordIdProp = Property.ShortText({
|
||||
displayName: 'Record ID',
|
||||
description: 'The ID of the record',
|
||||
required: true,
|
||||
});
|
||||
|
||||
export const fieldsMapperProp = Property.Object({
|
||||
displayName: 'Fields',
|
||||
description: 'Map the fields to update. Use field names or field IDs.',
|
||||
required: true,
|
||||
});
|
||||
|
||||
export const createDynamicFieldsMapperProp = () => Property.DynamicProperties({
|
||||
displayName: 'Field Values',
|
||||
auth: quickbaseAuth,
|
||||
description: 'Select and set values for table fields',
|
||||
required: true,
|
||||
refreshers: ['appId', 'tableId'],
|
||||
props: async ({ auth, appId, tableId }) => {
|
||||
if (!auth || !appId || !tableId) {
|
||||
return {};
|
||||
}
|
||||
|
||||
try {
|
||||
const client = new QuickbaseClient(auth.props.realmHostname, auth.props.userToken);
|
||||
const fields = await client.get<QuickbaseField[]>(`/fields?tableId=${tableId}`);
|
||||
|
||||
const props: Record<string, any> = {};
|
||||
console.log("fields", JSON.stringify(fields, null, 2));
|
||||
for (const field of fields) {
|
||||
if (field.id === 3) continue;
|
||||
|
||||
const propKey = `field_${field.id}`;
|
||||
const isRequired = field.required || false;
|
||||
|
||||
if (field.fieldType === 'checkbox') {
|
||||
props[propKey] = Property.Checkbox({
|
||||
displayName: `${field.label}${isRequired ? ' *' : ''}`,
|
||||
description: `${field.fieldType} field${isRequired ? ' (required)' : ''}`,
|
||||
required: isRequired,
|
||||
});
|
||||
} else if (field.fieldType === 'number') {
|
||||
props[propKey] = Property.Number({
|
||||
displayName: `${field.label}${isRequired ? ' *' : ''}`,
|
||||
description: `${field.fieldType} field${isRequired ? ' (required)' : ''}`,
|
||||
required: isRequired,
|
||||
});
|
||||
} else if (field.fieldType === 'date ' || field.fieldType === 'timestamp') {
|
||||
props[propKey] = Property.DateTime({
|
||||
displayName: `${field.label}${isRequired ? ' *' : ''}`,
|
||||
description: `${field.fieldType} field${isRequired ? ' (required)' : ''}`,
|
||||
required: isRequired,
|
||||
});
|
||||
} else {
|
||||
props[propKey] = Property.ShortText({
|
||||
displayName: `${field.label}${isRequired ? ' *' : ''}`,
|
||||
description: `${field.fieldType} field${isRequired ? ' (required)' : ''}`,
|
||||
required: isRequired,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return props;
|
||||
} catch (error) {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const filtersProp = Property.Object({
|
||||
displayName: 'Filters',
|
||||
description: 'Filter criteria to find records. Use field names or field IDs as keys.',
|
||||
required: false,
|
||||
});
|
||||
|
||||
export const recordsArrayProp = Property.Array({
|
||||
displayName: 'Records',
|
||||
description: 'Array of records to create or update',
|
||||
required: true,
|
||||
});
|
||||
|
||||
|
||||
export const maxRecordsProp = Property.Number({
|
||||
displayName: 'Maximum Records',
|
||||
description: 'Maximum number of records to return',
|
||||
required: false,
|
||||
defaultValue: 100,
|
||||
});
|
||||
|
||||
|
||||
export const createAppIdProp = () => Property.Dropdown({
|
||||
auth: quickbaseAuth,
|
||||
|
||||
displayName: 'App',
|
||||
description: 'Select the Quickbase app',
|
||||
required: true,
|
||||
refreshers: [],
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please connect your account first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const client = new QuickbaseClient(auth.props.realmHostname, auth.props.userToken);
|
||||
const apps = await client.get<QuickbaseApp[]>('/apps');
|
||||
|
||||
return {
|
||||
options: apps.map(app => ({
|
||||
label: app.name,
|
||||
value: app.id,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Failed to load apps',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const createTableIdProp = () => Property.Dropdown({
|
||||
auth: quickbaseAuth,
|
||||
|
||||
displayName: 'Table',
|
||||
description: 'Select the table',
|
||||
required: true,
|
||||
refreshers: ['appId'],
|
||||
options: async ({ auth, appId }) => {
|
||||
if (!auth || !appId) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please select an app first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const client = new QuickbaseClient(auth.props.realmHostname, auth.props.userToken);
|
||||
const tables = await client.get<QuickbaseTable[]>(`/tables?appId=${appId}`);
|
||||
|
||||
return {
|
||||
options: tables.map(table => ({
|
||||
label: table.name,
|
||||
value: table.id,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Failed to load tables',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const createMergeFieldProp = () => Property.Dropdown({
|
||||
auth: quickbaseAuth,
|
||||
|
||||
displayName: 'Merge Field',
|
||||
description: 'Field to use for matching existing records (for upsert operations)',
|
||||
required: true,
|
||||
refreshers: ['appId', 'tableId'],
|
||||
options: async ({ auth, appId, tableId }) => {
|
||||
if (!auth || !appId || !tableId) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please select app and table first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const client = new QuickbaseClient(auth.props.realmHostname, auth.props.userToken);
|
||||
const fields = await client.get<QuickbaseField[]>(`/fields?tableId=${tableId}`);
|
||||
|
||||
return {
|
||||
options: fields
|
||||
.filter(field => field.unique || field.fieldType === 'text' || field.fieldType === 'email')
|
||||
.map(field => ({
|
||||
label: field.label,
|
||||
value: field.id.toString(),
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Failed to load fields',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
export const createSortFieldProp = () => Property.Dropdown({
|
||||
auth: quickbaseAuth,
|
||||
|
||||
displayName: 'Sort Field',
|
||||
description: 'Field to sort records by (optional)',
|
||||
required: false,
|
||||
refreshers: ['appId', 'tableId'],
|
||||
options: async ({ auth, appId, tableId }) => {
|
||||
if (!auth || !appId || !tableId) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please select app and table first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const client = new QuickbaseClient(auth.props.realmHostname, auth.props.userToken);
|
||||
const fields = await client.get<QuickbaseField[]>(`/fields?tableId=${tableId}`);
|
||||
|
||||
return {
|
||||
options: [
|
||||
{ label: 'No sorting', value: '' },
|
||||
...fields
|
||||
.filter(field => ['text', 'number', 'date', 'timestamp'].includes(field.fieldType))
|
||||
.map(field => ({
|
||||
label: `${field.label} (${field.fieldType})`,
|
||||
value: field.id.toString(),
|
||||
}))
|
||||
],
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Failed to load fields',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const createSortOrderProp = () => Property.StaticDropdown({
|
||||
displayName: 'Sort Order',
|
||||
description: 'Order to sort records',
|
||||
required: false,
|
||||
defaultValue: 'ASC',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Ascending (A-Z, 1-9)', value: 'ASC' },
|
||||
{ label: 'Descending (Z-A, 9-1)', value: 'DESC' },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
export const createRecordIdProp = () => Property.Dropdown({
|
||||
auth: quickbaseAuth,
|
||||
|
||||
displayName: 'Record',
|
||||
description: 'Select a record from the table',
|
||||
required: true,
|
||||
refreshers: ['appId', 'tableId'],
|
||||
options: async ({ auth, appId, tableId }) => {
|
||||
if (!auth || !appId || !tableId) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please select app and table first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const client = new QuickbaseClient(auth.props.realmHostname, auth.props.userToken);
|
||||
|
||||
const fields = await client.get<QuickbaseField[]>(`/fields?tableId=${tableId}`);
|
||||
const displayField = fields.find(f => f.fieldType === 'text' && f.label.toLowerCase().includes('name'))
|
||||
|| fields.find(f => f.fieldType === 'text')
|
||||
|| fields[1];
|
||||
|
||||
|
||||
const query = {
|
||||
from: tableId,
|
||||
select: [3, displayField?.id || 6],
|
||||
options: { top: 50 },
|
||||
};
|
||||
|
||||
const response = await client.post<any>('/records/query', query);
|
||||
|
||||
return {
|
||||
options: response.data.map((record: any) => {
|
||||
const recordId = record['3']?.value;
|
||||
const displayValue = record[displayField?.id.toString() || '6']?.value || `Record ${recordId}`;
|
||||
return {
|
||||
label: `${displayValue} (ID: ${recordId})`,
|
||||
value: recordId.toString(),
|
||||
};
|
||||
}),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Failed to load records',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
export const appIdProp = createAppIdProp();
|
||||
export const tableIdProp = createTableIdProp();
|
||||
export const mergeFieldProp = createMergeFieldProp();
|
||||
export const sortFieldProp = createSortFieldProp();
|
||||
export const sortOrderProp = createSortOrderProp();
|
||||
export const recordIdDropdownProp = createRecordIdProp();
|
||||
export const dynamicFieldsMapperProp = createDynamicFieldsMapperProp();
|
||||
@@ -0,0 +1,111 @@
|
||||
export interface QuickbaseApp {
|
||||
id: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
created: string;
|
||||
updated: string;
|
||||
}
|
||||
|
||||
export interface QuickbaseTable {
|
||||
id: string;
|
||||
name: string;
|
||||
alias?: string;
|
||||
description?: string;
|
||||
created: string;
|
||||
updated: string;
|
||||
nextRecordId: number;
|
||||
nextFieldId: number;
|
||||
defaultSortFieldId: number;
|
||||
defaultSortOrder: string;
|
||||
keyFieldId: number;
|
||||
singleRecordName: string;
|
||||
pluralRecordName: string;
|
||||
}
|
||||
|
||||
export interface QuickbaseField {
|
||||
id: number;
|
||||
label: string;
|
||||
fieldType: string;
|
||||
mode?: string;
|
||||
required?: boolean;
|
||||
unique?: boolean;
|
||||
properties?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface QuickbaseRecord {
|
||||
[fieldId: string]: {
|
||||
value: any;
|
||||
};
|
||||
}
|
||||
|
||||
export interface QuickbaseRecordResponse {
|
||||
data: QuickbaseRecord[];
|
||||
fields: QuickbaseField[];
|
||||
metadata: {
|
||||
numRecords: number;
|
||||
numFields: number;
|
||||
skip: number;
|
||||
top: number;
|
||||
totalRecords: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface QuickbaseCreateRecordResponse {
|
||||
data: Array<{
|
||||
[fieldId: string]: {
|
||||
value: any;
|
||||
};
|
||||
}>;
|
||||
metadata: {
|
||||
createdRecordIds: number[];
|
||||
totalNumberOfRecordsProcessed: number;
|
||||
unchangedRecordIds: number[];
|
||||
updatedRecordIds: number[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface QuickbaseUpdateRecordResponse {
|
||||
data: Array<{
|
||||
[fieldId: string]: {
|
||||
value: any;
|
||||
};
|
||||
}>;
|
||||
metadata: {
|
||||
totalNumberOfRecordsProcessed: number;
|
||||
unchangedRecordIds: number[];
|
||||
updatedRecordIds: number[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface QuickbaseDeleteRecordResponse {
|
||||
numberDeleted: number;
|
||||
}
|
||||
|
||||
export interface QuickbaseError {
|
||||
message: string;
|
||||
description?: string;
|
||||
code?: string;
|
||||
}
|
||||
|
||||
export interface QuickbaseApiError {
|
||||
errors: QuickbaseError[];
|
||||
}
|
||||
|
||||
export interface QuickbaseQuery {
|
||||
from: string;
|
||||
select?: number[];
|
||||
where?: string;
|
||||
sortBy?: Array<{
|
||||
fieldId: number;
|
||||
order: 'ASC' | 'DESC';
|
||||
}>;
|
||||
groupBy?: Array<{
|
||||
fieldId: number;
|
||||
grouping: string;
|
||||
}>;
|
||||
options?: {
|
||||
skip?: number;
|
||||
top?: number;
|
||||
compareWithAppLocalTime?: boolean;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import { QuickbaseRecord, QuickbaseField } from './types';
|
||||
|
||||
export function generateDeduplicationKey(recordId: string | number, lastModified: string): string {
|
||||
return `${recordId}-${lastModified}`;
|
||||
}
|
||||
|
||||
export function mapFieldsToRecord(
|
||||
fieldsData: Record<string, any>,
|
||||
fields: QuickbaseField[]
|
||||
): Record<string, { value: any }> {
|
||||
const record: Record<string, { value: any }> = {};
|
||||
|
||||
for (const [key, value] of Object.entries(fieldsData)) {
|
||||
let fieldId: string;
|
||||
|
||||
if (/^\d+$/.test(key)) {
|
||||
fieldId = key;
|
||||
} else {
|
||||
const field = fields.find(f => f.label.toLowerCase() === key.toLowerCase());
|
||||
if (field) {
|
||||
fieldId = field.id.toString();
|
||||
} else {
|
||||
throw new Error(`Field not found: ${key}`);
|
||||
}
|
||||
}
|
||||
|
||||
record[fieldId] = { value };
|
||||
}
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
export function extractRecordValues(record: QuickbaseRecord): Record<string, any> {
|
||||
const values: Record<string, any> = {};
|
||||
|
||||
for (const [fieldId, fieldData] of Object.entries(record)) {
|
||||
values[fieldId] = fieldData.value;
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
export function chunkArray<T>(array: T[], chunkSize: number): T[][] {
|
||||
const chunks: T[][] = [];
|
||||
for (let i = 0; i < array.length; i += chunkSize) {
|
||||
chunks.push(array.slice(i, i + chunkSize));
|
||||
}
|
||||
return chunks;
|
||||
}
|
||||
|
||||
export function buildWhereClause(filters: Record<string, any>): string {
|
||||
const conditions: string[] = [];
|
||||
|
||||
for (const [fieldId, value] of Object.entries(filters)) {
|
||||
if (value === null || value === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
conditions.push(`{${fieldId}.EX.'${value.replace(/'/g, "''")}'}`);
|
||||
} else if (typeof value === 'number') {
|
||||
conditions.push(`{${fieldId}.EX.${value}}`);
|
||||
} else if (typeof value === 'boolean') {
|
||||
conditions.push(`{${fieldId}.EX.${value}}`);
|
||||
} else if (Array.isArray(value)) {
|
||||
const arrayConditions = value.map(v =>
|
||||
typeof v === 'string'
|
||||
? `{${fieldId}.EX.'${v.replace(/'/g, "''")}'}`
|
||||
: `{${fieldId}.EX.${v}}`
|
||||
);
|
||||
conditions.push(`(${arrayConditions.join('OR')})`);
|
||||
}
|
||||
}
|
||||
|
||||
return conditions.join('AND');
|
||||
}
|
||||
|
||||
export function validateRequiredFields(
|
||||
data: Record<string, any>,
|
||||
requiredFields: string[]
|
||||
): void {
|
||||
const missingFields = requiredFields.filter(field =>
|
||||
data[field] === undefined || data[field] === null || data[field] === ''
|
||||
);
|
||||
|
||||
if (missingFields.length > 0) {
|
||||
throw new Error(`Missing required fields: ${missingFields.join(', ')}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import { AppConnectionValueForAuthProperty, createTrigger, StaticPropsValue, TriggerStrategy } from "@activepieces/pieces-framework";
|
||||
import { quickbaseAuth } from "../..";
|
||||
import { DedupeStrategy, Polling, pollingHelper } from "@activepieces/pieces-common";
|
||||
import { QuickbaseClient } from "../common/client";
|
||||
import { QuickbaseRecordResponse, QuickbaseField } from "../common/types";
|
||||
import { appIdProp, tableIdProp } from "../common/props";
|
||||
type QuickbaseAuth = AppConnectionValueForAuthProperty<typeof quickbaseAuth>;
|
||||
const props = {
|
||||
appId: appIdProp,
|
||||
tableId: tableIdProp,
|
||||
}
|
||||
const polling: Polling<QuickbaseAuth, StaticPropsValue<typeof props>> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
items: async ({ auth, propsValue, lastFetchEpochMS }) => {
|
||||
const { tableId, } = propsValue;
|
||||
const client = new QuickbaseClient(auth.props.realmHostname, auth.props.userToken);
|
||||
|
||||
const fields = await client.get<QuickbaseField[]>(`/fields?tableId=${tableId}`);
|
||||
|
||||
const select = fields.map((f) => f.id);
|
||||
|
||||
const modifiedField = fields.find(
|
||||
(f) => /modified/i.test(f.label) && (f.fieldType === 'timestamp' || f.fieldType === 'date')
|
||||
);
|
||||
|
||||
const anyTimeField = fields.find((f) => f.fieldType === 'timestamp' || f.fieldType === 'date');
|
||||
|
||||
const timeFieldId = (modifiedField || anyTimeField)?.id || 6;
|
||||
|
||||
const query = {
|
||||
from: tableId,
|
||||
select,
|
||||
sortBy: [
|
||||
{
|
||||
fieldId: timeFieldId,
|
||||
order: 'DESC',
|
||||
},
|
||||
],
|
||||
options: {
|
||||
top: 100,
|
||||
},
|
||||
};
|
||||
|
||||
const response = await client.post<QuickbaseRecordResponse>('/records/query', query);
|
||||
|
||||
const isTest = lastFetchEpochMS === 0;
|
||||
|
||||
return response.data
|
||||
.map((record) => {
|
||||
const timeFieldKey = timeFieldId.toString();
|
||||
const rawValue = record[timeFieldKey]?.value;
|
||||
|
||||
let epoch: number;
|
||||
if (rawValue) {
|
||||
epoch = new Date(rawValue).getTime();
|
||||
} else {
|
||||
|
||||
epoch = Date.now();
|
||||
}
|
||||
|
||||
return {
|
||||
epochMilliSeconds: epoch,
|
||||
data: record,
|
||||
};
|
||||
})
|
||||
.filter((item) => item.epochMilliSeconds > lastFetchEpochMS);
|
||||
},
|
||||
};
|
||||
|
||||
export const newOrUpdatedRecord = createTrigger({
|
||||
auth: quickbaseAuth,
|
||||
name: 'new_or_updated_record',
|
||||
displayName: 'New or Updated Record',
|
||||
description: 'Triggers when a record is created or updated in a Quickbase table',
|
||||
props,
|
||||
type: TriggerStrategy.POLLING,
|
||||
sampleData: {
|
||||
},
|
||||
async onEnable(context) {
|
||||
const { store, auth, propsValue } = context;
|
||||
await pollingHelper.onEnable(polling, { store, auth, propsValue });
|
||||
},
|
||||
async onDisable(context) {
|
||||
const { store, auth, propsValue } = context;
|
||||
await pollingHelper.onDisable(polling, { store, auth, propsValue });
|
||||
},
|
||||
async run(context) {
|
||||
const { store, auth, propsValue, files } = context;
|
||||
return await pollingHelper.poll(polling, { store, auth, propsValue, files });
|
||||
},
|
||||
async test(context) {
|
||||
const { store, auth, propsValue, files } = context;
|
||||
return await pollingHelper.test(polling, { store, auth, propsValue, files });
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,97 @@
|
||||
import { createTrigger, TriggerStrategy, StaticPropsValue, AppConnectionValueForAuthProperty } from '@activepieces/pieces-framework';
|
||||
import { quickbaseAuth } from '../../index';
|
||||
import { appIdProp, tableIdProp } from '../common/props';
|
||||
import { QuickbaseClient } from '../common/client';
|
||||
import { QuickbaseRecordResponse, QuickbaseField } from '../common/types';
|
||||
import { generateDeduplicationKey, extractRecordValues } from '../common/utils';
|
||||
import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common';
|
||||
|
||||
const props = {
|
||||
appId: appIdProp,
|
||||
tableId: tableIdProp,
|
||||
};
|
||||
|
||||
type QuickbaseAuth = AppConnectionValueForAuthProperty<typeof quickbaseAuth>;
|
||||
|
||||
const polling: Polling<QuickbaseAuth, StaticPropsValue<typeof props>> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
items: async ({ auth, propsValue, lastFetchEpochMS }: { auth: QuickbaseAuth; propsValue: StaticPropsValue<typeof props>; lastFetchEpochMS: number }) => {
|
||||
const { appId, tableId } = propsValue;
|
||||
const client = new QuickbaseClient(auth.props.realmHostname, auth.props.userToken);
|
||||
|
||||
const tableFields = await client.get<QuickbaseField[]>(`/fields?tableId=${tableId}`);
|
||||
const dateCreatedField = tableFields.find(
|
||||
(f) => f.fieldType === 'timestamp' && f.label.toLowerCase().includes('created')
|
||||
);
|
||||
|
||||
if (!dateCreatedField) {
|
||||
throw new Error(
|
||||
'No date created field found in table. A timestamp field with "created" in the name is required.'
|
||||
);
|
||||
}
|
||||
|
||||
const query = {
|
||||
from: tableId,
|
||||
select: tableFields.map((f) => f.id),
|
||||
sortBy: [{ fieldId: dateCreatedField.id, order: 'DESC' as const }],
|
||||
options: { top: 100 },
|
||||
};
|
||||
|
||||
const response = await client.post<QuickbaseRecordResponse>('/records/query', query);
|
||||
|
||||
const isTest = lastFetchEpochMS === 0;
|
||||
|
||||
return response.data
|
||||
.map((record) => {
|
||||
const recordId = record['3']?.value;
|
||||
const dateCreated = record[dateCreatedField.id.toString()]?.value;
|
||||
|
||||
const epoch = dateCreated ? new Date(dateCreated).getTime() : Date.now();
|
||||
|
||||
return {
|
||||
epochMilliSeconds: epoch,
|
||||
data: {
|
||||
id: generateDeduplicationKey(recordId, dateCreated),
|
||||
created_at: dateCreated,
|
||||
updated_at:
|
||||
record[
|
||||
tableFields.find(
|
||||
(f) => f.fieldType === 'timestamp' && f.label.toLowerCase().includes('modified')
|
||||
)?.id.toString() || ''
|
||||
]?.value || dateCreated,
|
||||
recordId,
|
||||
tableId,
|
||||
appId,
|
||||
fields: extractRecordValues(record),
|
||||
},
|
||||
};
|
||||
})
|
||||
.filter((item) => isTest || item.epochMilliSeconds > lastFetchEpochMS);
|
||||
},
|
||||
};
|
||||
|
||||
export const newRecord = createTrigger({
|
||||
name: 'new_record',
|
||||
displayName: 'New Record',
|
||||
description: 'Triggers when a new record is created in a Quickbase table',
|
||||
auth: quickbaseAuth,
|
||||
props,
|
||||
type: TriggerStrategy.POLLING,
|
||||
sampleData: {},
|
||||
async onEnable(context) {
|
||||
const { store, auth, propsValue } = context;
|
||||
await pollingHelper.onEnable(polling, { store, auth, propsValue });
|
||||
},
|
||||
async onDisable(context) {
|
||||
const { store, auth, propsValue } = context;
|
||||
await pollingHelper.onDisable(polling, { store, auth, propsValue });
|
||||
},
|
||||
async run(context) {
|
||||
const { store, auth, propsValue, files } = context;
|
||||
return await pollingHelper.poll(polling, { store, auth, propsValue, files });
|
||||
},
|
||||
async test(context) {
|
||||
const { store, auth, propsValue, files } = context;
|
||||
return await pollingHelper.test(polling, { store, auth, propsValue, files });
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"extends": "../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"importHelpers": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noPropertyAccessFromIndexSignature": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user