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-formstack
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Building
|
||||
|
||||
Run `nx build pieces-formstack` to build the library.
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "@activepieces/piece-formstack",
|
||||
"version": "0.0.10"
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"name": "pieces-formstack",
|
||||
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "packages/pieces/community/formstack/src",
|
||||
"projectType": "library",
|
||||
"release": {
|
||||
"version": {
|
||||
"currentVersionResolver": "git-tag",
|
||||
"preserveLocalDependencyProtocols": false,
|
||||
"manifestRootsToUpdate": [
|
||||
"dist/{projectRoot}"
|
||||
]
|
||||
}
|
||||
},
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/js:tsc",
|
||||
"outputs": [
|
||||
"{options.outputPath}"
|
||||
],
|
||||
"options": {
|
||||
"outputPath": "dist/packages/pieces/community/formstack",
|
||||
"tsConfig": "packages/pieces/community/formstack/tsconfig.lib.json",
|
||||
"packageJson": "packages/pieces/community/formstack/package.json",
|
||||
"main": "packages/pieces/community/formstack/src/index.ts",
|
||||
"assets": [
|
||||
"packages/pieces/community/formstack/*.md",
|
||||
{
|
||||
"input": "packages/pieces/community/formstack/src/i18n",
|
||||
"output": "./src/i18n",
|
||||
"glob": "**/!(i18n.json)"
|
||||
}
|
||||
],
|
||||
"buildableProjectDepsInPackageJsonType": "dependencies",
|
||||
"updateBuildableProjectDepsInPackageJson": true
|
||||
},
|
||||
"dependsOn": [
|
||||
"^build",
|
||||
"prebuild"
|
||||
]
|
||||
},
|
||||
"nx-release-publish": {
|
||||
"options": {
|
||||
"packageRoot": "dist/{projectRoot}"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint",
|
||||
"outputs": [
|
||||
"{options.outputFile}"
|
||||
]
|
||||
},
|
||||
"prebuild": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"cwd": "packages/pieces/community/formstack",
|
||||
"command": "bun install --no-save --silent"
|
||||
},
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"Connect your Formstack account": "Verbinden Sie Ihren Formstack Account",
|
||||
"Create Submission": "Einreichung erstellen",
|
||||
"Find Form by Name or ID": "Formular nach Name oder ID suchen",
|
||||
"Get Submission Details": "Einreichungsdetails abrufen",
|
||||
"Find Submission by Field Value": "Suche Einreichung nach Feldwert",
|
||||
"Custom API Call": "Eigener API-Aufruf",
|
||||
"Submit data to a Formstack form": "Daten an ein Formstack-Formular senden",
|
||||
"Find a form by name or ID": "Suche ein Formular mit Namen oder ID",
|
||||
"Get details of a form submission": "Details zu einer Formularabgabe erhalten",
|
||||
"Search submissions by field values": "Durchsuche Einreichungen nach Feldwerten",
|
||||
"Make a custom API call to a specific endpoint": "Einen benutzerdefinierten API-Aufruf an einen bestimmten Endpunkt machen",
|
||||
"Forms ": "Formulare ",
|
||||
"User Agent": "User-Agent",
|
||||
"IP Address": "IP-Adresse",
|
||||
"Payment Status": "Zahlungsstatus",
|
||||
"Mark as Read": "Als gelesen markieren",
|
||||
"Encryption Password": "Verschlüsselungspasswort",
|
||||
"Form Fields": "Formularfelder",
|
||||
"Form Name or ID": "Formularname oder ID",
|
||||
"Group by Folders": "Nach Ordnern gruppieren",
|
||||
"Exact Name Match": "Genaues Namensmatch",
|
||||
"Submission": "Einreichung",
|
||||
"Include Technical Metadata": "Technische Metadaten einbeziehen",
|
||||
"Search Value": "Suchwert",
|
||||
"Results Per Page": "Ergebnisse pro Seite",
|
||||
"Page Number": "Seitennummer",
|
||||
"Sort Order": "Sortierung",
|
||||
"Include Form Names": "Formularnamen einschließen",
|
||||
"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)",
|
||||
"Browser user agent to record": "Browser-User-Agent zum Aufzeichnen",
|
||||
"IP address to record": "Zu erfassende IP-Adresse",
|
||||
"Payment integration status": "Status der Zahlungsintegration",
|
||||
"Mark submission as read when created": "Vorlage als gelesen markieren, wenn erstellt",
|
||||
"Password for encrypted forms": "Passwort für verschlüsselte Formulare",
|
||||
"Fill out the form fields": "Formularfelder ausfüllen",
|
||||
"Enter form name or ID to search": "Formularname oder ID zur Suche eingeben",
|
||||
"Organize results by folders": "Ergebnisse nach Ordnern organisieren",
|
||||
"Only exact name matches": "Nur exakte Namensübereinstimmung",
|
||||
"Include IP, user agent, and location data": "IP, User-Agent und Standortdaten einbeziehen",
|
||||
"Value to search for (minimum 3 characters)": "Wert für die Suche (mindestens 3 Zeichen)",
|
||||
"Number of results per page (1-100)": "Anzahl der Ergebnisse pro Seite (1-100)",
|
||||
"Page number to return": "Rückzugebende Seitennummer",
|
||||
"Sort results by submission ID": "Ergebnisse nach Einreichungs-ID sortieren",
|
||||
"Include form names in results": "Formularnamen in Ergebnisse einfügen",
|
||||
"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..",
|
||||
"Newest First (DESC)": "Neueste zuerst (DESC)",
|
||||
"Oldest First (ASC)": "Älteste zuerst (ASC)",
|
||||
"GET": "ERHALTEN",
|
||||
"POST": "POST",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "LÖSCHEN",
|
||||
"HEAD": "HEAD",
|
||||
"New Submission": "Neue Einreichung",
|
||||
"New Form": "Neues Formular",
|
||||
"Triggers when a form receives a new submission": "Wird ausgelöst, wenn ein Formular eine neue Einreichung erhält",
|
||||
"Triggers when a new form is created": "Wird ausgelöst, wenn ein neues Formular erstellt wird"
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"Connect your Formstack account": "Conecte su cuenta Formstack",
|
||||
"Create Submission": "Crear Envío",
|
||||
"Find Form by Name or ID": "Buscar formulario por nombre o ID",
|
||||
"Get Submission Details": "Obtener detalles del envío",
|
||||
"Find Submission by Field Value": "Encontrar envío por valor de campo",
|
||||
"Custom API Call": "Llamada API personalizada",
|
||||
"Submit data to a Formstack form": "Enviar datos a un Formstack",
|
||||
"Find a form by name or ID": "Encontrar un formulario por nombre o ID",
|
||||
"Get details of a form submission": "Obtener detalles del envío de un formulario",
|
||||
"Search submissions by field values": "Buscar envíos por valores de campo",
|
||||
"Make a custom API call to a specific endpoint": "Hacer una llamada API personalizada a un extremo específico",
|
||||
"Forms ": "Formularios ",
|
||||
"User Agent": "Agente de usuario",
|
||||
"IP Address": "Dirección IP",
|
||||
"Payment Status": "Estado del pago",
|
||||
"Mark as Read": "Marcar como leído",
|
||||
"Encryption Password": "Contraseña del cifrado",
|
||||
"Form Fields": "Campos de Formulario",
|
||||
"Form Name or ID": "Nombre del formulario o ID",
|
||||
"Group by Folders": "Agrupar por carpetas",
|
||||
"Exact Name Match": "Nombre exacto coincidencia",
|
||||
"Submission": "Envío",
|
||||
"Include Technical Metadata": "Incluye metadatos técnicos",
|
||||
"Search Value": "Valor de búsqueda",
|
||||
"Results Per Page": "Resultados por página",
|
||||
"Page Number": "Número de página",
|
||||
"Sort Order": "Ordenar",
|
||||
"Include Form Names": "Incluye nombres de formulario",
|
||||
"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)",
|
||||
"Browser user agent to record": "Navegar agente de usuario para registrar",
|
||||
"IP address to record": "Dirección IP a grabar",
|
||||
"Payment integration status": "Estado de integración de pago",
|
||||
"Mark submission as read when created": "Marcar envío como leído cuando se crea",
|
||||
"Password for encrypted forms": "Contraseña para formularios cifrados",
|
||||
"Fill out the form fields": "Rellene los campos del formulario",
|
||||
"Enter form name or ID to search": "Introduzca nombre de formulario o ID para buscar",
|
||||
"Organize results by folders": "Organizar resultados por carpetas",
|
||||
"Only exact name matches": "Sólo coincidencias de nombres exactos",
|
||||
"Include IP, user agent, and location data": "Incluye IP, agente de usuario y datos de ubicación",
|
||||
"Value to search for (minimum 3 characters)": "Valor para buscar (mínimo 3 caracteres)",
|
||||
"Number of results per page (1-100)": "Número de resultados por página (1-100)",
|
||||
"Page number to return": "Número de página a devolver",
|
||||
"Sort results by submission ID": "Ordenar resultados por ID de envío",
|
||||
"Include form names in results": "Incluye nombres de formulario en los resultados",
|
||||
"Authorization headers are injected automatically from your connection.": "Las cabeceras de autorización se inyectan automáticamente desde tu conexión.",
|
||||
"Enable for files like PDFs, images, etc..": "Activar para archivos como PDFs, imágenes, etc.",
|
||||
"Newest First (DESC)": "Más reciente primero (DESC)",
|
||||
"Oldest First (ASC)": "Lo más antiguo primero (ASC)",
|
||||
"GET": "RECOGER",
|
||||
"POST": "POST",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "BORRAR",
|
||||
"HEAD": "LIMPIO",
|
||||
"New Submission": "Nuevo envío",
|
||||
"New Form": "Nuevo Formulario",
|
||||
"Triggers when a form receives a new submission": "Dispara cuando un formulario recibe un nuevo envío",
|
||||
"Triggers when a new form is created": "Dispara cuando se crea un nuevo formulario"
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"Connect your Formstack account": "Connectez votre compte Formstack",
|
||||
"Create Submission": "Créer une soumission",
|
||||
"Find Form by Name or ID": "Formulaire de recherche par nom ou ID",
|
||||
"Get Submission Details": "Obtenir les détails de la soumission",
|
||||
"Find Submission by Field Value": "Rechercher la soumission par valeur de champ",
|
||||
"Custom API Call": "Appel d'API personnalisé",
|
||||
"Submit data to a Formstack form": "Soumettre des données à un formulaire Formstack",
|
||||
"Find a form by name or ID": "Trouver un formulaire par nom ou ID",
|
||||
"Get details of a form submission": "Obtenir les détails d'une soumission de formulaire",
|
||||
"Search submissions by field values": "Rechercher les soumissions par valeur de champ",
|
||||
"Make a custom API call to a specific endpoint": "Passer un appel API personnalisé à un endpoint spécifique",
|
||||
"Forms ": "Formulaires ",
|
||||
"User Agent": "Agent Utilisateur",
|
||||
"IP Address": "Adresse IP",
|
||||
"Payment Status": "Statut du paiement",
|
||||
"Mark as Read": "Marquer comme lu",
|
||||
"Encryption Password": "Mot de passe de chiffrement",
|
||||
"Form Fields": "Champs de formulaire",
|
||||
"Form Name or ID": "Nom du formulaire ou ID",
|
||||
"Group by Folders": "Grouper par dossiers",
|
||||
"Exact Name Match": "Correspondance de nom exacte",
|
||||
"Submission": "Soumission",
|
||||
"Include Technical Metadata": "Inclure les métadonnées techniques",
|
||||
"Search Value": "Valeur de la recherche",
|
||||
"Results Per Page": "Résultats par page",
|
||||
"Page Number": "Numéro de page",
|
||||
"Sort Order": "Ordre de tri",
|
||||
"Include Form Names": "Inclure les noms de formulaire",
|
||||
"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)",
|
||||
"Browser user agent to record": "Navigateur utilisateur à enregistrer",
|
||||
"IP address to record": "Adresse IP à enregistrer",
|
||||
"Payment integration status": "Statut de l'intégration du paiement",
|
||||
"Mark submission as read when created": "Marquer la soumission comme lue lors de la création",
|
||||
"Password for encrypted forms": "Mot de passe pour les formulaires chiffrés",
|
||||
"Fill out the form fields": "Remplissez les champs du formulaire",
|
||||
"Enter form name or ID to search": "Entrez le nom du formulaire ou l'ID à rechercher",
|
||||
"Organize results by folders": "Organiser les résultats par dossiers",
|
||||
"Only exact name matches": "Seul le nom exact correspond",
|
||||
"Include IP, user agent, and location data": "Inclure les données IP, l'agent utilisateur et la localisation",
|
||||
"Value to search for (minimum 3 characters)": "Valeur à rechercher (minimum 3 caractères)",
|
||||
"Number of results per page (1-100)": "Nombre de résultats par page (1-100)",
|
||||
"Page number to return": "Numéro de page à retourner",
|
||||
"Sort results by submission ID": "Trier les résultats par ID de remise",
|
||||
"Include form names in results": "Inclure les noms des formulaires dans les résultats",
|
||||
"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.",
|
||||
"Newest First (DESC)": "Plus récent en premier (DESC)",
|
||||
"Oldest First (ASC)": "Le plus ancien en premier (ASC)",
|
||||
"GET": "GET",
|
||||
"POST": "POST",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "DELETE",
|
||||
"HEAD": "HEAD",
|
||||
"New Submission": "Nouvelle soumission",
|
||||
"New Form": "Nouveau formulaire",
|
||||
"Triggers when a form receives a new submission": "Déclenche lorsqu'un formulaire reçoit une nouvelle soumission",
|
||||
"Triggers when a new form is created": "Déclenche lorsqu'un nouveau formulaire est créé"
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"Connect your Formstack account": "Formstackアカウントに接続",
|
||||
"Create Submission": "提出物を作成",
|
||||
"Find Form by Name or ID": "名前またはIDでフォームを検索",
|
||||
"Get Submission Details": "提出物の詳細を取得する",
|
||||
"Find Submission by Field Value": "フィールド値で提出物を検索",
|
||||
"Custom API Call": "カスタムAPI通話",
|
||||
"Submit data to a Formstack form": "フォームスタックフォームにデータを送信",
|
||||
"Find a form by name or ID": "名前またはIDでフォームを検索",
|
||||
"Get details of a form submission": "フォーム送信の詳細を取得します。",
|
||||
"Search submissions by field values": "フィールド値で提出物を検索",
|
||||
"Make a custom API call to a specific endpoint": "特定のエンドポイントへのカスタム API コールを実行します。",
|
||||
"Forms ": "フォーム ",
|
||||
"User Agent": "ユーザーエージェント",
|
||||
"IP Address": "IP アドレス",
|
||||
"Payment Status": "支払ステータス",
|
||||
"Mark as Read": "既読にする",
|
||||
"Encryption Password": "暗号化パスワード",
|
||||
"Form Fields": "フォームフィールド",
|
||||
"Form Name or ID": "フォーム名またはID",
|
||||
"Group by Folders": "フォルダ別にグループ化",
|
||||
"Exact Name Match": "完全な名前一致",
|
||||
"Submission": "提出",
|
||||
"Include Technical Metadata": "技術的なメタデータを含める",
|
||||
"Search Value": "検索値",
|
||||
"Results Per Page": "ページ毎の結果",
|
||||
"Page Number": "ページ番号",
|
||||
"Sort Order": "並び順",
|
||||
"Include Form Names": "フォーム名を含める",
|
||||
"Method": "方法",
|
||||
"Headers": "ヘッダー",
|
||||
"Query Parameters": "クエリパラメータ",
|
||||
"Body": "本文",
|
||||
"Response is Binary ?": "応答はバイナリですか?",
|
||||
"No Error on Failure": "失敗時にエラーはありません",
|
||||
"Timeout (in seconds)": "タイムアウト(秒)",
|
||||
"Browser user agent to record": "録画するブラウザーユーザーエージェント",
|
||||
"IP address to record": "記録するIPアドレス",
|
||||
"Payment integration status": "Payment integration status",
|
||||
"Mark submission as read when created": "作成時に提出物を既読にする",
|
||||
"Password for encrypted forms": "暗号化されたフォームのパスワード",
|
||||
"Fill out the form fields": "フォームフィールドに入力してください",
|
||||
"Enter form name or ID to search": "検索するフォーム名またはIDを入力してください",
|
||||
"Organize results by folders": "フォルダごとに結果を整理する",
|
||||
"Only exact name matches": "一致する名前のみです",
|
||||
"Include IP, user agent, and location data": "IP、ユーザーエージェント、位置情報データを含める",
|
||||
"Value to search for (minimum 3 characters)": "検索する値 (最低3文字)",
|
||||
"Number of results per page (1-100)": "Number of results per page (1-100)",
|
||||
"Page number to return": "戻るページ番号",
|
||||
"Sort results by submission ID": "提出物IDで結果をソート",
|
||||
"Include form names in results": "フォーム名を結果に含める",
|
||||
"Authorization headers are injected automatically from your connection.": "認証ヘッダは接続から自動的に注入されます。",
|
||||
"Enable for files like PDFs, images, etc..": "PDF、画像などのファイルを有効にします。",
|
||||
"Newest First (DESC)": "最近の最初(降順)",
|
||||
"Oldest First (ASC)": "古い順 (ASC)",
|
||||
"GET": "取得",
|
||||
"POST": "POST",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "削除",
|
||||
"HEAD": "頭",
|
||||
"New Submission": "新しい提出",
|
||||
"New Form": "新しいフォーム",
|
||||
"Triggers when a form receives a new submission": "フォームが新しい提出物を受け取ったときにトリガーします",
|
||||
"Triggers when a new form is created": "新しいフォームが作成されたときにトリガーします"
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"Connect your Formstack account": "Verbind uw Formstack account",
|
||||
"Create Submission": "Indiening aanmaken",
|
||||
"Find Form by Name or ID": "Formulier zoeken op naam of ID",
|
||||
"Get Submission Details": "Krijg inzending details",
|
||||
"Find Submission by Field Value": "Zoek inzending op veldwaarde",
|
||||
"Custom API Call": "Custom API Call",
|
||||
"Submit data to a Formstack form": "Verstuur gegevens naar een Formstack formulier",
|
||||
"Find a form by name or ID": "Zoek een formulier op naam of ID",
|
||||
"Get details of a form submission": "Krijg details van een formulier uitwerking",
|
||||
"Search submissions by field values": "Zoek inzendingen op veldwaarden",
|
||||
"Make a custom API call to a specific endpoint": "Maak een aangepaste API call naar een specifiek eindpunt",
|
||||
"Forms ": "Formulieren ",
|
||||
"User Agent": "User Agent",
|
||||
"IP Address": "IP adres",
|
||||
"Payment Status": "Betalings Status",
|
||||
"Mark as Read": "Markeren als gelezen",
|
||||
"Encryption Password": "Encryptie wachtwoord",
|
||||
"Form Fields": "Formulier velden",
|
||||
"Form Name or ID": "Formulier naam of ID",
|
||||
"Group by Folders": "Groeperen op mappen",
|
||||
"Exact Name Match": "Exacte naam overeenkomst",
|
||||
"Submission": "Inzending",
|
||||
"Include Technical Metadata": "Inclusief technische metadata",
|
||||
"Search Value": "Waarde zoeken",
|
||||
"Results Per Page": "Resultaten per pagina",
|
||||
"Page Number": "Pagina Nummer",
|
||||
"Sort Order": "Sorteren bestelling",
|
||||
"Include Form Names": "Formuliernamen opnemen",
|
||||
"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)",
|
||||
"Browser user agent to record": "Browser gebruikersagent om te registreren",
|
||||
"IP address to record": "IP-adres om op te nemen",
|
||||
"Payment integration status": "Integratiestatus van betaling",
|
||||
"Mark submission as read when created": "Markeer inzending als gelezen wanneer gemaakt",
|
||||
"Password for encrypted forms": "Wachtwoord voor versleutelde formulieren",
|
||||
"Fill out the form fields": "Vul de formuliervelden in",
|
||||
"Enter form name or ID to search": "Voer formuliernaam of ID in om te zoeken",
|
||||
"Organize results by folders": "Resultaten organiseren door mappen",
|
||||
"Only exact name matches": "Alleen exacte naam overeenkomsten",
|
||||
"Include IP, user agent, and location data": "Inclusief IP-, gebruikers- en locatiegegevens",
|
||||
"Value to search for (minimum 3 characters)": "Waarde om naar te zoeken (minimum 3 tekens)",
|
||||
"Number of results per page (1-100)": "Aantal resultaten per pagina (1-100)",
|
||||
"Page number to return": "Pagina nummer om te retourneren",
|
||||
"Sort results by submission ID": "Sorteer resultaten op indienings-ID",
|
||||
"Include form names in results": "Formuliernamen in zoekresultaten opnemen",
|
||||
"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..",
|
||||
"Newest First (DESC)": "Nieuwste eerst (AFLOPEND)",
|
||||
"Oldest First (ASC)": "Oudste eerst (ASC)",
|
||||
"GET": "KRIJG",
|
||||
"POST": "POSTE",
|
||||
"PATCH": "BEKIJK",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "VERWIJDEREN",
|
||||
"HEAD": "HOOFD",
|
||||
"New Submission": "Nieuwe inzending",
|
||||
"New Form": "Nieuw formulier",
|
||||
"Triggers when a form receives a new submission": "Triggert wanneer een formulier een nieuwe uitwerking ontvangt",
|
||||
"Triggers when a new form is created": "Triggert wanneer een nieuw formulier wordt aangemaakt"
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"Connect your Formstack account": "Conecte sua conta do Formstack",
|
||||
"Create Submission": "Criar Submissão",
|
||||
"Find Form by Name or ID": "Localizar Formulário por Nome ou ID",
|
||||
"Get Submission Details": "Obter detalhes do envio",
|
||||
"Find Submission by Field Value": "Encontrar Submissão por Valor do Campo",
|
||||
"Custom API Call": "Chamada de API personalizada",
|
||||
"Submit data to a Formstack form": "Enviar dados a um formulário de Formstack",
|
||||
"Find a form by name or ID": "Encontrar um formulário por nome ou ID",
|
||||
"Get details of a form submission": "Obter detalhes de um envio do formulário",
|
||||
"Search submissions by field values": "Pesquisar submissões por valores de campo",
|
||||
"Make a custom API call to a specific endpoint": "Faça uma chamada de API personalizada para um ponto de extremidade específico",
|
||||
"Forms ": "Formulários ",
|
||||
"User Agent": "Agente do usuário",
|
||||
"IP Address": "Endereço IP",
|
||||
"Payment Status": "Status do pagamento",
|
||||
"Mark as Read": "Marcar Como Lida",
|
||||
"Encryption Password": "Senha de Criptografia",
|
||||
"Form Fields": "Campos do formulário",
|
||||
"Form Name or ID": "Nome do formulário ou ID",
|
||||
"Group by Folders": "Agrupar por pastas",
|
||||
"Exact Name Match": "Correspondência de nome exata",
|
||||
"Submission": "Submissão",
|
||||
"Include Technical Metadata": "Incluir Metadados Técnicos",
|
||||
"Search Value": "Pesquisar Valor",
|
||||
"Results Per Page": "Resultados por Página",
|
||||
"Page Number": "Número da página",
|
||||
"Sort Order": "Ordem de classificação",
|
||||
"Include Form Names": "Incluir Nomes dos Formulários",
|
||||
"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)",
|
||||
"Browser user agent to record": "Agente de usuário do navegador para gravar",
|
||||
"IP address to record": "Endereço de IP para gravar",
|
||||
"Payment integration status": "Integração de pagamento",
|
||||
"Mark submission as read when created": "Marcar submissão como lida quando criada",
|
||||
"Password for encrypted forms": "Senha para formulários criptografados",
|
||||
"Fill out the form fields": "Preencha os campos do formulário",
|
||||
"Enter form name or ID to search": "Digite o nome do formulário ou ID para pesquisar",
|
||||
"Organize results by folders": "Organizar resultados por pastas",
|
||||
"Only exact name matches": "Apenas nomes exatos correspondem",
|
||||
"Include IP, user agent, and location data": "Incluir IP, usuário agente e dados de localização",
|
||||
"Value to search for (minimum 3 characters)": "Valor a ser pesquisado (mínimo de 3 caracteres)",
|
||||
"Number of results per page (1-100)": "Número de resultados por página (1-100)",
|
||||
"Page number to return": "Número da página a retornar",
|
||||
"Sort results by submission ID": "Ordenar resultados por ID da submissão",
|
||||
"Include form names in results": "Incluir nomes de formulários nos resultados",
|
||||
"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..",
|
||||
"Newest First (DESC)": "Mais recentes (DESC)",
|
||||
"Oldest First (ASC)": "Mais antigos primeiro (ASC)",
|
||||
"GET": "OBTER",
|
||||
"POST": "POSTAR",
|
||||
"PATCH": "COMPRAR",
|
||||
"PUT": "COLOCAR",
|
||||
"DELETE": "EXCLUIR",
|
||||
"HEAD": "CABEÇA",
|
||||
"New Submission": "Nova Submissão",
|
||||
"New Form": "Novo Formulário",
|
||||
"Triggers when a form receives a new submission": "Aciona quando um formulário recebe uma nova submissão",
|
||||
"Triggers when a new form is created": "Dispara quando um novo formulário é criado"
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"Formstack": "Формастек",
|
||||
"Connect your Formstack account": "Подключите ваш аккаунт Formstack",
|
||||
"Create Submission": "Создать сообщение",
|
||||
"Find Form by Name or ID": "Найти форму по имени или ID",
|
||||
"Get Submission Details": "Получить детали сданной работы",
|
||||
"Find Submission by Field Value": "Поиск сообщения по значению поля",
|
||||
"Submit data to a Formstack form": "Отправить данные в форму Formstack",
|
||||
"Find a form by name or ID": "Найти форму по имени или ID",
|
||||
"Get details of a form submission": "Получить подробную информацию об отправке формы",
|
||||
"Search submissions by field values": "Поиск по значениям полей",
|
||||
"Forms ": "Формы ",
|
||||
"User Agent": "User Agent",
|
||||
"IP Address": "IP-адрес",
|
||||
"Payment Status": "Статус платежа",
|
||||
"Mark as Read": "Отметить как прочитанное",
|
||||
"Encryption Password": "Пароль шифрования",
|
||||
"Form Fields": "Поля формы",
|
||||
"Form Name or ID": "Имя или ID формы",
|
||||
"Group by Folders": "Группировать по папкам",
|
||||
"Exact Name Match": "Точное соответствие имен",
|
||||
"Submission": "Представление",
|
||||
"Include Technical Metadata": "Включить технические метаданные",
|
||||
"Search Value": "Поисковое значение",
|
||||
"Results Per Page": "Результаты на странице",
|
||||
"Page Number": "Номер страницы",
|
||||
"Sort Order": "Порядок сортировки",
|
||||
"Include Form Names": "Включить имена форм",
|
||||
"Browser user agent to record": "Браузер пользователя агента для записи",
|
||||
"IP address to record": "IP адрес для записи",
|
||||
"Payment integration status": "Статус интеграции платежа",
|
||||
"Mark submission as read when created": "Отметить сабмит как прочитанный при создании",
|
||||
"Password for encrypted forms": "Пароль для зашифрованных форм",
|
||||
"Fill out the form fields": "Заполните поля формы",
|
||||
"Enter form name or ID to search": "Введите имя формы или ID для поиска",
|
||||
"Organize results by folders": "Организовать результаты по папкам",
|
||||
"Only exact name matches": "Только точное имя совпадает",
|
||||
"Include IP, user agent, and location data": "Включить IP, агент пользователя и данные местоположения",
|
||||
"Value to search for (minimum 3 characters)": "Значение для поиска (минимум 3 символа)",
|
||||
"Number of results per page (1-100)": "Количество результатов на странице (1-100)",
|
||||
"Page number to return": "Возвращаемый номер страницы",
|
||||
"Sort results by submission ID": "Сортировать результаты по ID сдачи",
|
||||
"Include form names in results": "Включить имена форм в результаты",
|
||||
"Newest First (DESC)": "Первое новое (DESC)",
|
||||
"Oldest First (ASC)": "Сначала старые (ASC)",
|
||||
"New Submission": "Новая заявка",
|
||||
"New Form": "Новая форма",
|
||||
"Triggers when a form receives a new submission": "Срабатывает при получении формы",
|
||||
"Triggers when a new form is created": "Триггеры при создании новой формы"
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"Connect your Formstack account": "Connect your Formstack account",
|
||||
"Create Submission": "Create Submission",
|
||||
"Find Form by Name or ID": "Find Form by Name or ID",
|
||||
"Get Submission Details": "Get Submission Details",
|
||||
"Find Submission by Field Value": "Find Submission by Field Value",
|
||||
"Custom API Call": "Custom API Call",
|
||||
"Submit data to a Formstack form": "Submit data to a Formstack form",
|
||||
"Find a form by name or ID": "Find a form by name or ID",
|
||||
"Get details of a form submission": "Get details of a form submission",
|
||||
"Search submissions by field values": "Search submissions by field values",
|
||||
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
|
||||
"Forms ": "Forms ",
|
||||
"User Agent": "User Agent",
|
||||
"IP Address": "IP Address",
|
||||
"Payment Status": "Payment Status",
|
||||
"Mark as Read": "Mark as Read",
|
||||
"Encryption Password": "Encryption Password",
|
||||
"Form Fields": "Form Fields",
|
||||
"Form Name or ID": "Form Name or ID",
|
||||
"Group by Folders": "Group by Folders",
|
||||
"Exact Name Match": "Exact Name Match",
|
||||
"Submission": "Submission",
|
||||
"Include Technical Metadata": "Include Technical Metadata",
|
||||
"Search Value": "Search Value",
|
||||
"Results Per Page": "Results Per Page",
|
||||
"Page Number": "Page Number",
|
||||
"Sort Order": "Sort Order",
|
||||
"Include Form Names": "Include Form Names",
|
||||
"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)",
|
||||
"Browser user agent to record": "Browser user agent to record",
|
||||
"IP address to record": "IP address to record",
|
||||
"Payment integration status": "Payment integration status",
|
||||
"Mark submission as read when created": "Mark submission as read when created",
|
||||
"Password for encrypted forms": "Password for encrypted forms",
|
||||
"Fill out the form fields": "Fill out the form fields",
|
||||
"Enter form name or ID to search": "Enter form name or ID to search",
|
||||
"Organize results by folders": "Organize results by folders",
|
||||
"Only exact name matches": "Only exact name matches",
|
||||
"Include IP, user agent, and location data": "Include IP, user agent, and location data",
|
||||
"Value to search for (minimum 3 characters)": "Value to search for (minimum 3 characters)",
|
||||
"Number of results per page (1-100)": "Number of results per page (1-100)",
|
||||
"Page number to return": "Page number to return",
|
||||
"Sort results by submission ID": "Sort results by submission ID",
|
||||
"Include form names in results": "Include form names in results",
|
||||
"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..",
|
||||
"Newest First (DESC)": "Newest First (DESC)",
|
||||
"Oldest First (ASC)": "Oldest First (ASC)",
|
||||
"GET": "GET",
|
||||
"POST": "POST",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "DELETE",
|
||||
"HEAD": "HEAD",
|
||||
"New Submission": "New Submission",
|
||||
"New Form": "New Form",
|
||||
"Triggers when a form receives a new submission": "Triggers when a form receives a new submission",
|
||||
"Triggers when a new form is created": "Triggers when a new form is created"
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"Formstack": "Formstack",
|
||||
"Connect your Formstack account": "Connect your Formstack account",
|
||||
"Create Submission": "Create Submission",
|
||||
"Find Form by Name or ID": "Find Form by Name or ID",
|
||||
"Get Submission Details": "Get Submission Details",
|
||||
"Find Submission by Field Value": "Find Submission by Field Value",
|
||||
"Submit data to a Formstack form": "Submit data to a Formstack form",
|
||||
"Find a form by name or ID": "Find a form by name or ID",
|
||||
"Get details of a form submission": "Get details of a form submission",
|
||||
"Search submissions by field values": "Search submissions by field values",
|
||||
"Forms ": "Forms ",
|
||||
"User Agent": "User Agent",
|
||||
"IP Address": "IP Address",
|
||||
"Payment Status": "Payment Status",
|
||||
"Mark as Read": "Mark as Read",
|
||||
"Encryption Password": "Encryption Password",
|
||||
"Form Fields": "Form Fields",
|
||||
"Form Name or ID": "Form Name or ID",
|
||||
"Group by Folders": "Group by Folders",
|
||||
"Exact Name Match": "Exact Name Match",
|
||||
"Submission": "Submission",
|
||||
"Include Technical Metadata": "Include Technical Metadata",
|
||||
"Search Value": "Search Value",
|
||||
"Results Per Page": "Results Per Page",
|
||||
"Page Number": "Page Number",
|
||||
"Sort Order": "Sort Order",
|
||||
"Include Form Names": "Include Form Names",
|
||||
"Browser user agent to record": "Browser user agent to record",
|
||||
"IP address to record": "IP address to record",
|
||||
"Payment integration status": "Payment integration status",
|
||||
"Mark submission as read when created": "Mark submission as read when created",
|
||||
"Password for encrypted forms": "Password for encrypted forms",
|
||||
"Fill out the form fields": "Fill out the form fields",
|
||||
"Enter form name or ID to search": "Enter form name or ID to search",
|
||||
"Organize results by folders": "Organize results by folders",
|
||||
"Only exact name matches": "Only exact name matches",
|
||||
"Include IP, user agent, and location data": "Include IP, user agent, and location data",
|
||||
"Value to search for (minimum 3 characters)": "Value to search for (minimum 3 characters)",
|
||||
"Number of results per page (1-100)": "Number of results per page (1-100)",
|
||||
"Page number to return": "Page number to return",
|
||||
"Sort results by submission ID": "Sort results by submission ID",
|
||||
"Include form names in results": "Include form names in results",
|
||||
"Newest First (DESC)": "Newest First (DESC)",
|
||||
"Oldest First (ASC)": "Oldest First (ASC)",
|
||||
"New Submission": "New Submission",
|
||||
"New Form": "New Form",
|
||||
"Triggers when a form receives a new submission": "Triggers when a form receives a new submission",
|
||||
"Triggers when a new form is created": "Triggers when a new form is created"
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"Connect your Formstack account": "Connect your Formstack account",
|
||||
"Create Submission": "Create Submission",
|
||||
"Find Form by Name or ID": "Find Form by Name or ID",
|
||||
"Get Submission Details": "Get Submission Details",
|
||||
"Find Submission by Field Value": "Find Submission by Field Value",
|
||||
"Custom API Call": "自定义 API 呼叫",
|
||||
"Submit data to a Formstack form": "Submit data to a Formstack form",
|
||||
"Find a form by name or ID": "Find a form by name or ID",
|
||||
"Get details of a form submission": "Get details of a form submission",
|
||||
"Search submissions by field values": "Search submissions by field values",
|
||||
"Make a custom API call to a specific endpoint": "将一个自定义 API 调用到一个特定的终点",
|
||||
"Forms ": "Forms ",
|
||||
"User Agent": "User Agent",
|
||||
"IP Address": "IP 地址",
|
||||
"Payment Status": "Payment Status",
|
||||
"Mark as Read": "Mark as Read",
|
||||
"Encryption Password": "Encryption Password",
|
||||
"Form Fields": "Form Fields",
|
||||
"Form Name or ID": "Form Name or ID",
|
||||
"Group by Folders": "Group by Folders",
|
||||
"Exact Name Match": "Exact Name Match",
|
||||
"Submission": "Submission",
|
||||
"Include Technical Metadata": "Include Technical Metadata",
|
||||
"Search Value": "搜索值",
|
||||
"Results Per Page": "Results Per Page",
|
||||
"Page Number": "Page Number",
|
||||
"Sort Order": "Sort Order",
|
||||
"Include Form Names": "Include Form Names",
|
||||
"Method": "方法",
|
||||
"Headers": "信头",
|
||||
"Query Parameters": "查询参数",
|
||||
"Body": "正文内容",
|
||||
"Response is Binary ?": "Response is Binary ?",
|
||||
"No Error on Failure": "失败时没有错误",
|
||||
"Timeout (in seconds)": "超时(秒)",
|
||||
"Browser user agent to record": "Browser user agent to record",
|
||||
"IP address to record": "IP address to record",
|
||||
"Payment integration status": "Payment integration status",
|
||||
"Mark submission as read when created": "Mark submission as read when created",
|
||||
"Password for encrypted forms": "Password for encrypted forms",
|
||||
"Fill out the form fields": "Fill out the form fields",
|
||||
"Enter form name or ID to search": "Enter form name or ID to search",
|
||||
"Organize results by folders": "Organize results by folders",
|
||||
"Only exact name matches": "Only exact name matches",
|
||||
"Include IP, user agent, and location data": "Include IP, user agent, and location data",
|
||||
"Value to search for (minimum 3 characters)": "Value to search for (minimum 3 characters)",
|
||||
"Number of results per page (1-100)": "Number of results per page (1-100)",
|
||||
"Page number to return": "Page number to return",
|
||||
"Sort results by submission ID": "Sort results by submission ID",
|
||||
"Include form names in results": "Include form names in results",
|
||||
"Authorization headers are injected automatically from your connection.": "授权头自动从您的连接中注入。",
|
||||
"Enable for files like PDFs, images, etc..": "Enable for files like PDFs, images, etc..",
|
||||
"Newest First (DESC)": "Newest First (DESC)",
|
||||
"Oldest First (ASC)": "Oldest First (ASC)",
|
||||
"GET": "获取",
|
||||
"POST": "帖子",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "弹出",
|
||||
"DELETE": "删除",
|
||||
"HEAD": "黑色",
|
||||
"New Submission": "New Submission",
|
||||
"New Form": "New Form",
|
||||
"Triggers when a form receives a new submission": "Triggers when a form receives a new submission",
|
||||
"Triggers when a new form is created": "Triggers when a new form is created"
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import {
|
||||
createPiece,
|
||||
OAuth2PropertyValue,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { createCustomApiCallAction } from '@activepieces/pieces-common';
|
||||
import { formStackAuth } from './lib/common/auth';
|
||||
|
||||
import { createSubmission } from './lib/actions/create-submission';
|
||||
import { findFormByNameOrId } from './lib/actions/find-form-by-name-or-id';
|
||||
import { getSubmissionDetails } from './lib/actions/get-submission-details';
|
||||
import { findSubmissionByFieldValue } from './lib/actions/find-submission-by-field-value';
|
||||
|
||||
import { newSubmission } from './lib/triggers/new-submission';
|
||||
import { newForm } from './lib/triggers/new-form';
|
||||
import { BASE_URL } from './lib/common/client';
|
||||
|
||||
export const formstack = createPiece({
|
||||
displayName: 'Formstack',
|
||||
auth: formStackAuth,
|
||||
minimumSupportedRelease: '0.36.1',
|
||||
logoUrl: 'https://cdn.activepieces.com/pieces/formstack.png',
|
||||
authors: ['Sanket6652', 'onyedikachi-david'],
|
||||
actions: [
|
||||
createSubmission,
|
||||
findFormByNameOrId,
|
||||
getSubmissionDetails,
|
||||
findSubmissionByFieldValue,
|
||||
createCustomApiCallAction({
|
||||
baseUrl: () => BASE_URL,
|
||||
auth: formStackAuth,
|
||||
authMapping: async (auth) => {
|
||||
const authValue = auth as OAuth2PropertyValue;
|
||||
|
||||
return {
|
||||
Authorization: `Bearer ${authValue.access_token}`,
|
||||
};
|
||||
},
|
||||
}),
|
||||
],
|
||||
triggers: [newSubmission, newForm],
|
||||
});
|
||||
@@ -0,0 +1,427 @@
|
||||
import {
|
||||
createAction,
|
||||
OAuth2PropertyValue,
|
||||
Property,
|
||||
DynamicPropsValue,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { formIdDropdown } from '../common/props';
|
||||
import { formStackAuth } from '../common/auth';
|
||||
import { makeFormRequest, makeRequest } from '../common/client';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
|
||||
export const createSubmission = createAction({
|
||||
auth: formStackAuth,
|
||||
name: 'createSubmission',
|
||||
displayName: 'Create Submission',
|
||||
description: 'Submit data to a Formstack form',
|
||||
props: {
|
||||
form_id: formIdDropdown,
|
||||
user_agent: Property.ShortText({
|
||||
displayName: 'User Agent',
|
||||
description: 'Browser user agent to record',
|
||||
required: false,
|
||||
}),
|
||||
remote_addr: Property.ShortText({
|
||||
displayName: 'IP Address',
|
||||
description: 'IP address to record',
|
||||
required: false,
|
||||
}),
|
||||
payment_status: Property.ShortText({
|
||||
displayName: 'Payment Status',
|
||||
description: 'Payment integration status',
|
||||
required: false,
|
||||
}),
|
||||
read: Property.Checkbox({
|
||||
displayName: 'Mark as Read',
|
||||
description: 'Mark submission as read when created',
|
||||
defaultValue: false,
|
||||
required: false,
|
||||
}),
|
||||
encryption_password: Property.ShortText({
|
||||
displayName: 'Encryption Password',
|
||||
description: 'Password for encrypted forms',
|
||||
required: false,
|
||||
}),
|
||||
form_fields: Property.DynamicProperties({
|
||||
auth: formStackAuth,
|
||||
displayName: 'Form Fields',
|
||||
description: 'Fill out the form fields',
|
||||
required: true,
|
||||
refreshers: ['form_id'],
|
||||
props: async ({ auth, form_id }) => {
|
||||
if (!auth || !form_id) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const authentication = auth;
|
||||
const accessToken = authentication['access_token'];
|
||||
|
||||
try {
|
||||
const formDetails = await makeRequest(
|
||||
accessToken,
|
||||
HttpMethod.GET,
|
||||
`/form/${form_id}.json`
|
||||
);
|
||||
|
||||
const fields: Record<string, any> = {};
|
||||
|
||||
if (formDetails?.fields) {
|
||||
for (const field of formDetails.fields) {
|
||||
const fieldKey = `field_${field.id}`;
|
||||
const isRequired = field.required === '1' || field.required === 1;
|
||||
|
||||
const fieldLabel = field.label || field.name || field.title || `Field ${field.id}`;
|
||||
|
||||
if (field.type?.toLowerCase() === 'section') {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (field.type?.toLowerCase()) {
|
||||
case 'select':
|
||||
case 'radio':
|
||||
case 'checkbox':{
|
||||
const optionsData = field.options || field.choices || field.option_choices;
|
||||
|
||||
if (optionsData) {
|
||||
let options: Array<{ label: string; value: string }> = [];
|
||||
|
||||
if (typeof optionsData === 'string') {
|
||||
options = optionsData.split('\n').filter(opt => opt.trim()).map((option: string) => ({
|
||||
label: option.trim(),
|
||||
value: option.trim(),
|
||||
}));
|
||||
} else if (Array.isArray(optionsData)) {
|
||||
options = optionsData.map((option: any) => {
|
||||
if (typeof option === 'string') {
|
||||
return { label: option, value: option };
|
||||
} else if (option && typeof option === 'object') {
|
||||
const label = option.label || option.text || option.option || option.value;
|
||||
const value = option.value || option.label || option.text || option.option;
|
||||
|
||||
if (label && value) {
|
||||
return { label: String(label), value: String(value) };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return { label: String(option), value: String(option) };
|
||||
}).filter((opt: any): opt is { label: string; value: string } => opt !== null && opt.label && opt.value);
|
||||
} else if (typeof optionsData === 'object') {
|
||||
options = Object.entries(optionsData).map(([key, value]) => ({
|
||||
label: String(value),
|
||||
value: key,
|
||||
}));
|
||||
}
|
||||
|
||||
if (options.length > 0) {
|
||||
if (field.type?.toLowerCase() === 'checkbox') {
|
||||
fields[fieldKey] = Property.StaticMultiSelectDropdown({
|
||||
displayName: fieldLabel,
|
||||
description: field.description || undefined,
|
||||
required: isRequired,
|
||||
options: {
|
||||
options,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
fields[fieldKey] = Property.StaticDropdown({
|
||||
displayName: fieldLabel,
|
||||
description: field.description || undefined,
|
||||
required: isRequired,
|
||||
options: {
|
||||
options,
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
fields[fieldKey] = Property.ShortText({
|
||||
displayName: fieldLabel,
|
||||
description: field.description || undefined,
|
||||
required: isRequired,
|
||||
defaultValue: field.default || undefined,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
fields[fieldKey] = Property.ShortText({
|
||||
displayName: fieldLabel,
|
||||
description: field.description || undefined,
|
||||
required: isRequired,
|
||||
defaultValue: field.default || undefined,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'text':
|
||||
fields[fieldKey] = Property.ShortText({
|
||||
displayName: fieldLabel,
|
||||
description: field.description || undefined,
|
||||
required: isRequired,
|
||||
defaultValue: field.default || undefined,
|
||||
});
|
||||
break;
|
||||
|
||||
case 'textarea':
|
||||
case 'richtext':
|
||||
fields[fieldKey] = Property.LongText({
|
||||
displayName: fieldLabel,
|
||||
description: field.description || undefined,
|
||||
required: isRequired,
|
||||
defaultValue: field.default || undefined,
|
||||
});
|
||||
break;
|
||||
|
||||
case 'email':
|
||||
fields[fieldKey] = Property.ShortText({
|
||||
displayName: fieldLabel,
|
||||
description: field.description || undefined,
|
||||
required: isRequired,
|
||||
defaultValue: field.default || undefined,
|
||||
});
|
||||
break;
|
||||
|
||||
case 'phone':
|
||||
fields[fieldKey] = Property.ShortText({
|
||||
displayName: fieldLabel,
|
||||
description: field.description ? `${field.description} (Format: (XXX) XXX-XXXX)` : 'Phone number (Format: (XXX) XXX-XXXX)',
|
||||
required: isRequired,
|
||||
defaultValue: field.default || undefined,
|
||||
});
|
||||
break;
|
||||
|
||||
case 'number':
|
||||
fields[fieldKey] = Property.Number({
|
||||
displayName: fieldLabel,
|
||||
description: field.description || undefined,
|
||||
required: isRequired,
|
||||
defaultValue: field.default ? Number(field.default) : undefined,
|
||||
});
|
||||
break;
|
||||
|
||||
case 'creditcard':
|
||||
fields[fieldKey] = Property.ShortText({
|
||||
displayName: fieldLabel,
|
||||
description: field.description || 'Credit card number',
|
||||
required: isRequired,
|
||||
});
|
||||
break;
|
||||
|
||||
case 'datetime':
|
||||
fields[fieldKey] = Property.DateTime({
|
||||
displayName: fieldLabel,
|
||||
description: field.description || undefined,
|
||||
required: isRequired,
|
||||
});
|
||||
break;
|
||||
case 'file':
|
||||
fields[fieldKey] = Property.File({
|
||||
displayName: fieldLabel,
|
||||
description: field.description ? `${field.description} (File will be base64 encoded automatically)` : 'Upload a file (will be base64 encoded automatically)',
|
||||
required: isRequired,
|
||||
});
|
||||
break;
|
||||
|
||||
case 'name':{
|
||||
const nameSubfields = field.visible_subfields || ['first', 'last'];
|
||||
|
||||
if (nameSubfields.includes('prefix')) {
|
||||
fields[`${fieldKey}[prefix]`] = Property.ShortText({
|
||||
displayName: `${fieldLabel} - Prefix`,
|
||||
description: 'Title (Mr., Mrs., Dr., etc.)',
|
||||
required: false,
|
||||
});
|
||||
}
|
||||
|
||||
if (nameSubfields.includes('first')) {
|
||||
fields[`${fieldKey}[first]`] = Property.ShortText({
|
||||
displayName: `${fieldLabel} - First Name`,
|
||||
description: 'First name',
|
||||
required: isRequired,
|
||||
});
|
||||
}
|
||||
|
||||
if (nameSubfields.includes('middle')) {
|
||||
fields[`${fieldKey}[middle]`] = Property.ShortText({
|
||||
displayName: `${fieldLabel} - Middle Name`,
|
||||
description: 'Middle name',
|
||||
required: false,
|
||||
});
|
||||
}
|
||||
|
||||
if (nameSubfields.includes('initial')) {
|
||||
fields[`${fieldKey}[initial]`] = Property.ShortText({
|
||||
displayName: `${fieldLabel} - Middle Initial`,
|
||||
description: 'Middle initial',
|
||||
required: false,
|
||||
});
|
||||
}
|
||||
|
||||
if (nameSubfields.includes('last')) {
|
||||
fields[`${fieldKey}[last]`] = Property.ShortText({
|
||||
displayName: `${fieldLabel} - Last Name`,
|
||||
description: 'Last name',
|
||||
required: isRequired,
|
||||
});
|
||||
}
|
||||
|
||||
if (nameSubfields.includes('suffix')) {
|
||||
fields[`${fieldKey}[suffix]`] = Property.ShortText({
|
||||
displayName: `${fieldLabel} - Suffix`,
|
||||
description: 'Suffix (Jr., Sr., III, etc.)',
|
||||
required: false,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'address': {
|
||||
const addressSubfields = field.visible_subfields || ['address', 'city', 'state', 'zip'];
|
||||
|
||||
if (addressSubfields.includes('address')) {
|
||||
fields[`${fieldKey}[address]`] = Property.ShortText({
|
||||
displayName: `${fieldLabel} - Address Line 1`,
|
||||
description: 'Street address',
|
||||
required: isRequired,
|
||||
});
|
||||
}
|
||||
|
||||
if (addressSubfields.includes('address2')) {
|
||||
fields[`${fieldKey}[address2]`] = Property.ShortText({
|
||||
displayName: `${fieldLabel} - Address Line 2`,
|
||||
description: 'Apartment, suite, etc.',
|
||||
required: false,
|
||||
});
|
||||
}
|
||||
|
||||
if (addressSubfields.includes('city')) {
|
||||
fields[`${fieldKey}[city]`] = Property.ShortText({
|
||||
displayName: `${fieldLabel} - City`,
|
||||
description: 'City',
|
||||
required: isRequired,
|
||||
});
|
||||
}
|
||||
|
||||
if (addressSubfields.includes('state')) {
|
||||
fields[`${fieldKey}[state]`] = Property.ShortText({
|
||||
displayName: `${fieldLabel} - State`,
|
||||
description: 'State/Province',
|
||||
required: isRequired,
|
||||
});
|
||||
}
|
||||
|
||||
if (addressSubfields.includes('zip')) {
|
||||
fields[`${fieldKey}[zip]`] = Property.ShortText({
|
||||
displayName: `${fieldLabel} - ZIP Code`,
|
||||
description: 'ZIP/Postal code',
|
||||
required: isRequired,
|
||||
});
|
||||
}
|
||||
|
||||
if (addressSubfields.includes('country')) {
|
||||
fields[`${fieldKey}[country]`] = Property.ShortText({
|
||||
displayName: `${fieldLabel} - Country`,
|
||||
description: 'Country',
|
||||
required: false,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
fields[fieldKey] = Property.ShortText({
|
||||
displayName: fieldLabel,
|
||||
description: field.description || field.hint || undefined,
|
||||
required: isRequired,
|
||||
defaultValue: field.default || field.defaultValue || undefined,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fields;
|
||||
} catch (error) {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
const authentication = context.auth as OAuth2PropertyValue;
|
||||
const accessToken = authentication['access_token'];
|
||||
|
||||
const {
|
||||
form_id,
|
||||
user_agent,
|
||||
remote_addr,
|
||||
payment_status,
|
||||
read,
|
||||
encryption_password,
|
||||
form_fields,
|
||||
} = context.propsValue;
|
||||
|
||||
const formData: Record<string, any> = {};
|
||||
|
||||
if (form_fields) {
|
||||
for (const [key, value] of Object.entries(form_fields as DynamicPropsValue)) {
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
if (typeof value === 'object' && value.base64) {
|
||||
const filename = value.filename || 'upload.file';
|
||||
formData[key] = `${filename};${value.base64}`;
|
||||
} else if (Array.isArray(value)) {
|
||||
formData[key] = value.join(',');
|
||||
} else {
|
||||
let processedValue = value;
|
||||
|
||||
if (key.includes('phone') || key.includes('Phone')) {
|
||||
const phoneStr = String(value);
|
||||
const digits = phoneStr.replace(/\D/g, '');
|
||||
if (digits.length === 10) {
|
||||
processedValue = `(${digits.slice(0, 3)}) ${digits.slice(3, 6)}-${digits.slice(6)}`;
|
||||
} else if (digits.length === 11 && digits[0] === '1') {
|
||||
processedValue = `(${digits.slice(1, 4)}) ${digits.slice(4, 7)}-${digits.slice(7)}`;
|
||||
} else {
|
||||
processedValue = phoneStr;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof value === 'string' && value.includes('T') && value.includes(':')) {
|
||||
const date = new Date(value);
|
||||
if (!isNaN(date.getTime())) {
|
||||
processedValue = date.toLocaleString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: '2-digit',
|
||||
hour12: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
formData[key] = processedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (user_agent) formData['user_agent'] = user_agent;
|
||||
if (remote_addr) formData['remote_addr'] = remote_addr;
|
||||
if (payment_status) formData['payment_status'] = payment_status;
|
||||
if (read !== undefined) formData['read'] = read;
|
||||
if (encryption_password) formData['encryption_password'] = encryption_password;
|
||||
|
||||
const response = await makeFormRequest(
|
||||
accessToken,
|
||||
HttpMethod.POST,
|
||||
`/form/${form_id}/submission`,
|
||||
formData
|
||||
);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
submission_id: response.id,
|
||||
message: 'Submission created successfully',
|
||||
details: response,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,141 @@
|
||||
import {
|
||||
createAction,
|
||||
OAuth2PropertyValue,
|
||||
Property,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { formStackAuth } from '../common/auth';
|
||||
import { makeRequest } from '../common/client';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
|
||||
export const findFormByNameOrId = createAction({
|
||||
auth: formStackAuth,
|
||||
name: 'findFormByNameOrId',
|
||||
displayName: 'Find Form by Name or ID',
|
||||
description: 'Find a form by name or ID',
|
||||
props: {
|
||||
search_query: Property.ShortText({
|
||||
displayName: 'Form Name or ID',
|
||||
description: 'Enter form name or ID to search',
|
||||
required: true,
|
||||
}),
|
||||
include_folders: Property.Checkbox({
|
||||
displayName: 'Group by Folders',
|
||||
description: 'Organize results by folders',
|
||||
defaultValue: false,
|
||||
required: false,
|
||||
}),
|
||||
exact_match: Property.Checkbox({
|
||||
displayName: 'Exact Name Match',
|
||||
description: 'Only exact name matches',
|
||||
defaultValue: false,
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const authentication = context.auth;
|
||||
const accessToken = authentication['access_token'];
|
||||
|
||||
const { search_query, include_folders, exact_match } = context.propsValue;
|
||||
|
||||
const isNumericId = /^\d+$/.test(search_query.trim());
|
||||
|
||||
if (isNumericId) {
|
||||
try {
|
||||
const response = await makeRequest(
|
||||
accessToken,
|
||||
HttpMethod.GET,
|
||||
`/form/${search_query}.json`,
|
||||
{}
|
||||
);
|
||||
|
||||
return {
|
||||
search_type: 'id',
|
||||
query: search_query,
|
||||
found: true,
|
||||
form: {
|
||||
id: response.id,
|
||||
name: response.name,
|
||||
url: response.url,
|
||||
created: response.created,
|
||||
updated: response.updated,
|
||||
submissions: response.submissions,
|
||||
submissions_unread: response.submissions_unread,
|
||||
last_submission_time: response.last_submission_time,
|
||||
timezone: response.timezone,
|
||||
folder: response.folder,
|
||||
},
|
||||
message: `Form found with ID: ${search_query}`,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
search_type: 'id',
|
||||
query: search_query,
|
||||
found: false,
|
||||
form: null,
|
||||
message: `No form found with ID: ${search_query}`,
|
||||
error: 'Form not found or access denied',
|
||||
};
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const queryParams = new URLSearchParams();
|
||||
queryParams.append('search', search_query);
|
||||
|
||||
if (include_folders) {
|
||||
queryParams.append('folders', 'true');
|
||||
}
|
||||
|
||||
const response = await makeRequest(
|
||||
accessToken,
|
||||
HttpMethod.GET,
|
||||
`/form.json?${queryParams.toString()}`,
|
||||
{}
|
||||
);
|
||||
|
||||
let matchingForms = response.forms || [];
|
||||
|
||||
if (exact_match) {
|
||||
matchingForms = matchingForms.filter((form: any) =>
|
||||
form.name.toLowerCase() === search_query.toLowerCase()
|
||||
);
|
||||
}
|
||||
|
||||
const foundCount = matchingForms.length;
|
||||
|
||||
return {
|
||||
search_type: 'name',
|
||||
query: search_query,
|
||||
found: foundCount > 0,
|
||||
total_found: foundCount,
|
||||
forms: matchingForms.map((form: any) => ({
|
||||
id: form.id,
|
||||
name: form.name,
|
||||
url: form.url,
|
||||
created: form.created,
|
||||
updated: form.updated,
|
||||
submissions: form.submissions,
|
||||
submissions_unread: form.submissions_unread,
|
||||
last_submission_time: form.last_submission_time,
|
||||
views: form.views,
|
||||
})),
|
||||
message: foundCount > 0
|
||||
? `Found ${foundCount} form${foundCount === 1 ? '' : 's'} matching "${search_query}"`
|
||||
: `No forms found matching "${search_query}"`,
|
||||
search_options: {
|
||||
exact_match_used: exact_match,
|
||||
folders_included: include_folders,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
search_type: 'name',
|
||||
query: search_query,
|
||||
found: false,
|
||||
forms: [],
|
||||
message: `Search failed for "${search_query}"`,
|
||||
error: 'Unable to search forms or access denied',
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,198 @@
|
||||
import {
|
||||
createAction,
|
||||
OAuth2PropertyValue,
|
||||
Property,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { formStackAuth } from '../common/auth';
|
||||
import { makeRequest } from '../common/client';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
|
||||
export const findSubmissionByFieldValue = createAction({
|
||||
auth: formStackAuth,
|
||||
name: 'findSubmissionByFieldValue',
|
||||
displayName: 'Find Submission by Field Value',
|
||||
description: 'Search submissions by field values',
|
||||
props: {
|
||||
search_value: Property.LongText({
|
||||
displayName: 'Search Value',
|
||||
description: 'Value to search for (minimum 3 characters)',
|
||||
required: true,
|
||||
}),
|
||||
per_page: Property.Number({
|
||||
displayName: 'Results Per Page',
|
||||
description: 'Number of results per page (1-100)',
|
||||
required: false,
|
||||
defaultValue: 25,
|
||||
}),
|
||||
page: Property.Number({
|
||||
displayName: 'Page Number',
|
||||
description: 'Page number to return',
|
||||
required: false,
|
||||
defaultValue: 1,
|
||||
}),
|
||||
sort_order: Property.StaticDropdown({
|
||||
displayName: 'Sort Order',
|
||||
description: 'Sort results by submission ID',
|
||||
required: false,
|
||||
defaultValue: 'DESC',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Newest First (DESC)', value: 'DESC' },
|
||||
{ label: 'Oldest First (ASC)', value: 'ASC' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
include_form_names: Property.Checkbox({
|
||||
displayName: 'Include Form Names',
|
||||
description: 'Include form names in results',
|
||||
defaultValue: true,
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const authentication = context.auth;
|
||||
const accessToken = authentication['access_token'];
|
||||
|
||||
const {
|
||||
search_value,
|
||||
per_page = 25,
|
||||
page = 1,
|
||||
sort_order = 'DESC',
|
||||
include_form_names = true,
|
||||
} = context.propsValue;
|
||||
|
||||
if (!search_value || search_value.trim().length < 3) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'invalid_search_length',
|
||||
message: 'Search value must be at least 3 characters long.',
|
||||
search_value,
|
||||
};
|
||||
}
|
||||
|
||||
const validatedPerPage = Math.min(Math.max(1, per_page || 25), 100);
|
||||
const validatedPage = Math.max(1, page || 1);
|
||||
|
||||
try {
|
||||
const params = new URLSearchParams();
|
||||
params.append('search', search_value.trim());
|
||||
params.append('per_page', validatedPerPage.toString());
|
||||
params.append('page', validatedPage.toString());
|
||||
|
||||
if (sort_order) {
|
||||
params.append('sort', `id-${sort_order}`);
|
||||
}
|
||||
|
||||
const response = await makeRequest(
|
||||
accessToken,
|
||||
HttpMethod.GET,
|
||||
`/submission?${params.toString()}`,
|
||||
{}
|
||||
);
|
||||
|
||||
const submissions = response.submissions || [];
|
||||
const total = response.total || 0;
|
||||
const pages = response.pages || 0;
|
||||
|
||||
let formNames: Record<string, string> = {};
|
||||
if (include_form_names && submissions.length > 0) {
|
||||
try {
|
||||
const formIds = [...new Set(submissions.map((sub: any) => sub.formId))];
|
||||
|
||||
const formRequests = formIds.map(async (formId: any) => {
|
||||
try {
|
||||
const formDetails = await makeRequest(
|
||||
accessToken,
|
||||
HttpMethod.GET,
|
||||
`/form/${formId}.json`,
|
||||
{}
|
||||
);
|
||||
return { id: formId, name: formDetails.name };
|
||||
} catch {
|
||||
return { id: formId, name: `Form ${formId}` };
|
||||
}
|
||||
});
|
||||
|
||||
const formResults = await Promise.all(formRequests);
|
||||
formNames = formResults.reduce((acc, form) => {
|
||||
acc[form.id] = form.name;
|
||||
return acc;
|
||||
}, {} as Record<string, string>);
|
||||
} catch (error) {
|
||||
console.warn('Could not fetch form names:', error);
|
||||
}
|
||||
}
|
||||
|
||||
const formattedSubmissions = submissions.map((submission: any) => {
|
||||
const result: any = {
|
||||
id: submission.id,
|
||||
form_id: submission.formId,
|
||||
submitted_at: submission.timestamp,
|
||||
submitter_info: {
|
||||
ip_address: submission.remote_addr,
|
||||
user_agent: submission.user_agent,
|
||||
location: submission.latitude && submission.longitude ? {
|
||||
latitude: submission.latitude,
|
||||
longitude: submission.longitude,
|
||||
} : null,
|
||||
},
|
||||
};
|
||||
|
||||
if (include_form_names && formNames[submission.formId]) {
|
||||
result.form_name = formNames[submission.formId];
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
search_query: search_value.trim(),
|
||||
results: {
|
||||
submissions: formattedSubmissions,
|
||||
pagination: {
|
||||
current_page: validatedPage,
|
||||
per_page: validatedPerPage,
|
||||
total_results: total,
|
||||
total_pages: pages,
|
||||
has_next_page: validatedPage < pages,
|
||||
has_previous_page: validatedPage > 1,
|
||||
},
|
||||
search_options: {
|
||||
sort_order,
|
||||
include_form_names,
|
||||
},
|
||||
},
|
||||
message: `Found ${total} submission${total === 1 ? '' : 's'} matching "${search_value.trim()}"`,
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
||||
|
||||
if (errorMessage.includes('400')) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'invalid_search',
|
||||
message: 'Invalid search parameters. Please check your search value and try again.',
|
||||
search_value,
|
||||
};
|
||||
}
|
||||
|
||||
if (errorMessage.includes('403') || errorMessage.includes('unauthorized')) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'access_denied',
|
||||
message: 'Access denied. You may not have permission to search submissions.',
|
||||
search_value,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: 'search_failed',
|
||||
message: `Search failed: ${errorMessage}`,
|
||||
search_value,
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,137 @@
|
||||
import {
|
||||
createAction,
|
||||
OAuth2PropertyValue,
|
||||
Property,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { formIdDropdown, submissionIdDropdown } from '../common/props';
|
||||
import { formStackAuth } from '../common/auth';
|
||||
import { makeRequest } from '../common/client';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
|
||||
export const getSubmissionDetails = createAction({
|
||||
auth: formStackAuth,
|
||||
name: 'getSubmissionDetails',
|
||||
displayName: 'Get Submission Details',
|
||||
description: 'Get details of a form submission',
|
||||
props: {
|
||||
form_id: formIdDropdown,
|
||||
submission_id: submissionIdDropdown,
|
||||
encryption_password: Property.ShortText({
|
||||
displayName: 'Encryption Password',
|
||||
description: 'Password for encrypted forms',
|
||||
required: false,
|
||||
}),
|
||||
include_metadata: Property.Checkbox({
|
||||
displayName: 'Include Technical Metadata',
|
||||
description: 'Include IP, user agent, and location data',
|
||||
defaultValue: false,
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const authentication = context.auth;
|
||||
const accessToken = authentication['access_token'];
|
||||
|
||||
const {
|
||||
form_id,
|
||||
submission_id,
|
||||
encryption_password,
|
||||
include_metadata,
|
||||
} = context.propsValue;
|
||||
|
||||
try {
|
||||
const queryParams: Record<string, string> = {};
|
||||
if (encryption_password) {
|
||||
queryParams['encryption_password'] = encryption_password;
|
||||
}
|
||||
|
||||
const response = await makeRequest(
|
||||
accessToken,
|
||||
HttpMethod.GET,
|
||||
`/submission/${submission_id}.json`,
|
||||
{},
|
||||
queryParams
|
||||
);
|
||||
|
||||
const formattedData: Record<string, any> = {};
|
||||
|
||||
if (response.data && Array.isArray(response.data)) {
|
||||
for (const item of response.data) {
|
||||
if (item.field && item.value !== undefined) {
|
||||
formattedData[`field_${item.field}`] = item.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = {
|
||||
submission: {
|
||||
id: response.id,
|
||||
form_id: response.form,
|
||||
submitted_at: response.timestamp,
|
||||
data: formattedData,
|
||||
raw_data: response.data,
|
||||
},
|
||||
form_data_count: response.data ? response.data.length : 0,
|
||||
success: true,
|
||||
message: `Successfully retrieved submission ${submission_id} from form ${form_id}`,
|
||||
};
|
||||
|
||||
if (include_metadata) {
|
||||
(result.submission as any).metadata = {
|
||||
user_agent: response.user_agent,
|
||||
ip_address: response.remote_addr,
|
||||
latitude: response.latitude,
|
||||
longitude: response.longitude,
|
||||
portal_info: response.portal_name ? {
|
||||
portal_name: response.portal_name,
|
||||
portal_form_name: response.portal_form_name,
|
||||
participant_email: response.portal_participant_email,
|
||||
} : null,
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
||||
|
||||
if (errorMessage.includes('404') || errorMessage.includes('not found')) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'submission_not_found',
|
||||
message: `Submission with ID "${submission_id}" was not found. Please check the submission ID and try again.`,
|
||||
submission_id,
|
||||
form_id,
|
||||
};
|
||||
}
|
||||
|
||||
if (errorMessage.includes('403') || errorMessage.includes('unauthorized')) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'access_denied',
|
||||
message: `Access denied to submission "${submission_id}". You may not have permission to view this submission.`,
|
||||
submission_id,
|
||||
form_id,
|
||||
};
|
||||
}
|
||||
|
||||
if (errorMessage.includes('encryption')) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'encryption_required',
|
||||
message: `This submission is encrypted and requires a decryption password. Please provide the encryption password and try again.`,
|
||||
submission_id,
|
||||
form_id,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: 'retrieval_failed',
|
||||
message: `Failed to retrieve submission "${submission_id}": ${errorMessage}`,
|
||||
submission_id,
|
||||
form_id,
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
import { PieceAuth } from "@activepieces/pieces-framework";
|
||||
|
||||
export const formStackAuth = PieceAuth.OAuth2({
|
||||
description: 'Connect your Formstack account',
|
||||
authUrl: 'https://www.formstack.com/api/v2/oauth2/authorize',
|
||||
tokenUrl: 'https://www.formstack.com/api/v2/oauth2/token',
|
||||
required: true,
|
||||
scope: [],
|
||||
});
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
|
||||
|
||||
export const BASE_URL = 'https://www.formstack.com/api/v2';
|
||||
|
||||
export const RATE_LIMIT = {
|
||||
DAILY_LIMIT: 14400, // 14,400 calls per access token per day
|
||||
WINDOW: 24 * 60 * 60 * 1000, // 24 hours in milliseconds
|
||||
};
|
||||
|
||||
export enum RequestFormat {
|
||||
JSON = 'json',
|
||||
URL_ENCODED = 'url-encoded',
|
||||
}
|
||||
|
||||
interface RequestOptions {
|
||||
format?: RequestFormat;
|
||||
useQueryAuth?: boolean;
|
||||
}
|
||||
|
||||
export async function makeRequest(
|
||||
accessToken: string,
|
||||
method: HttpMethod,
|
||||
path: string,
|
||||
body?: unknown,
|
||||
queryParams?: Record<string, any>,
|
||||
options: RequestOptions = {}
|
||||
) {
|
||||
const {
|
||||
format = RequestFormat.JSON,
|
||||
useQueryAuth = false,
|
||||
} = options;
|
||||
|
||||
try {
|
||||
const headers: Record<string, string> = {};
|
||||
|
||||
if (useQueryAuth) {
|
||||
queryParams = { ...queryParams, oauth_token: accessToken };
|
||||
} else {
|
||||
headers['Authorization'] = `Bearer ${accessToken}`;
|
||||
}
|
||||
|
||||
// Only set content type and process body for requests that should have a body
|
||||
let requestBody = undefined;
|
||||
const shouldHaveBody = method !== HttpMethod.GET && method !== HttpMethod.DELETE && body !== undefined;
|
||||
|
||||
if (shouldHaveBody) {
|
||||
if (format === RequestFormat.JSON) {
|
||||
headers['Content-Type'] = 'application/json';
|
||||
requestBody = body;
|
||||
} else {
|
||||
headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
if (typeof body === 'object') {
|
||||
requestBody = Object.entries(body as Record<string, any>)
|
||||
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
|
||||
.join('&');
|
||||
} else {
|
||||
requestBody = body;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const response = await httpClient.sendRequest({
|
||||
method,
|
||||
url: `${BASE_URL}${path}`,
|
||||
headers,
|
||||
body: requestBody,
|
||||
queryParams,
|
||||
});
|
||||
|
||||
return response.body;
|
||||
|
||||
} catch (error: any) {
|
||||
const status = error.response?.status || error.status;
|
||||
const errorMessage = error.response?.body?.error || error.message || 'Unknown error';
|
||||
|
||||
switch (status) {
|
||||
case 400:
|
||||
throw new Error(`Bad Request: The request URI was invalid. ${errorMessage}`);
|
||||
|
||||
case 401:
|
||||
throw new Error(`Unauthorized: Valid OAuth2 credentials were not supplied. Please check your access token.`);
|
||||
|
||||
case 403:
|
||||
throw new Error(`Forbidden: You do not have access to this resource. Check your user permissions in Formstack.`);
|
||||
|
||||
case 404:
|
||||
throw new Error(`Not Found: The requested resource could not be found. ${errorMessage}`);
|
||||
|
||||
case 405:
|
||||
throw new Error(`Method Not Allowed: The requested HTTP method is not supported for this endpoint.`);
|
||||
|
||||
case 415:
|
||||
throw new Error(`Unsupported Media Type: Please use a valid media type (JSON or URL-encoded).`);
|
||||
|
||||
case 429:
|
||||
throw new Error(`Rate Limit Exceeded: You have hit the daily limit of ${RATE_LIMIT.DAILY_LIMIT} API calls. Try again in 24 hours.`);
|
||||
|
||||
case 500:
|
||||
throw new Error(`Internal Server Error: An error occurred while processing the request. Please try again later.`);
|
||||
|
||||
default:
|
||||
throw new Error(`Request failed (${status}): ${errorMessage}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function makeFormRequest(
|
||||
accessToken: string,
|
||||
method: HttpMethod,
|
||||
path: string,
|
||||
formData: Record<string, any>,
|
||||
queryParams?: Record<string, any>
|
||||
) {
|
||||
return makeRequest(accessToken, method, path, formData, queryParams, {
|
||||
format: RequestFormat.URL_ENCODED,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import { OAuth2PropertyValue, Property } from '@activepieces/pieces-framework';
|
||||
import { makeRequest } from './client';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { formStackAuth } from './auth';
|
||||
|
||||
export const formIdDropdown = Property.Dropdown({
|
||||
displayName: 'Forms ',
|
||||
required: true,
|
||||
auth: formStackAuth,
|
||||
refreshers: ['auth'],
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Connect your account',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
const authentication = auth;
|
||||
const accessToken = authentication['access_token'];
|
||||
|
||||
const forms = await makeRequest(
|
||||
accessToken,
|
||||
HttpMethod.GET,
|
||||
'/form.json'
|
||||
);
|
||||
const options = forms.forms.map((field: { id: string; name: string }) => {
|
||||
return {
|
||||
label: field.name,
|
||||
value: field.id,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
options,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const submissionIdDropdown = Property.Dropdown({
|
||||
auth: formStackAuth,
|
||||
displayName: 'Submission',
|
||||
required: true,
|
||||
refreshers: ['auth', 'form_id'],
|
||||
options: async ({ auth, form_id }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Connect your account',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
if (!form_id) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please select a form first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
const authentication = auth;
|
||||
const accessToken = authentication['access_token'];
|
||||
|
||||
try {
|
||||
const response = await makeRequest(
|
||||
accessToken,
|
||||
HttpMethod.GET,
|
||||
`/form/${form_id}/submission.json`
|
||||
);
|
||||
|
||||
if (!response.submissions || response.submissions.length === 0) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'No submissions found for this form',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
|
||||
const options = response.submissions.map((submission: any) => {
|
||||
let label = `ID: ${submission.id}`;
|
||||
|
||||
if (submission.timestamp) {
|
||||
const date = new Date(submission.timestamp).toLocaleDateString();
|
||||
label += ` (${date})`;
|
||||
}
|
||||
|
||||
if (submission.data && Array.isArray(submission.data) && submission.data.length > 0) {
|
||||
const previewFields = submission.data
|
||||
.slice(0, 2)
|
||||
.map((field: any) => {
|
||||
if (field.value && typeof field.value === 'string' && field.value.length > 0) {
|
||||
const value = field.value.length > 20
|
||||
? field.value.substring(0, 20) + '...'
|
||||
: field.value;
|
||||
return value;
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
if (previewFields.length > 0) {
|
||||
label += ` - ${previewFields.join(', ')}`;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
label,
|
||||
value: submission.id,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
options,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Error loading submissions',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,162 @@
|
||||
|
||||
import {
|
||||
createTrigger,
|
||||
TriggerStrategy,
|
||||
PiecePropValueSchema,
|
||||
OAuth2PropertyValue,
|
||||
AppConnectionValueForAuthProperty
|
||||
} from '@activepieces/pieces-framework';
|
||||
import {
|
||||
DedupeStrategy,
|
||||
Polling,
|
||||
pollingHelper,
|
||||
HttpMethod
|
||||
} from '@activepieces/pieces-common';
|
||||
import dayjs from 'dayjs';
|
||||
import { formStackAuth } from '../common/auth';
|
||||
import { makeRequest } from '../common/client';
|
||||
|
||||
const polling: Polling<AppConnectionValueForAuthProperty<typeof formStackAuth>, any> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
items: async ({ auth, propsValue, lastFetchEpochMS }) => {
|
||||
const authentication = auth as OAuth2PropertyValue;
|
||||
const accessToken = authentication['access_token'];
|
||||
|
||||
try {
|
||||
const formsResponse = await makeRequest(
|
||||
accessToken,
|
||||
HttpMethod.GET,
|
||||
'/form.json'
|
||||
);
|
||||
|
||||
const forms = formsResponse.forms || [];
|
||||
console.log('Raw forms API response:', JSON.stringify(formsResponse, null, 2));
|
||||
|
||||
const newForms = forms.filter((form: any) => {
|
||||
if (!form.created) return false;
|
||||
|
||||
const createdTime = dayjs(form.created, 'YYYY-MM-DD HH:mm:ss').valueOf();
|
||||
return createdTime > (lastFetchEpochMS ?? 0);
|
||||
});
|
||||
|
||||
return newForms.map((form: any) => ({
|
||||
epochMilliSeconds: dayjs(form.created, 'YYYY-MM-DD HH:mm:ss').valueOf(),
|
||||
data: {
|
||||
id: form.id,
|
||||
name: form.name,
|
||||
views: parseInt(form.views) || 0,
|
||||
created: form.created,
|
||||
updated: form.updated,
|
||||
submissions: parseInt(form.submissions) || 0,
|
||||
submissions_unread: parseInt(form.submissions_unread) || 0,
|
||||
last_submission_id: form.last_submission_id,
|
||||
last_submission_time: form.last_submission_time,
|
||||
url: form.url,
|
||||
data_url: form.data_url,
|
||||
summary_url: form.summary_url,
|
||||
rss_url: form.rss_url,
|
||||
timezone: form.timezone,
|
||||
status: form.status,
|
||||
folder: form.folder,
|
||||
language: form.language,
|
||||
encrypted: form.encrypted,
|
||||
ssl: form.ssl,
|
||||
viewkey: form.viewkey,
|
||||
},
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error('Error fetching forms:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const newForm = createTrigger({
|
||||
auth: formStackAuth,
|
||||
name: 'newForm',
|
||||
displayName: 'New Form',
|
||||
description: 'Triggers when a new form is created',
|
||||
props: {},
|
||||
sampleData: {
|
||||
id: "6244510",
|
||||
name: "Customer Registration Form",
|
||||
views: 342,
|
||||
created: "2024-12-15 14:22:18",
|
||||
updated: "2024-12-20 09:45:33",
|
||||
submissions: 127,
|
||||
submissions_unread: 8,
|
||||
last_submission_id: "1361884054",
|
||||
last_submission_time: "2025-01-14 14:16:49",
|
||||
url: "https://activepieces.formstack.com/forms/customer_registration",
|
||||
data_url: "https://www.formstack.com/admin/form/summary/6244510",
|
||||
summary_url: "https://www.formstack.com/admin/form/data/6244510",
|
||||
rss_url: "https://www.formstack.com/forms/index.php?6244510-rss",
|
||||
timezone: "America/New_York",
|
||||
status: "1",
|
||||
folder: "Marketing Forms",
|
||||
language: "en",
|
||||
encrypted: "0",
|
||||
ssl: "1",
|
||||
viewkey: "K6244510MjPqRt"
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
async test(context) {
|
||||
try {
|
||||
const result = await pollingHelper.test(polling, context);
|
||||
|
||||
if (result && result.length > 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return [{
|
||||
epochMilliSeconds: Date.now(),
|
||||
data: {
|
||||
message: 'No recently created forms found. The trigger is working and will detect new forms when they are created.',
|
||||
note: 'This trigger monitors for newly created forms in your Formstack account.'
|
||||
}
|
||||
}];
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error in test function:', error);
|
||||
|
||||
return [{
|
||||
epochMilliSeconds: Date.now(),
|
||||
data: {
|
||||
error: 'Unable to fetch real data. Here is sample data to show the expected structure.',
|
||||
sample: true,
|
||||
id: "6244510",
|
||||
name: "Customer Registration Form",
|
||||
views: 342,
|
||||
created: "2024-12-15 14:22:18",
|
||||
updated: "2024-12-20 09:45:33",
|
||||
submissions: 127,
|
||||
submissions_unread: 8,
|
||||
last_submission_id: "1361884054",
|
||||
last_submission_time: "2025-01-14 14:16:49",
|
||||
url: "https://activepieces.formstack.com/forms/customer_registration",
|
||||
data_url: "https://www.formstack.com/admin/form/summary/6244510",
|
||||
summary_url: "https://www.formstack.com/admin/form/data/6244510",
|
||||
rss_url: "https://www.formstack.com/forms/index.php?6244510-rss",
|
||||
timezone: "America/New_York",
|
||||
status: "1",
|
||||
folder: "Marketing Forms",
|
||||
language: "en",
|
||||
encrypted: "0",
|
||||
ssl: "1",
|
||||
viewkey: "K6244510MjPqRt"
|
||||
}
|
||||
}];
|
||||
}
|
||||
},
|
||||
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) {
|
||||
return await pollingHelper.poll(polling, context);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,261 @@
|
||||
import {
|
||||
createTrigger,
|
||||
TriggerStrategy,
|
||||
PiecePropValueSchema,
|
||||
OAuth2PropertyValue,
|
||||
AppConnectionValueForAuthProperty,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import {
|
||||
DedupeStrategy,
|
||||
Polling,
|
||||
pollingHelper,
|
||||
HttpMethod,
|
||||
} from '@activepieces/pieces-common';
|
||||
import dayjs from 'dayjs';
|
||||
import timezone from 'dayjs/plugin/timezone';
|
||||
import utc from 'dayjs/plugin/utc';
|
||||
import { formStackAuth } from '../common/auth';
|
||||
import { formIdDropdown } from '../common/props';
|
||||
import { makeRequest } from '../common/client';
|
||||
|
||||
dayjs.extend(timezone);
|
||||
dayjs.extend(utc);
|
||||
|
||||
const polling: Polling<AppConnectionValueForAuthProperty<typeof formStackAuth>, any> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
items: async ({ auth, propsValue, lastFetchEpochMS }) => {
|
||||
const authentication = auth as OAuth2PropertyValue;
|
||||
const accessToken = authentication['access_token'];
|
||||
const formId = propsValue.form_id;
|
||||
|
||||
if (!formId) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
const isTest = lastFetchEpochMS === 0;
|
||||
|
||||
// use form timezone for storing epochMilliSeconds
|
||||
const formResponse = await makeRequest(
|
||||
accessToken,
|
||||
HttpMethod.GET,
|
||||
`/form/${formId}.json`
|
||||
);
|
||||
const formTimezone = formResponse.timezone;
|
||||
|
||||
const queryParams: Record<string, any> = {
|
||||
data: 'true',
|
||||
sort: 'DESC',
|
||||
page: 1,
|
||||
};
|
||||
|
||||
if (isTest) {
|
||||
queryParams['per_page'] = 10;
|
||||
} else {
|
||||
queryParams['per_page'] = 100;
|
||||
// YYYY-MM-DD HH:MM:SS expected (Based around Eastern Time)
|
||||
queryParams['min_time'] = dayjs
|
||||
.utc(lastFetchEpochMS)
|
||||
.tz('America/New_York')
|
||||
.format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
|
||||
const detailedSubmissions: any[] = [];
|
||||
let hasMorePages = true;
|
||||
|
||||
while (hasMorePages) {
|
||||
const submissionsResponse = await makeRequest(
|
||||
accessToken,
|
||||
HttpMethod.GET,
|
||||
`/form/${formId}/submission.json`,
|
||||
undefined,
|
||||
queryParams
|
||||
);
|
||||
|
||||
const submissions: any[] = submissionsResponse.submissions || [];
|
||||
submissions.forEach((submission: any) => {
|
||||
detailedSubmissions.push({
|
||||
epochMilliSeconds: dayjs
|
||||
.tz(submission.timestamp, formTimezone)
|
||||
.valueOf(),
|
||||
data: {
|
||||
id: submission.id,
|
||||
form_id: formId,
|
||||
timestamp: submission.timestamp,
|
||||
user_agent: submission.user_agent,
|
||||
remote_addr: submission.remote_addr,
|
||||
latitude: submission.latitude,
|
||||
longitude: submission.longitude,
|
||||
payment_status: submission.payment_status || '',
|
||||
data: Object.values(submission.data),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
if (isTest || queryParams['page'] >= submissionsResponse['pages']) {
|
||||
hasMorePages = false;
|
||||
} else {
|
||||
queryParams['page'] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return detailedSubmissions;
|
||||
} catch (error) {
|
||||
console.error('Error fetching submissions:', error);
|
||||
return [];
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export const newSubmission = createTrigger({
|
||||
auth: formStackAuth,
|
||||
name: 'newSubmission',
|
||||
displayName: 'New Submission',
|
||||
description: 'Triggers when a form receives a new submission',
|
||||
props: {
|
||||
form_id: formIdDropdown,
|
||||
},
|
||||
sampleData: {
|
||||
id: '185502901',
|
||||
form_id: '5439876',
|
||||
timestamp: '2024-01-15T14:32:18Z',
|
||||
user_agent:
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||
remote_addr: '198.51.100.42',
|
||||
latitude: '37.7749',
|
||||
longitude: '-122.4194',
|
||||
payment_status: '',
|
||||
data: [
|
||||
{
|
||||
field: '185502595',
|
||||
value: 'John',
|
||||
},
|
||||
{
|
||||
field: '185502596',
|
||||
value: 'Doe',
|
||||
},
|
||||
{
|
||||
field: '185502597',
|
||||
value: 'john.doe@company.com',
|
||||
},
|
||||
{
|
||||
field: '185502598',
|
||||
value: '(555) 123-4567',
|
||||
},
|
||||
{
|
||||
field: '185502599',
|
||||
value: 'Software Engineer',
|
||||
},
|
||||
{
|
||||
field: '185502600',
|
||||
value: 'Premium Plan',
|
||||
},
|
||||
{
|
||||
field: '185502601',
|
||||
value: 'Newsletter, Product Updates',
|
||||
},
|
||||
{
|
||||
field: '185502602',
|
||||
value: '2',
|
||||
},
|
||||
{
|
||||
field: '185502603',
|
||||
value: '4532123456789012',
|
||||
},
|
||||
{
|
||||
field: '185502604',
|
||||
value:
|
||||
'https://files.formstack.com/uploads/5439876/185502901/987654321/resume.pdf',
|
||||
},
|
||||
{
|
||||
field: '185502605',
|
||||
value:
|
||||
'I would like to learn more about your enterprise solutions and discuss potential partnership opportunities.',
|
||||
},
|
||||
{
|
||||
field: '185502606',
|
||||
value: '01/15/2024',
|
||||
},
|
||||
{
|
||||
field: '185502607',
|
||||
value: 'San Francisco',
|
||||
},
|
||||
{
|
||||
field: '185502608',
|
||||
value: 'CA',
|
||||
},
|
||||
{
|
||||
field: '185502609',
|
||||
value: '94105',
|
||||
},
|
||||
],
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
async test(context) {
|
||||
try {
|
||||
const result = await pollingHelper.test(polling, context);
|
||||
|
||||
if (result && result.length > 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
epochMilliSeconds: Date.now(),
|
||||
data: {
|
||||
message:
|
||||
'No recent submissions found. The trigger is working and will detect new submissions when they arrive.',
|
||||
form_id: context.propsValue.form_id,
|
||||
},
|
||||
},
|
||||
];
|
||||
} catch (error) {
|
||||
console.error('Error in test function:', error);
|
||||
|
||||
return [
|
||||
{
|
||||
epochMilliSeconds: Date.now(),
|
||||
data: {
|
||||
error:
|
||||
'Unable to fetch real data. Here is sample data to show the expected structure.',
|
||||
sample: true,
|
||||
id: '185502901',
|
||||
form_id: '5439876',
|
||||
timestamp: '2024-01-15T14:32:18Z',
|
||||
user_agent:
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||
remote_addr: '198.51.100.42',
|
||||
latitude: '37.7749',
|
||||
longitude: '-122.4194',
|
||||
payment_status: '',
|
||||
data: [
|
||||
{
|
||||
field: '185502595',
|
||||
value: 'John',
|
||||
},
|
||||
{
|
||||
field: '185502596',
|
||||
value: 'Doe',
|
||||
},
|
||||
{
|
||||
field: '185502597',
|
||||
value: 'john.doe@company.com',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
},
|
||||
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) {
|
||||
return await pollingHelper.poll(polling, context);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noPropertyAccessFromIndexSignature": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"outDir": "../../../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user