Add Activepieces integration for workflow automation

- Add Activepieces fork with SmoothSchedule custom piece
- Create integrations app with Activepieces service layer
- Add embed token endpoint for iframe integration
- Create Automations page with embedded workflow builder
- Add sidebar visibility fix for embed mode
- Add list inactive customers endpoint to Public API
- Include SmoothSchedule triggers: event created/updated/cancelled
- Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
poduck
2025-12-18 22:59:37 -05:00
parent 9848268d34
commit 3aa7199503
16292 changed files with 1284892 additions and 4708 deletions

View File

@@ -0,0 +1,33 @@
{
"extends": [
"../../../../.eslintrc.base.json"
],
"ignorePatterns": [
"!**/*"
],
"overrides": [
{
"files": [
"*.ts",
"*.tsx",
"*.js",
"*.jsx"
],
"rules": {}
},
{
"files": [
"*.ts",
"*.tsx"
],
"rules": {}
},
{
"files": [
"*.js",
"*.jsx"
],
"rules": {}
}
]
}

View File

@@ -0,0 +1,7 @@
# pieces-smartsuite
This library was generated with [Nx](https://nx.dev).
## Building
Run `nx build pieces-smartsuite` to build the library.

View File

@@ -0,0 +1,4 @@
{
"name": "@activepieces/piece-smartsuite",
"version": "0.0.8"
}

View File

@@ -0,0 +1,51 @@
{
"name": "pieces-smartsuite",
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/pieces/community/smartsuite/src",
"projectType": "library",
"targets": {
"build": {
"executor": "@nx/js:tsc",
"outputs": [
"{options.outputPath}"
],
"options": {
"outputPath": "dist/packages/pieces/community/smartsuite",
"tsConfig": "packages/pieces/community/smartsuite/tsconfig.lib.json",
"packageJson": "packages/pieces/community/smartsuite/package.json",
"main": "packages/pieces/community/smartsuite/src/index.ts",
"assets": [
"packages/pieces/community/smartsuite/*.md",
{
"input": "packages/pieces/community/smartsuite/src/i18n",
"output": "./src/i18n",
"glob": "**/!(i18n.json)"
}
],
"buildableProjectDepsInPackageJsonType": "dependencies",
"updateBuildableProjectDepsInPackageJson": true
},
"dependsOn": [
"^build",
"prebuild"
]
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": [
"{options.outputFile}"
]
},
"prebuild": {
"executor": "nx:run-commands",
"options": {
"cwd": "packages/pieces/community/smartsuite",
"command": "bun install --no-save --silent"
},
"dependsOn": [
"^build"
]
}
},
"tags": []
}

View File

@@ -0,0 +1,47 @@
{
"Collaborative work management platform combining databases with spreadsheets.": "Kollaborative Arbeitsmanagementplattform, die Datenbanken mit Tabellenkalkulationen kombiniert.",
"API Key": "API-Schlüssel",
"Account ID": "Konto-ID",
"\n You can obtain API key by navigate to **My Profile->API Key** from top-right corner.\n \n You can obtain Account ID from browser URL.For example, if smartsuite workspace URL is https://app.smartsuite.com/xyz/home, your Account ID is **xyz**.": "\n Du kannst API-Schlüssel über **Mein Profil->API-Schlüssel** aus der oberen rechten Ecke erhalten.\n \n Sie können Konto-ID von der Browser-URL erhalten. oder beispielsweise, wenn die URL des smartsuite Arbeitsbereiches https://app.smartsuite.com/xyz/home ist, ist Ihre Konto-ID **xyz**.",
"Create a Record": "Datensatz erstellen",
"Update a Record": "Datensatz aktualisieren",
"Delete a Record": "Datensatz löschen",
"Upload File": "Datei hochladen",
"Find Records": "Datensätze finden",
"Get a Record": "Datensatz abrufen",
"Custom API Call": "Eigener API-Aufruf",
"Creates a new record in the specified table.": "Erstellt einen neuen Datensatz in der angegebenen Tabelle.",
"Updates an existing record in the specified table": "Aktualisiert einen vorhandenen Datensatz in der angegebenen Tabelle",
"Deletes a record from the specified table": "Löscht einen Eintrag aus der angegebenen Tabelle",
"Uploads a file and attaches it to a record.": "Lädt eine Datei hoch und fügt sie an einen Datensatz an.",
"Searches for records in the specified table based on criteria.": "Sucht nach Datensätzen in der angegebenen Tabelle basierend auf Kriterien.",
"Retrieves a specific record by ID": "Ruft einen bestimmten Datensatz per ID ab",
"Make a custom API call to a specific endpoint": "Einen benutzerdefinierten API-Aufruf an einen bestimmten Endpunkt machen",
"Solution": "Lösung",
"Table": "Tisch",
"Fields": "Felder",
"Record ID": "Datensatz-ID",
"Search Field": "Suchfeld",
"File": "Datei",
"Search Value": "Suchwert",
"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)",
"The file to upload": "Die hochzuladende Datei",
"Authorization headers are injected automatically from your connection.": "Autorisierungs-Header werden automatisch von Ihrer Verbindung injiziert.",
"Enable for files like PDFs, images, etc..": "Aktivieren für Dateien wie PDFs, Bilder, etc..",
"GET": "ERHALTEN",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "LÖSCHEN",
"HEAD": "HEAD",
"New Record": "Neuer Datensatz",
"Updated Record": "Aktualisierte Datensatz",
"Triggers when a new record is created in the specified table": "Wird ausgelöst, wenn ein neuer Datensatz in der angegebenen Tabelle erstellt wird",
"Triggers when a record is updated in the specified table.": "Wird ausgelöst, wenn ein Datensatz in der angegebenen Tabelle aktualisiert wird."
}

View File

@@ -0,0 +1,47 @@
{
"Collaborative work management platform combining databases with spreadsheets.": "Plataforma de gestión de trabajo colaborativa que combina bases de datos con hojas de cálculo.",
"API Key": "Clave API",
"Account ID": "ID de cuenta",
"\n You can obtain API key by navigate to **My Profile->API Key** from top-right corner.\n \n You can obtain Account ID from browser URL.For example, if smartsuite workspace URL is https://app.smartsuite.com/xyz/home, your Account ID is **xyz**.": "\n You can obtain API key by navigate to **My Profile->API Key** from top-right corner.\n \n You can obtain Account ID from browser URL.For example, if smartsuite workspace URL is https://app.smartsuite.com/xyz/home, your Account ID is **xyz**.",
"Create a Record": "Crear un registro",
"Update a Record": "Actualizar un registro",
"Delete a Record": "Eliminar un registro",
"Upload File": "Subir archivo",
"Find Records": "Buscar registros",
"Get a Record": "Obtener un registro",
"Custom API Call": "Llamada API personalizada",
"Creates a new record in the specified table.": "Crea un nuevo registro en la tabla especificada.",
"Updates an existing record in the specified table": "Actualiza un registro existente en la tabla especificada",
"Deletes a record from the specified table": "Borrar un registro de la tabla especificada",
"Uploads a file and attaches it to a record.": "Sube un archivo y lo adjunta a un registro.",
"Searches for records in the specified table based on criteria.": "Busca registros en la tabla especificada según criterios.",
"Retrieves a specific record by ID": "Recuperar un registro específico por ID",
"Make a custom API call to a specific endpoint": "Hacer una llamada API personalizada a un extremo específico",
"Solution": "Solución",
"Table": "Tabla",
"Fields": "Campos",
"Record ID": "ID de registro",
"Search Field": "Campo de búsqueda",
"File": "Archivo",
"Search Value": "Valor de búsqueda",
"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)",
"The file to upload": "El archivo a subir",
"Authorization headers are injected automatically from your connection.": "Las cabeceras de autorización se inyectan automáticamente desde tu conexión.",
"Enable for files like PDFs, images, etc..": "Activar para archivos como PDFs, imágenes, etc.",
"GET": "RECOGER",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "BORRAR",
"HEAD": "LIMPIO",
"New Record": "Nuevo registro",
"Updated Record": "Registro actualizado",
"Triggers when a new record is created in the specified table": "Dispara cuando se crea un nuevo registro en la tabla especificada",
"Triggers when a record is updated in the specified table.": "Dispara cuando un registro se actualiza en la tabla especificada."
}

View File

@@ -0,0 +1,47 @@
{
"Collaborative work management platform combining databases with spreadsheets.": "Plateforme de gestion de travail collaborative combinant les bases de données et les feuilles de calcul.",
"API Key": "Clé API",
"Account ID": "ID du compte client",
"\n You can obtain API key by navigate to **My Profile->API Key** from top-right corner.\n \n You can obtain Account ID from browser URL.For example, if smartsuite workspace URL is https://app.smartsuite.com/xyz/home, your Account ID is **xyz**.": "\n You can obtain API key by navigate to **My Profile->API Key** from top-right corner.\n \n You can obtain Account ID from browser URL.For example, if smartsuite workspace URL is https://app.smartsuite.com/xyz/home, your Account ID is **xyz**.",
"Create a Record": "Créer un enregistrement",
"Update a Record": "Mettre à jour un enregistrement",
"Delete a Record": "Supprimer un enregistrement",
"Upload File": "Charger un fichier",
"Find Records": "Trouver des enregistrements",
"Get a Record": "Obtenir un enregistrement",
"Custom API Call": "Appel d'API personnalisé",
"Creates a new record in the specified table.": "Crée un nouvel enregistrement dans la table spécifiée.",
"Updates an existing record in the specified table": "Met à jour un enregistrement existant dans la table spécifiée",
"Deletes a record from the specified table": "Supprime un enregistrement de la table spécifiée",
"Uploads a file and attaches it to a record.": "Télécharge un fichier et le joint à un enregistrement.",
"Searches for records in the specified table based on criteria.": "Recherche les enregistrements dans la table spécifiée en fonction des critères.",
"Retrieves a specific record by ID": "Récupère un enregistrement spécifique par ID",
"Make a custom API call to a specific endpoint": "Passer un appel API personnalisé à un endpoint spécifique",
"Solution": "Solution",
"Table": "Tableau",
"Fields": "Champs",
"Record ID": "ID de l'enregistrement",
"Search Field": "Champ de recherche",
"File": "Ficher",
"Search Value": "Valeur de la recherche",
"Method": "Méthode",
"Headers": "En-têtes",
"Query Parameters": "Paramètres de requête",
"Body": "Corps",
"Response is Binary ?": "La réponse est Binaire ?",
"No Error on Failure": "Aucune erreur en cas d'échec",
"Timeout (in seconds)": "Délai d'expiration (en secondes)",
"The file to upload": "Le fichier à télécharger",
"Authorization headers are injected automatically from your connection.": "Les en-têtes d'autorisation sont injectés automatiquement à partir de votre connexion.",
"Enable for files like PDFs, images, etc..": "Activer pour les fichiers comme les PDFs, les images, etc.",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"New Record": "Nouvel enregistrement",
"Updated Record": "Enregistrement mis à jour",
"Triggers when a new record is created in the specified table": "Déclenche lorsqu'un nouvel enregistrement est créé dans la table spécifiée",
"Triggers when a record is updated in the specified table.": "Déclenche lorsqu'un enregistrement est mis à jour dans la table spécifiée."
}

View File

@@ -0,0 +1,47 @@
{
"Collaborative work management platform combining databases with spreadsheets.": "データベースとスプレッドシートを組み合わせた共同作業管理プラットフォーム。",
"API Key": "API キー",
"Account ID": "アカウントID",
"\n You can obtain API key by navigate to **My Profile->API Key** from top-right corner.\n \n You can obtain Account ID from browser URL.For example, if smartsuite workspace URL is https://app.smartsuite.com/xyz/home, your Account ID is **xyz**.": "\n You can obtain API key by navigate to **My Profile->API Key** from top-right corner.\n \n You can obtain Account ID from browser URL.For example, if smartsuite workspace URL is https://app.smartsuite.com/xyz/home, your Account ID is **xyz**.",
"Create a Record": "レコードを作成",
"Update a Record": "レコードを更新",
"Delete a Record": "レコードを削除",
"Upload File": "ファイルをアップロード",
"Find Records": "レコードを検索",
"Get a Record": "レコードを取得する",
"Custom API Call": "カスタムAPI通話",
"Creates a new record in the specified table.": "指定したテーブルに新しいレコードを作成します。",
"Updates an existing record in the specified table": "指定したテーブル内の既存のレコードを更新します",
"Deletes a record from the specified table": "指定したテーブルからレコードを削除します",
"Uploads a file and attaches it to a record.": "ファイルをアップロードし、レコードに添付します。",
"Searches for records in the specified table based on criteria.": "指定したテーブル内のレコードを条件に基づいて検索します。",
"Retrieves a specific record by ID": "IDで特定のレコードを取得します。",
"Make a custom API call to a specific endpoint": "特定のエンドポイントへのカスタム API コールを実行します。",
"Solution": "解決策",
"Table": "表",
"Fields": "フィールド",
"Record ID": "レコードID",
"Search Field": "検索フィールド",
"File": "ファイル",
"Search Value": "検索値",
"Method": "方法",
"Headers": "ヘッダー",
"Query Parameters": "クエリパラメータ",
"Body": "本文",
"Response is Binary ?": "応答はバイナリですか?",
"No Error on Failure": "失敗時にエラーはありません",
"Timeout (in seconds)": "タイムアウト(秒)",
"The file to upload": "アップロードするファイル",
"Authorization headers are injected automatically from your connection.": "認証ヘッダは接続から自動的に注入されます。",
"Enable for files like PDFs, images, etc..": "PDF、画像などのファイルを有効にします。",
"GET": "取得",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "削除",
"HEAD": "頭",
"New Record": "新しいレコード",
"Updated Record": "更新されたレコード",
"Triggers when a new record is created in the specified table": "指定したテーブルに新しいレコードが作成されたときにトリガーされます。",
"Triggers when a record is updated in the specified table.": "指定したテーブルでレコードが更新されたときにトリガーされます。"
}

View File

@@ -0,0 +1,47 @@
{
"Collaborative work management platform combining databases with spreadsheets.": "Het gezamenlijke werkbeheerplatform dat databases combineert met spreadsheets.",
"API Key": "API Sleutel",
"Account ID": "ID klant",
"\n You can obtain API key by navigate to **My Profile->API Key** from top-right corner.\n \n You can obtain Account ID from browser URL.For example, if smartsuite workspace URL is https://app.smartsuite.com/xyz/home, your Account ID is **xyz**.": "\n Je kunt een API-sleutel verkrijgen door naar **Mijn profiel>API Key** te navigeren vanuit de rechterbovenhoek.\n \n U kunt een Account ID verkrijgen via de browser URL. of voorbeeld, als de smartsuite workspace URL https://app.smartsuite.com/xyz/home is, dan is uw account ID **xyz**.",
"Create a Record": "Een record maken",
"Update a Record": "Een record bijwerken",
"Delete a Record": "Een record verwijderen",
"Upload File": "Bestand uploaden",
"Find Records": "Records zoeken",
"Get a Record": "Krijg een record",
"Custom API Call": "Custom API Call",
"Creates a new record in the specified table.": "Maakt een nieuwe record aan in de opgegeven tabel.",
"Updates an existing record in the specified table": "Werkt een bestaand record in de opgegeven tabel bij",
"Deletes a record from the specified table": "Verwijdert een record van de opgegeven tabel",
"Uploads a file and attaches it to a record.": "Uploaden van een bestand en hecht het aan een record.",
"Searches for records in the specified table based on criteria.": "Zoekt naar records in de opgegeven tabel op basis van criteria.",
"Retrieves a specific record by ID": "Ophalen van een specifiek record via ID",
"Make a custom API call to a specific endpoint": "Maak een aangepaste API call naar een specifiek eindpunt",
"Solution": "Oplossing",
"Table": "Tabel",
"Fields": "Velden",
"Record ID": "Record ID",
"Search Field": "Zoek veld",
"File": "Bestand",
"Search Value": "Waarde zoeken",
"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)",
"The file to upload": "Het bestand om te uploaden",
"Authorization headers are injected automatically from your connection.": "Autorisatie headers worden automatisch geïnjecteerd vanuit uw verbinding.",
"Enable for files like PDFs, images, etc..": "Inschakelen voor bestanden zoals PDF's, afbeeldingen etc..",
"GET": "KRIJG",
"POST": "POSTE",
"PATCH": "BEKIJK",
"PUT": "PUT",
"DELETE": "VERWIJDEREN",
"HEAD": "HOOFD",
"New Record": "Nieuwe Record",
"Updated Record": "Bijgewerkt Record",
"Triggers when a new record is created in the specified table": "Triggert wanneer een nieuwe record wordt aangemaakt in de opgegeven tabel",
"Triggers when a record is updated in the specified table.": "Activeert wanneer een record wordt bijgewerkt in de opgegeven tabel."
}

View File

@@ -0,0 +1,47 @@
{
"Collaborative work management platform combining databases with spreadsheets.": "Plataforma de gerenciamento de trabalho colaborativo combinando bancos de dados com planilhas.",
"API Key": "Chave de API",
"Account ID": "ID da Conta",
"\n You can obtain API key by navigate to **My Profile->API Key** from top-right corner.\n \n You can obtain Account ID from browser URL.For example, if smartsuite workspace URL is https://app.smartsuite.com/xyz/home, your Account ID is **xyz**.": "U\n Você pode obter chave de API navegando até **Minha chave de perfil->API** no canto superior direito.\n \n Você pode obter o ID da conta através do URL do navegador. ou exemplo, se o URL do espaço de trabalho smartsuite for https://app.smartsuite.com/xyz/home, seu ID de conta é **xyz**.",
"Create a Record": "Criar um Registro",
"Update a Record": "Atualizar um Registro",
"Delete a Record": "Apagar um registro",
"Upload File": "Enviar Arquivo",
"Find Records": "Encontrar registros",
"Get a Record": "Obter um Registro",
"Custom API Call": "Chamada de API personalizada",
"Creates a new record in the specified table.": "Cria um novo registro na tabela especificada.",
"Updates an existing record in the specified table": "Atualiza um registro existente na tabela especificada",
"Deletes a record from the specified table": "Exclui um registro da tabela especificada",
"Uploads a file and attaches it to a record.": "Carrega um arquivo e o anexa a um registro.",
"Searches for records in the specified table based on criteria.": "Busca registros na tabela especificada com base em critérios.",
"Retrieves a specific record by ID": "Recupera um registro específico por ID",
"Make a custom API call to a specific endpoint": "Faça uma chamada de API personalizada para um ponto de extremidade específico",
"Solution": "Soluções",
"Table": "Classificações",
"Fields": "campos",
"Record ID": "ID do Registro",
"Search Field": "Campo de pesquisa",
"File": "Arquivo",
"Search Value": "Pesquisar Valor",
"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)",
"The file to upload": "O arquivo para enviar",
"Authorization headers are injected automatically from your connection.": "Os cabeçalhos de autorização são inseridos automaticamente a partir da sua conexão.",
"Enable for files like PDFs, images, etc..": "Habilitar para arquivos como PDFs, imagens, etc..",
"GET": "OBTER",
"POST": "POSTAR",
"PATCH": "COMPRAR",
"PUT": "COLOCAR",
"DELETE": "EXCLUIR",
"HEAD": "CABEÇA",
"New Record": "Novo Registro",
"Updated Record": "Registro atualizado",
"Triggers when a new record is created in the specified table": "Aciona quando um novo registro é criado na tabela especificada",
"Triggers when a record is updated in the specified table.": "Aciona quando um registro é atualizado na tabela especificada."
}

View File

@@ -0,0 +1,46 @@
{
"SmartSuite": "SmartSuite",
"Collaborative work management platform combining databases with spreadsheets.": "Платформа совместного управления работой, объединяющая базы данных с электронными таблицами.",
"API Key": "Ключ API",
"Account ID": "ID клиента",
"\n You can obtain API key by navigate to **My Profile->API Key** from top-right corner.\n \n You can obtain Account ID from browser URL.For example, if smartsuite workspace URL is https://app.smartsuite.com/xyz/home, your Account ID is **xyz**.": "\n Вы можете получить ключ API, перейдя по ссылке **My Profile->API Key** в правом верхнем углу.\n \n Вы можете получить идентификатор аккаунта по URL-адресу браузера. или, например, если URL-адрес smartsuite workspace https://app.smartsuite.com/xyz/home, ваш идентификатор учетной записи **xyz**.",
"Create a Record": "Создать запись",
"Update a Record": "Обновить запись",
"Delete a Record": "Удалить запись",
"Upload File": "Загрузить файл",
"Find Records": "Найти записи",
"Get a Record": "Получить запись",
"Custom API Call": "Пользовательский вызов API",
"Creates a new record in the specified table.": "Создает новую запись в указанной таблице.",
"Updates an existing record in the specified table": "Обновляет существующую запись в указанной таблице",
"Deletes a record from the specified table": "Удаляет запись из указанной таблицы",
"Uploads a file and attaches it to a record.": "Загружает файл и прикрепляет его к записи.",
"Searches for records in the specified table based on criteria.": "Поиск записей в указанной таблице на основе критериев.",
"Retrieves a specific record by ID": "Извлекает определенную запись по ID",
"Make a custom API call to a specific endpoint": "Сделать пользовательский API вызов к определенной конечной точке",
"Solution": "Решение",
"Table": "Таблица",
"Fields": "Поля",
"Record ID": "ID записи",
"Search Field": "Поле поиска",
"File": "Файл",
"Search Value": "Поисковое значение",
"Method": "Метод",
"Headers": "Заголовки",
"Query Parameters": "Параметры запроса",
"Body": "Тело",
"No Error on Failure": "Нет ошибок при ошибке",
"Timeout (in seconds)": "Таймаут (в секундах)",
"The file to upload": "Файл для загрузки",
"Authorization headers are injected automatically from your connection.": "Заголовки авторизации включаются автоматически из вашего соединения.",
"GET": "ПОЛУЧИТЬ",
"POST": "ПОСТ",
"PATCH": "ПАТЧ",
"PUT": "ПОКУПИТЬ",
"DELETE": "УДАЛИТЬ",
"HEAD": "HEAD",
"New Record": "Новая запись",
"Updated Record": "Запись обновлена",
"Triggers when a new record is created in the specified table": "Триггеры при создании новой записи в указанной таблице",
"Triggers when a record is updated in the specified table.": "Триггеры при обновлении записи в указанной таблице."
}

View File

@@ -0,0 +1,47 @@
{
"Collaborative work management platform combining databases with spreadsheets.": "Collaborative work management platform combining databases with spreadsheets.",
"API Key": "API Key",
"Account ID": "Account ID",
"\n You can obtain API key by navigate to **My Profile->API Key** from top-right corner.\n \n You can obtain Account ID from browser URL.For example, if smartsuite workspace URL is https://app.smartsuite.com/xyz/home, your Account ID is **xyz**.": "\n You can obtain API key by navigate to **My Profile->API Key** from top-right corner.\n \n You can obtain Account ID from browser URL.For example, if smartsuite workspace URL is https://app.smartsuite.com/xyz/home, your Account ID is **xyz**.",
"Create a Record": "Create a Record",
"Update a Record": "Update a Record",
"Delete a Record": "Delete a Record",
"Upload File": "Upload File",
"Find Records": "Find Records",
"Get a Record": "Get a Record",
"Custom API Call": "Custom API Call",
"Creates a new record in the specified table.": "Creates a new record in the specified table.",
"Updates an existing record in the specified table": "Updates an existing record in the specified table",
"Deletes a record from the specified table": "Deletes a record from the specified table",
"Uploads a file and attaches it to a record.": "Uploads a file and attaches it to a record.",
"Searches for records in the specified table based on criteria.": "Searches for records in the specified table based on criteria.",
"Retrieves a specific record by ID": "Retrieves a specific record by ID",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Solution": "Solution",
"Table": "Table",
"Fields": "Fields",
"Record ID": "Record ID",
"Search Field": "Search Field",
"File": "File",
"Search Value": "Search Value",
"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)",
"The file to upload": "The file to upload",
"Authorization headers are injected automatically from your connection.": "Authorization headers are injected automatically from your connection.",
"Enable for files like PDFs, images, etc..": "Enable for files like PDFs, images, etc..",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"New Record": "New Record",
"Updated Record": "Updated Record",
"Triggers when a new record is created in the specified table": "Triggers when a new record is created in the specified table",
"Triggers when a record is updated in the specified table.": "Triggers when a record is updated in the specified table."
}

View File

@@ -0,0 +1,46 @@
{
"SmartSuite": "SmartSuite",
"Collaborative work management platform combining databases with spreadsheets.": "Collaborative work management platform combining databases with spreadsheets.",
"API Key": "API Key",
"Account ID": "Account ID",
"\n You can obtain API key by navigate to **My Profile->API Key** from top-right corner.\n \n You can obtain Account ID from browser URL.For example, if smartsuite workspace URL is https://app.smartsuite.com/xyz/home, your Account ID is **xyz**.": "\n You can obtain API key by navigate to **My Profile->API Key** from top-right corner.\n \n You can obtain Account ID from browser URL.For example, if smartsuite workspace URL is https://app.smartsuite.com/xyz/home, your Account ID is **xyz**.",
"Create a Record": "Create a Record",
"Update a Record": "Update a Record",
"Delete a Record": "Delete a Record",
"Upload File": "Upload File",
"Find Records": "Find Records",
"Get a Record": "Get a Record",
"Custom API Call": "Custom API Call",
"Creates a new record in the specified table.": "Creates a new record in the specified table.",
"Updates an existing record in the specified table": "Updates an existing record in the specified table",
"Deletes a record from the specified table": "Deletes a record from the specified table",
"Uploads a file and attaches it to a record.": "Uploads a file and attaches it to a record.",
"Searches for records in the specified table based on criteria.": "Searches for records in the specified table based on criteria.",
"Retrieves a specific record by ID": "Retrieves a specific record by ID",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Solution": "Solution",
"Table": "Table",
"Fields": "Fields",
"Record ID": "Record ID",
"Search Field": "Search Field",
"File": "File",
"Search Value": "Search Value",
"Method": "Method",
"Headers": "Headers",
"Query Parameters": "Query Parameters",
"Body": "Body",
"No Error on Failure": "No Error on Failure",
"Timeout (in seconds)": "Timeout (in seconds)",
"The file to upload": "The file to upload",
"Authorization headers are injected automatically from your connection.": "Authorization headers are injected automatically from your connection.",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"New Record": "New Record",
"Updated Record": "Updated Record",
"Triggers when a new record is created in the specified table": "Triggers when a new record is created in the specified table",
"Triggers when a record is updated in the specified table.": "Triggers when a record is updated in the specified table."
}

View File

@@ -0,0 +1,47 @@
{
"Collaborative work management platform combining databases with spreadsheets.": "Collaborative work management platform combining databases with spreadsheets.",
"API Key": "API 密钥",
"Account ID": "Account ID",
"\n You can obtain API key by navigate to **My Profile->API Key** from top-right corner.\n \n You can obtain Account ID from browser URL.For example, if smartsuite workspace URL is https://app.smartsuite.com/xyz/home, your Account ID is **xyz**.": "\n You can obtain API key by navigate to **My Profile->API Key** from top-right corner.\n \n You can obtain Account ID from browser URL.For example, if smartsuite workspace URL is https://app.smartsuite.com/xyz/home, your Account ID is **xyz**.",
"Create a Record": "Create a Record",
"Update a Record": "Update a Record",
"Delete a Record": "Delete a Record",
"Upload File": "Upload File",
"Find Records": "Find Records",
"Get a Record": "Get a Record",
"Custom API Call": "自定义 API 呼叫",
"Creates a new record in the specified table.": "Creates a new record in the specified table.",
"Updates an existing record in the specified table": "Updates an existing record in the specified table",
"Deletes a record from the specified table": "Deletes a record from the specified table",
"Uploads a file and attaches it to a record.": "Uploads a file and attaches it to a record.",
"Searches for records in the specified table based on criteria.": "Searches for records in the specified table based on criteria.",
"Retrieves a specific record by ID": "Retrieves a specific record by ID",
"Make a custom API call to a specific endpoint": "将一个自定义 API 调用到一个特定的终点",
"Solution": "Solution",
"Table": "表",
"Fields": "Fields",
"Record ID": "Record ID",
"Search Field": "Search Field",
"File": "文件",
"Search Value": "搜索值",
"Method": "方法",
"Headers": "信头",
"Query Parameters": "查询参数",
"Body": "正文内容",
"Response is Binary ?": "Response is Binary ?",
"No Error on Failure": "失败时没有错误",
"Timeout (in seconds)": "超时(秒)",
"The file to upload": "The file to upload",
"Authorization headers are injected automatically from your connection.": "授权头自动从您的连接中注入。",
"Enable for files like PDFs, images, etc..": "Enable for files like PDFs, images, etc..",
"GET": "获取",
"POST": "帖子",
"PATCH": "PATCH",
"PUT": "弹出",
"DELETE": "删除",
"HEAD": "黑色",
"New Record": "New Record",
"Updated Record": "Updated Record",
"Triggers when a new record is created in the specified table": "Triggers when a new record is created in the specified table",
"Triggers when a record is updated in the specified table.": "Triggers when a record is updated in the specified table."
}

View File

@@ -0,0 +1,51 @@
import {
createPiece,
PiecePropValueSchema,
} from '@activepieces/pieces-framework';
import { PieceCategory } from '@activepieces/shared';
import { smartsuiteAuth } from './lib/auth';
// Actions
import { createRecord } from './lib/actions/create-record';
import { updateRecord } from './lib/actions/update-record';
import { deleteRecord } from './lib/actions/delete-record';
import { uploadFile } from './lib/actions/upload-file';
import { findRecords } from './lib/actions/find-records';
import { getRecord } from './lib/actions/get-record';
// Triggers
import { newRecord } from './lib/triggers/new-record';
import { updatedRecord } from './lib/triggers/updated-record';
import { createCustomApiCallAction } from '@activepieces/pieces-common';
import { SMARTSUITE_API_URL } from './lib/common/constants';
export const smartsuite = createPiece({
displayName: 'SmartSuite',
description:
'Collaborative work management platform combining databases with spreadsheets.',
logoUrl: 'https://cdn.activepieces.com/pieces/smartsuite.png',
categories: [PieceCategory.PRODUCTIVITY],
auth: smartsuiteAuth,
minimumSupportedRelease: '0.30.0',
authors: ['Kunal-Darekar', 'kishanprmr'],
actions: [
createRecord,
updateRecord,
deleteRecord,
uploadFile,
findRecords,
getRecord,
createCustomApiCallAction({
auth: smartsuiteAuth,
baseUrl: () => SMARTSUITE_API_URL,
authMapping: async (auth) => {
const authValue = auth
return {
Authorization: `Token ${auth.props.apiKey}`,
'ACCOUNT-ID': auth.props.accountId,
};
},
}),
],
triggers: [newRecord, updatedRecord],
});

View File

@@ -0,0 +1,64 @@
import { createAction } from '@activepieces/pieces-framework';
import { HttpMethod } from '@activepieces/pieces-common';
import { smartsuiteAuth } from '../auth';
import { smartsuiteCommon, formatRecordFields, transformRecordFields } from '../common/props';
import { smartSuiteApiCall, TableStucture } from '../common';
export const createRecord = createAction({
name: 'create_record',
displayName: 'Create a Record',
description: 'Creates a new record in the specified table.',
auth: smartsuiteAuth,
props: {
solutionId: smartsuiteCommon.solutionId,
tableId: smartsuiteCommon.tableId,
fields: smartsuiteCommon.tableFields,
},
async run({ auth, propsValue }) {
const { tableId, fields, solutionId } = propsValue;
const tableResponse = await smartSuiteApiCall<{
structure: TableStucture[];
}>({
apiKey: auth.props.apiKey,
accountId: auth.props.accountId,
method: HttpMethod.GET,
resourceUri: `/applications/${tableId}`,
});
const tableSchema = tableResponse.structure;
const formattedFields = formatRecordFields(tableSchema, fields);
try {
const response = await smartSuiteApiCall<Record<string, any>>({
apiKey: auth.props.apiKey,
accountId: auth.props.accountId,
method: HttpMethod.POST,
resourceUri: `/applications/${tableId}/records/`,
body: formattedFields,
});
const transformedFields = transformRecordFields(tableSchema, response);
return transformedFields;
} catch (error: any) {
if (error.response?.status === 422) {
throw new Error(
`Invalid request: ${
error.response?.body?.message || 'Missing required fields or invalid data'
}`,
);
}
if (error.response?.status === 403) {
throw new Error('You do not have permission to create records in this table');
}
if (error.response?.status === 404) {
throw new Error(`Solution or table not found: ${solutionId}/${tableId}`);
}
throw new Error(`Failed to create record: ${error.message || 'Unknown error'}`);
}
},
});

View File

@@ -0,0 +1,41 @@
import { createAction } from '@activepieces/pieces-framework';
import { HttpMethod} from '@activepieces/pieces-common';
import { smartsuiteAuth } from '../auth';
import { smartsuiteCommon } from '../common/props';
import { smartSuiteApiCall } from '../common';
export const deleteRecord = createAction({
name: 'delete_record',
displayName: 'Delete a Record',
description: 'Deletes a record from the specified table',
auth: smartsuiteAuth,
props: {
solutionId: smartsuiteCommon.solutionId,
tableId: smartsuiteCommon.tableId,
recordId: smartsuiteCommon.recordId,
},
async run({ auth, propsValue }) {
const { tableId, recordId } = propsValue;
try {
const response = await smartSuiteApiCall<Record<string, any>>({
apiKey: auth.props.apiKey,
accountId: auth.props.accountId,
method: HttpMethod.DELETE,
resourceUri: `/applications/${tableId}/records/${recordId}/`,
});
return response;
} catch (error: any) {
if (error.response?.status === 404) {
throw new Error(`Record with ID ${recordId} not found in table ${tableId}`);
}
if (error.response?.status === 403) {
throw new Error('You do not have permission to delete this record');
}
throw new Error(`Failed to delete record: ${error.message || 'Unknown error'}`);
}
},
});

View File

@@ -0,0 +1,136 @@
import {
DropdownOption,
Property,
createAction,
} from '@activepieces/pieces-framework';
import { HttpMethod } from '@activepieces/pieces-common';
import { smartsuiteAuth } from '../auth';
import { smartsuiteCommon, transformRecordFields } from '../common/props';
import { smartSuiteApiCall, TableStucture } from '../common';
export const findRecords = createAction({
name: 'find_records',
displayName: 'Find Records',
description: 'Searches for records in the specified table based on criteria.',
auth: smartsuiteAuth,
props: {
solutionId: smartsuiteCommon.solutionId,
tableId: smartsuiteCommon.tableId,
searchField: Property.Dropdown({
auth: smartsuiteAuth,
displayName: 'Search Field',
required: true,
refreshers: ['tableId'],
options: async ({ auth, tableId }) => {
if (!auth || !tableId) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first.',
};
}
const { apiKey, accountId } = auth.props;
const response = await smartSuiteApiCall<{
structure: TableStucture[];
}>({
apiKey,
accountId,
method: HttpMethod.GET,
resourceUri: `/applications/${tableId}`,
});
const options: DropdownOption<string>[] = [];
for (const field of response.structure) {
if (field.params.is_auto_generated || field.params.system) {
continue;
}
options.push({ label: field.label, value: field.slug });
}
return {
disabled: false,
options,
};
},
}),
searchValue: Property.ShortText({
displayName: 'Search Value',
required: true,
}),
},
async run({ auth, propsValue }) {
const { solutionId, tableId, searchField, searchValue } = propsValue;
try {
const tableResponse = await smartSuiteApiCall<{
structure: TableStucture[];
}>({
apiKey: auth.props.apiKey,
accountId: auth.props.accountId,
method: HttpMethod.GET,
resourceUri: `/applications/${tableId}`,
});
const tableSchema = tableResponse.structure;
const matchedRecords = [];
const qs = { limit: 100, offset: 0 };
let hasMore = true;
do {
const response = await smartSuiteApiCall<{ items: Record<string, any>[] }>({
accountId: auth.props.accountId,
apiKey: auth.props.apiKey,
method: HttpMethod.POST,
resourceUri: `/applications/${tableId}/records/list/`,
query: qs,
body: {
filter: {
operator: 'and',
fields: [
{
field: searchField,
comparison: 'is',
value: searchValue,
},
],
},
},
});
const items = response.items || [];
matchedRecords.push(...items);
hasMore = items.length > 0;
if (hasMore) {
qs.offset = Number(qs.offset) + Number(qs.limit);
}
} while (hasMore);
return {
found: matchedRecords.length > 0,
result: matchedRecords.map((record) => transformRecordFields(tableSchema, record)),
};
} catch (error: any) {
if (error.response?.status === 400) {
throw new Error(
`Invalid filter or sort criteria: ${
error.response?.body?.message || 'Please check your filter JSON format'
}`,
);
}
if (error.response?.status === 403) {
throw new Error('You do not have permission to access this table');
}
if (error.response?.status === 404) {
throw new Error(`Solution or table not found: ${solutionId}/${tableId}`);
}
throw new Error(`Failed to find records: ${error.message || 'Unknown error'}`);
}
},
});

View File

@@ -0,0 +1,52 @@
import { createAction } from '@activepieces/pieces-framework';
import { HttpMethod } from '@activepieces/pieces-common';
import { smartsuiteAuth } from '../auth';
import { smartsuiteCommon, transformRecordFields } from '../common/props';
import { smartSuiteApiCall, TableStucture } from '../common';
export const getRecord = createAction({
name: 'get_record',
displayName: 'Get a Record',
description: 'Retrieves a specific record by ID',
auth: smartsuiteAuth,
props: {
solutionId: smartsuiteCommon.solutionId,
tableId: smartsuiteCommon.tableId,
recordId: smartsuiteCommon.recordId,
},
async run({ auth, propsValue }) {
const { tableId, recordId } = propsValue;
try {
const tableResponse = await smartSuiteApiCall<{
structure: TableStucture[];
}>({
apiKey: auth.props.apiKey,
accountId: auth.props.accountId,
method: HttpMethod.GET,
resourceUri: `/applications/${tableId}`,
});
const tableSchema = tableResponse.structure;
const response = await smartSuiteApiCall<Record<string, any>>({
apiKey: auth.props.apiKey,
accountId: auth.props.accountId,
method: HttpMethod.GET,
resourceUri: `/applications/${tableId}/records/${recordId}/`,
});
const transformedFields = transformRecordFields(tableSchema, response);
return transformedFields;
} catch (error: any) {
if (error.response?.status === 403) {
throw new Error('You do not have permission to access this record');
}
if (error.response?.status === 404) {
throw new Error(`Record with ID ${recordId} not found in table ${tableId}`);
}
throw new Error(`Failed to get record: ${error.message || 'Unknown error'}`);
}
},
});

View File

@@ -0,0 +1,63 @@
import { createAction } from '@activepieces/pieces-framework';
import { HttpMethod } from '@activepieces/pieces-common';
import { smartsuiteAuth } from '../auth';
import { smartsuiteCommon, formatRecordFields, transformRecordFields } from '../common/props';
import { smartSuiteApiCall, TableStucture } from '../common';
export const updateRecord = createAction({
name: 'update_record',
displayName: 'Update a Record',
description: 'Updates an existing record in the specified table',
auth: smartsuiteAuth,
props: {
solutionId: smartsuiteCommon.solutionId,
tableId: smartsuiteCommon.tableId,
recordId: smartsuiteCommon.recordId,
fields: smartsuiteCommon.tableFields,
},
async run({ auth, propsValue }) {
const { tableId, recordId, fields } = propsValue;
const tableResponse = await smartSuiteApiCall<{
structure: TableStucture[];
}>({
apiKey: auth.props.apiKey,
accountId: auth.props.accountId,
method: HttpMethod.GET,
resourceUri: `/applications/${tableId}`,
});
const tableSchema = tableResponse.structure;
const formattedFields = formatRecordFields(tableSchema, fields);
try {
const response = await smartSuiteApiCall<Record<string, any>>({
apiKey: auth.props.apiKey,
accountId: auth.props.accountId,
method: HttpMethod.PATCH,
resourceUri: `/applications/${tableId}/records/${recordId}/`,
body: formattedFields,
});
const transformedFields = transformRecordFields(tableSchema, response);
return transformedFields;
} catch (error: any) {
if (error.response?.status === 422) {
throw new Error(
`Invalid request: ${error.response?.body?.message || 'Invalid data format'}`,
);
}
if (error.response?.status === 403) {
throw new Error('You do not have permission to update this record');
}
if (error.response?.status === 404) {
throw new Error(`Record with ID ${recordId} not found in table ${tableId}`);
}
throw new Error(`Failed to update record: ${error.message || 'Unknown error'}`);
}
},
});

View File

@@ -0,0 +1,123 @@
import {
DropdownOption,
PiecePropValueSchema,
Property,
createAction,
} from '@activepieces/pieces-framework';
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
import { smartsuiteAuth } from '../auth';
import { smartsuiteCommon, transformRecordFields } from '../common/props';
import { smartSuiteApiCall, TableStucture } from '../common';
import FormData from 'form-data';
export const uploadFile = createAction({
name: 'upload_file',
displayName: 'Upload File',
description: 'Uploads a file and attaches it to a record.',
auth: smartsuiteAuth,
props: {
solutionId: smartsuiteCommon.solutionId,
tableId: smartsuiteCommon.tableId,
recordId: smartsuiteCommon.recordId,
field: Property.Dropdown({
auth: smartsuiteAuth,
displayName: 'Search Field',
required: true,
refreshers: ['tableId'],
options: async ({ auth, tableId }) => {
if (!auth || !tableId) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first.',
};
}
const { apiKey, accountId } = auth.props;
const response = await smartSuiteApiCall<{
structure: TableStucture[];
}>({
apiKey,
accountId,
method: HttpMethod.GET,
resourceUri: `/applications/${tableId}`,
});
const options: DropdownOption<string>[] = [];
for (const field of response.structure) {
if (field.field_type === 'filefield') {
options.push({ label: field.label, value: field.slug });
}
}
return {
disabled: false,
options,
};
},
}),
file: Property.File({
displayName: 'File',
description: 'The file to upload',
required: true,
}),
},
async run({ auth, propsValue }) {
const { recordId, field, tableId, file } = propsValue;
try {
const formData = new FormData();
formData.append('files', Buffer.from(file.base64, 'base64'), file.filename);
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: `https://app.smartsuite.com/api/v1/recordfiles/${tableId}/${recordId}/${field}/`,
body: formData,
headers: {
...formData.getHeaders(),
Authorization: `Token ${auth.props.apiKey}`,
'ACCOUNT-ID': auth.props.accountId,
},
});
const tableResponse = await smartSuiteApiCall<{
structure: TableStucture[];
}>({
apiKey: auth.props.apiKey,
accountId: auth.props.accountId,
method: HttpMethod.GET,
resourceUri: `/applications/${tableId}`,
});
const tableSchema = tableResponse.structure;
const formattedFields = transformRecordFields(tableSchema, response.body);
return formattedFields;
} catch (error: any) {
if (error.response?.status === 400) {
throw new Error(
`Invalid file format or size: ${
error.response?.body?.message || 'File may be too large or in an unsupported format'
}`,
);
}
if (error.response?.status === 403) {
throw new Error('You do not have permission to upload files to this record');
}
if (error.response?.status === 404) {
throw new Error(
`Record with ID ${recordId} not found or field ${field} is not a file field`,
);
}
if (error.response?.status === 413) {
throw new Error('File is too large. SmartSuite has file size limits');
}
throw new Error(`Failed to upload file: ${error.message || 'Unknown error'}`);
}
},
});

View File

@@ -0,0 +1,40 @@
import { PieceAuth, Property } from '@activepieces/pieces-framework';
import { HttpMethod } from '@activepieces/pieces-common';
import { smartSuiteApiCall } from './common';
export const smartsuiteAuth = PieceAuth.CustomAuth({
description: `
You can obtain API key by navigate to **My Profile->API Key** from top-right corner.
You can obtain Account ID from browser URL.For example, if smartsuite workspace URL is https://app.smartsuite.com/xyz/home, your Account ID is **xyz**.`,
required: true,
props: {
apiKey: PieceAuth.SecretText({
displayName: 'API Key',
required: true,
}),
accountId: Property.ShortText({
displayName: 'Account ID',
required: true,
}),
},
validate: async ({ auth }) => {
try {
await smartSuiteApiCall({
apiKey: auth.apiKey,
accountId: auth.accountId,
method: HttpMethod.GET,
resourceUri: '/solutions',
});
return {
valid: true,
};
} catch (e) {
return {
valid: false,
error: 'Invalid Credentials.',
};
}
},
});

View File

@@ -0,0 +1,18 @@
export const SMARTSUITE_API_URL = 'https://app.smartsuite.com/api/v1';
export const SMARTSUITE_WEBHOOKS_API_URL = 'https://webhooks.smartsuite.com/smartsuite.webhooks.engine.Webhooks';
export const WEBHOOK_EVENTS = {
RECORD_CREATED: 'RECORD_CREATED',
RECORD_UPDATED: 'RECORD_UPDATED',
RECORD_DELETED: 'RECORD_DELETED',
};
export const API_ENDPOINTS = {
// Webhooks
CREATE_WEBHOOK: '/CreateWebhook',
LIST_WEBHOOKS: '/ListWebhooks',
GET_WEBHOOK: '/GetWebhook',
UPDATE_WEBHOOK: '/UpdateWebhook',
DELETE_WEBHOOK: '/DeleteWebhook',
LIST_EVENTS: '/ListEvents',
};

View File

@@ -0,0 +1,104 @@
import {
httpClient,
HttpMessageBody,
HttpMethod,
HttpRequest,
QueryParams,
} from '@activepieces/pieces-common';
import { SMARTSUITE_API_URL } from './constants';
import { isNil } from '@activepieces/shared';
export type SmartSuiteApiCallParams = {
apiKey: string;
accountId: string;
method: HttpMethod;
resourceUri: string;
query?: Record<string, string | number | string[] | undefined>;
body?: any;
};
export type PaginatedResponse<T> = {
results: T[];
count: number;
next?: string;
previous?: string;
};
export type TableStucture = {
slug: string;
label: string;
field_type: string;
params: {
is_auto_generated: boolean;
system: boolean;
choices?: { label: string; value: string }[];
};
};
export async function smartSuiteApiCall<T extends HttpMessageBody>({
apiKey,
accountId,
method,
resourceUri,
query,
body,
}: SmartSuiteApiCallParams): Promise<T> {
const qs: QueryParams = {};
if (query) {
for (const [key, value] of Object.entries(query)) {
if (value !== null && value !== undefined) {
qs[key] = String(value);
}
}
}
const request: HttpRequest = {
method,
url: SMARTSUITE_API_URL + resourceUri,
headers: {
Authorization: `Token ${apiKey}`,
'ACCOUNT-ID': accountId,
},
queryParams: qs,
body,
};
const response = await httpClient.sendRequest<T>(request);
return response.body;
}
export async function smartSuitePaginatedApiCall<T extends HttpMessageBody>({
apiKey,
accountId,
method,
resourceUri,
query,
body,
}: SmartSuiteApiCallParams): Promise<T[]> {
const qs = { ...(query || {}), limit: 100, offset: 0 };
const resultData: T[] = [];
let hasMore = true;
do {
const response = await smartSuiteApiCall<PaginatedResponse<T>>({
accountId,
apiKey,
method,
resourceUri,
query: qs,
body,
});
const items = response.results || [];
resultData.push(...items);
hasMore = !!response.next && items.length > 0;
if (hasMore) {
qs.offset = Number(qs.offset) + Number(qs.limit);
}
} while (hasMore);
return resultData;
}

View File

@@ -0,0 +1,366 @@
import { Property, DynamicPropsValue, PiecePropValueSchema } from '@activepieces/pieces-framework';
import { HttpMethod } from '@activepieces/pieces-common';
import { smartSuiteApiCall, smartSuitePaginatedApiCall, TableStucture } from '.';
import { smartsuiteAuth } from '../auth';
import { isNil } from '@activepieces/shared';
export const smartsuiteCommon = {
solutionId: Property.Dropdown({
auth: smartsuiteAuth,
displayName: 'Solution',
required: true,
refreshers: [],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please enter your API key first.',
};
}
const { apiKey, accountId } = auth.props;
try {
const response = await smartSuitePaginatedApiCall<{
name: string;
id: string;
hidden: boolean;
}>({
apiKey,
accountId,
method: HttpMethod.GET,
resourceUri: '/solutions',
});
return {
disabled: false,
options: response
.filter((solution) => !solution.hidden)
.map((solution) => {
return {
label: solution.name,
value: solution.id,
};
}),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Error fetching solutions. Please check your API key.',
};
}
},
}),
tableId: Property.Dropdown({
auth: smartsuiteAuth,
displayName: 'Table',
required: true,
refreshers: ['solutionId'],
options: async ({ auth, solutionId }) => {
if (!auth || !solutionId) {
return {
disabled: true,
options: [],
placeholder: solutionId
? 'Please select a solution first.'
: 'Please enter your API key first.',
};
}
const { apiKey, accountId } = auth.props;
try {
const response = await smartSuitePaginatedApiCall<{
id: string;
name: string;
}>({
apiKey,
accountId,
method: HttpMethod.GET,
resourceUri: '/applications',
query: {
solution: solutionId as string,
},
});
return {
disabled: false,
options: response.map((table) => {
return {
label: table.name,
value: table.id,
};
}),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Error fetching tables. Please check your permissions.',
};
}
},
}),
tableFields: Property.DynamicProperties({
auth: smartsuiteAuth,
displayName: 'Fields',
required: true,
refreshers: ['solutionId', 'tableId'],
props: async ({ auth, solutionId, tableId }) => {
if (!auth || !solutionId || !tableId) {
return {};
}
const { apiKey, accountId } = auth.props;
try {
const response = await smartSuiteApiCall<{
structure: TableStucture[];
}>({
apiKey,
accountId,
method: HttpMethod.GET,
resourceUri: `/applications/${tableId}`,
});
const fieldProperties: DynamicPropsValue = {};
for (const field of response.structure) {
if (
field.params.is_auto_generated ||
field.params.system ||
[
'countfield',
'autonumberfield',
'rollupfield',
'votefield',
'filefield',
'fullnamefield',
'addressfield',
'daterangefield',
'duedatefield',
'userfield',
'checklistfield',
'signaturefield',
'subitemsfield',
'buttonfield',
'lookupfield',
'phonefield',
].includes(field.field_type)
) {
continue;
}
switch (field.field_type) {
case 'recordtitlefield':
case 'textfield':
case 'emailfield':
case 'linkfield':
case 'durationfield':
case 'numberfield':
case 'colorpickerfield':
case 'percentfield':
case 'currencyfield':
fieldProperties[field.slug] = Property.ShortText({
displayName: field.label,
required: false,
});
break;
case 'timefield':
fieldProperties[field.slug] = Property.ShortText({
displayName: field.label,
description: 'Provide value in HH:mm:ss format.',
required: false,
});
break;
case 'richtextareafield':
case 'textareafield':
fieldProperties[field.slug] = Property.LongText({
displayName: field.label,
required: false,
});
break;
case 'numbersliderfield':
case 'percentcompletefield':
case 'ratingfield':
fieldProperties[field.slug] = Property.Number({
displayName: field.label,
required: false,
});
break;
case 'yesnofield':
fieldProperties[field.slug] = Property.Checkbox({
displayName: field.label,
required: false,
});
break;
case 'datefield':
fieldProperties[field.slug] = Property.DateTime({
displayName: field.label,
required: false,
});
break;
case 'statusfield':
case 'singleselectfield':
fieldProperties[field.slug] = Property.StaticDropdown({
displayName: field.label,
required: false,
options: {
disabled: false,
options: field.params.choices
? field.params.choices.map((choice) => ({
label: choice.label,
value: choice.value,
}))
: [],
},
});
break;
case 'linkedrecordfield':
fieldProperties[field.slug] = Property.Array({
displayName: field.label,
required: false,
description: 'Provide Record IDs to link.',
});
break;
case 'multipleselectfield':
fieldProperties[field.slug] = Property.StaticMultiSelectDropdown({
displayName: field.label,
required: false,
options: {
disabled: false,
options: field.params.choices
? field.params.choices.map((choice) => ({
label: choice.label,
value: choice.value,
}))
: [],
},
});
break;
}
}
return fieldProperties;
} catch (error) {
return {};
}
},
}),
recordId: Property.ShortText({
displayName: 'Record ID',
required: true,
}),
};
export function formatRecordFields(
tableSchema: TableStucture[],
tableValues: Record<string, any>,
): Record<string, any> {
const formattedFields: Record<string, any> = {};
const fieldMap: Record<string, string> = tableSchema.reduce((acc, field) => {
acc[field.slug] = field.field_type;
return acc;
}, {} as Record<string, string>);
for (const [key, value] of Object.entries(tableValues)) {
if (isNil(value) || value === '') continue;
const fieldType = fieldMap[key];
switch (fieldType) {
case 'recordtitlefield':
case 'textfield':
case 'durationfield':
case 'timefield':
case 'textareafield':
case 'numberfield':
case 'numbersliderfield':
case 'percentfield':
case 'currencyfield':
case 'percentcompletefield':
case 'ratingfield':
case 'yesnofield':
case 'singleselectfield':
formattedFields[key] = value;
break;
case 'emailfield':
case 'linkfield':
formattedFields[key] = [value];
break;
case 'colorpickerfield':
formattedFields[key] = [
{
value,
},
];
break;
case 'datefield':
formattedFields[key] = {
date: value,
include_time: false,
};
break;
case 'statusfield':
formattedFields[key] = {
value,
};
break;
case 'richtextareafield':
formattedFields[key] = {
data: {
type: 'doc',
content: [
{
type: 'paragraph',
attrs: {
textAlign: 'left',
size: 'medium',
},
content: [
{
type: 'text',
text: value,
},
],
},
],
},
};
break;
case 'linkedrecordfield':
case 'multipleselectfield': {
if (Array.isArray(value) && value.length > 0) {
formattedFields[key] = value;
}
break;
}
default:
break;
}
}
return formattedFields;
}
export function transformRecordFields(
tableSchema: TableStucture[],
tableValues: Record<string, any>,
) {
const fieldMap: Record<string, string> = tableSchema.reduce((acc, field) => {
acc[field.slug] = field.label;
return acc;
}, {} as Record<string, string>);
const transformedFields: Record<string, any> = {};
for (const [slug, value] of Object.entries(tableValues)) {
const label = fieldMap[slug] ?? slug;
transformedFields[label] = value;
}
return transformedFields;
}

View File

@@ -0,0 +1,441 @@
import { TriggerStrategy, createTrigger } from '@activepieces/pieces-framework';
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
import { smartsuiteAuth } from '../auth';
import { smartsuiteCommon, transformRecordFields } from '../common/props';
import { SMARTSUITE_WEBHOOKS_API_URL, API_ENDPOINTS, WEBHOOK_EVENTS } from '../common/constants';
import { smartSuiteApiCall, TableStucture } from '../common';
export const newRecord = createTrigger({
name: 'new_record',
displayName: 'New Record',
description: 'Triggers when a new record is created in the specified table',
type: TriggerStrategy.WEBHOOK,
auth: smartsuiteAuth,
props: {
solutionId: smartsuiteCommon.solutionId,
tableId: smartsuiteCommon.tableId,
},
async onEnable(context) {
const { solutionId, tableId } = context.propsValue;
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: `${SMARTSUITE_WEBHOOKS_API_URL}${API_ENDPOINTS.CREATE_WEBHOOK}`,
body: {
webhook: {
filter: {
applications: {
application_ids: [tableId],
},
},
kinds: [WEBHOOK_EVENTS.RECORD_CREATED],
locator: {
account_id: context.auth.props.accountId, // This will be filled by SmartSuite based on the API key
solution_id: solutionId,
},
notification_status: {
enabled: {
url: context.webhookUrl,
},
},
},
},
headers: {
Authorization: `Token ${context.auth.props.apiKey}`,
'ACCOUNT-ID': context.auth.props.accountId,
},
});
await context.store.put('new_record', response.body.webhook.webhook_id);
},
async onDisable(context) {
const webhookId = await context.store.get('new_record');
if (webhookId) {
await httpClient.sendRequest({
method: HttpMethod.POST,
url: `${SMARTSUITE_WEBHOOKS_API_URL}${API_ENDPOINTS.DELETE_WEBHOOK}`,
body: {
webhook_id: webhookId,
},
headers: {
Authorization: `Token ${context.auth.props.apiKey}`,
'ACCOUNT-ID': context.auth.props.accountId,
},
});
}
},
async test(context) {
const { tableId } = context.propsValue;
const response = await smartSuiteApiCall<{ items: Record<string, any>[] }>({
accountId: context.auth.props.accountId,
apiKey: context.auth.props.apiKey,
method: HttpMethod.POST,
resourceUri: `/applications/${tableId}/records/list/`,
query: { limit: '5', offset: '0' },
});
const items = response.items || [];
const tableResponse = await smartSuiteApiCall<{
structure: TableStucture[];
}>({
apiKey: context.auth.props.apiKey,
accountId: context.auth.props.accountId,
method: HttpMethod.GET,
resourceUri: `/applications/${context.propsValue.tableId}`,
});
const tableSchema = tableResponse.structure;
return items.map((item) => transformRecordFields(tableSchema, item));
},
async run(context) {
const webhookPayload = context.payload.body as {
webhookId: string;
locator: {
accountId: string;
solutionId: string;
};
};
let pageToken = (await context.store.get('pageToken')) ?? '';
if (!webhookPayload || !webhookPayload.webhookId || !webhookPayload.locator) {
return [];
}
const events = [];
let hasMore = true;
do {
const response = await httpClient.sendRequest<{
events: { record_event_data: { data: Record<string, any> } }[];
next_page_token: string;
}>({
method: HttpMethod.POST,
url: `${SMARTSUITE_WEBHOOKS_API_URL}${API_ENDPOINTS.LIST_EVENTS}`,
body: {
webhook_id: webhookPayload.webhookId,
page_size: '50',
page_token: pageToken,
},
headers: {
Authorization: `Token ${context.auth.props.apiKey}`,
'ACCOUNT-ID': context.auth.props.accountId,
},
});
pageToken = response.body.next_page_token;
const items = response.body.events ?? [];
events.push(...items);
hasMore = items.length > 0;
} while (hasMore);
await context.store.put('pageToken', pageToken);
const tableResponse = await smartSuiteApiCall<{
structure: TableStucture[];
}>({
apiKey: context.auth.props.apiKey,
accountId: context.auth.props.accountId,
method: HttpMethod.GET,
resourceUri: `/applications/${context.propsValue.tableId}`,
});
const tableSchema = tableResponse.structure;
return events.map((event) => transformRecordFields(tableSchema, event.record_event_data.data));
},
sampleData: {
Title: 'First Record',
Description: {
data: {
type: 'doc',
content: [
{
type: 'paragraph',
attrs: {
textAlign: 'left',
size: 'medium',
},
content: [
{
type: 'text',
text: 'xxzxzxzxzxz',
},
],
},
{
type: 'paragraph',
attrs: {
textAlign: 'left',
size: 'medium',
},
content: [
{
type: 'text',
text: 'xzxzxz',
},
],
},
{
type: 'paragraph',
attrs: {
textAlign: 'left',
size: 'medium',
},
content: [
{
type: 'text',
text: 'xzxz',
},
],
},
],
},
html: '<div class="rendered"><p class="align-left" >xxzxzxzxzxz</p><p class="align-left" >xzxzxz</p><p class="align-left" >xzxz</p></div>',
preview: 'xxzxzxzxzxz\n xzxzxz\n xzxz',
yjsData: '',
},
Status: {
value: 'backlog',
updated_on: '2025-05-25T14:52:17.110000Z',
},
'First Created': {
on: '2025-05-25T14:52:16.977000Z',
by: '682c72c82336bf787bb5c7a0',
},
'Last Updated': {
on: '2025-05-26T10:52:14.987027Z',
by: '682c72c82336bf787bb5c7a0',
},
'Followed by': [],
'Open Comments': 0,
'Auto Number': 1,
'text-field': 'text',
'Text Area': 'area',
Number: '12.0',
'Number Slider': 33,
Percent: '12.0',
Currency: '12',
'Yes / No': true,
'Single Select': '3u0Cl',
'Multiple Select': ['bZfFn', 'LvQIv'],
Date: {
date: '2025-05-30T00:00:00Z',
include_time: false,
},
'Full Name': {
title: '',
first_name: 'john',
middle_name: '',
last_name: 'doe',
sys_root: 'john doe',
},
Email: ['johndoe@gmail.com'],
Phone: [
{
phone_country: 'IN',
phone_number: '',
phone_extension: '',
phone_type: 2,
sys_root: '',
sys_title: '',
},
],
Address: {
location_address: '',
location_address2: '',
location_zip: '',
location_country: '',
location_state: '',
location_city: '',
location_longitude: '72.2',
location_latitude: '21.12',
sys_root: '',
},
Link: ['https://github.com'],
'Files and Images': [
{
handle: 'CeRMEqhySiFboDMkiZlx',
metadata: {
container: 'smart-suite-media',
filename: 'spotify.png',
key: 'PAfWmgwRnOhw6KJygepi_spotify.png',
mimetype: 'image/png',
size: 23422,
},
transform_options: {},
created_on: '2025-05-26T10:47:12.586000Z',
updated_on: '2025-05-26T10:47:12.586000Z',
description: '',
video_conversion_status: '',
video_thumbnail_handle: '',
converted_video_handle: '',
file_type: 'image',
icon: 'image',
},
{
handle: 'GUQyUrvYQrpswR97N8jT',
metadata: {
container: 'smart-suite-media',
filename: 'zagomail.png',
key: 'CSHRsjZRVS6HIFvJEfqQ_zagomail.png',
mimetype: 'image/png',
size: 96995,
},
transform_options: {},
created_on: '2025-05-26T10:49:41.891000Z',
updated_on: '2025-05-26T10:49:41.891000Z',
description: '',
video_conversion_status: '',
video_thumbnail_handle: '',
converted_video_handle: '',
file_type: 'image',
icon: 'image',
},
{
handle: 'eUhDadE9Q3yFz3XLCEgC',
metadata: {
container: 'smart-suite-media',
filename: 'coda.png',
key: 'BrE3gQheS108HgFd1HYT_coda.png',
mimetype: 'image/png',
size: 880,
},
transform_options: {},
created_on: '2025-05-26T10:52:14.981371Z',
updated_on: '2025-05-26T10:52:14.981377Z',
description: '',
video_conversion_status: '',
video_thumbnail_handle: '',
converted_video_handle: '',
file_type: 'image',
icon: 'image',
},
],
SmartDoc: {
data: {},
html: '',
preview: '',
yjsData: 'AAA=',
},
'Link to Tasks': ['682c72c84386b2737cab1bd0', '682c72c84386b2737cab1bcf'],
Time: '00:15:00',
'Date Range': {
from_date: {
date: '2025-05-25T00:00:00Z',
include_time: false,
},
to_date: {
date: '2025-05-29T00:00:00Z',
include_time: false,
},
},
'Percent Complete': 43,
'Status 1': {
value: 'backlog',
updated_on: '2025-05-25T14:52:17.111000Z',
},
'Due Date': {
from_date: {
date: null,
include_time: false,
},
to_date: {
date: '2025-05-30T00:00:00Z',
include_time: false,
},
status_is_completed: false,
status_updated_on: '2025-05-25T14:52:17.110000Z',
},
'Assigned To': ['682c72c82336bf787bb5c7a0'],
Duration: '60.0',
'Time Tracking Log': {
time_track_logs: [],
total_duration: 0,
},
Checklist: {
items: [
{
id: 'f93c6845-5823-4d73-945c-f10038125ae1',
content: {
data: {
type: 'doc',
content: [
{
type: 'paragraph',
attrs: {
textAlign: 'left',
size: 'medium',
},
content: [
{
type: 'text',
text: 'ss',
},
],
},
],
},
html: '<div class="rendered"><p class="align-left" >ss</p></div>',
preview: 'ss',
},
completed: false,
assignee: null,
due_date: null,
completed_at: null,
},
],
total_items: 1,
completed_items: 0,
},
Rating: 5,
Vote: {
total_votes: 0,
votes: [],
},
Tag: ['68333302894412d3ffa5f55a'],
'Record ID': '68332ea07e87b585dca5f3da',
Signature: {
text: '',
image_base64: '',
},
Count: '2',
'Sub-Items': {
count: 0,
items: [],
},
Button: null,
'Color Picker': [
{
value: '#715E5E',
},
],
'IP Address': [
{
address: '192.121.0.0',
country_code: 'gb',
},
],
Rollup: '9.0',
Lookup: [['Phase Gate'], ['Market Research and Design Conceptualization']],
id: '68332ea07e87b585dca5f3da',
application_slug: 'sc4keiie',
application_id: '682c745daf3f33a521fc8c8c',
ranking: {
default: 'aaaaaaaouq',
},
deleted_date: {
date: null,
include_time: false,
},
deleted_by: null,
},
});

View File

@@ -0,0 +1,445 @@
import { TriggerStrategy, createTrigger } from '@activepieces/pieces-framework';
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
import { smartsuiteAuth } from '../auth';
import { smartsuiteCommon, transformRecordFields } from '../common/props';
import {
SMARTSUITE_WEBHOOKS_API_URL,
API_ENDPOINTS,
WEBHOOK_EVENTS,
} from '../common/constants';
import { smartSuiteApiCall, TableStucture } from '../common';
export const updatedRecord = createTrigger({
name: 'updated_record',
displayName: 'Updated Record',
description: 'Triggers when a record is updated in the specified table.',
type: TriggerStrategy.WEBHOOK,
auth: smartsuiteAuth,
props: {
solutionId: smartsuiteCommon.solutionId,
tableId: smartsuiteCommon.tableId,
},
async onEnable(context) {
const { solutionId, tableId } = context.propsValue;
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: `${SMARTSUITE_WEBHOOKS_API_URL}${API_ENDPOINTS.CREATE_WEBHOOK}`,
body: {
webhook: {
filter: {
applications: {
application_ids: [tableId],
},
},
kinds: [WEBHOOK_EVENTS.RECORD_UPDATED],
locator: {
account_id: context.auth.props.accountId, // This will be filled by SmartSuite based on the API key
solution_id: solutionId,
},
notification_status: {
enabled: {
url: context.webhookUrl,
},
},
},
},
headers: {
Authorization: `Token ${context.auth.props.apiKey}`,
'ACCOUNT-ID': context.auth.props.accountId,
},
});
await context.store.put('updated_record', response.body.webhook.webhook_id);
},
async onDisable(context) {
const webhookId = await context.store.get('updated_record');
if (webhookId) {
await httpClient.sendRequest({
method: HttpMethod.POST,
url: `${SMARTSUITE_WEBHOOKS_API_URL}${API_ENDPOINTS.DELETE_WEBHOOK}`,
body: {
webhook_id: webhookId,
},
headers: {
Authorization: `Token ${context.auth.props.apiKey}`,
'ACCOUNT-ID': context.auth.props.accountId,
},
});
}
},
async test(context) {
const { tableId } = context.propsValue;
const response = await smartSuiteApiCall<{ items: Record<string, any>[] }>({
accountId: context.auth.props.accountId,
apiKey: context.auth.props.apiKey,
method: HttpMethod.POST,
resourceUri: `/applications/${tableId}/records/list/`,
query: { limit: '5', offset: '0' },
});
const items = response.items || [];
const tableResponse = await smartSuiteApiCall<{
structure: TableStucture[];
}>({
apiKey: context.auth.props.apiKey,
accountId: context.auth.props.accountId,
method: HttpMethod.GET,
resourceUri: `/applications/${context.propsValue.tableId}`,
});
const tableSchema = tableResponse.structure;
return items.map((item) => transformRecordFields(tableSchema, item));
},
async run(context) {
const webhookPayload = context.payload.body as {
webhookId: string;
locator: {
accountId: string;
solutionId: string;
};
};
let pageToken = (await context.store.get('pageToken')) ?? '';
if (!webhookPayload || !webhookPayload.webhookId || !webhookPayload.locator) {
return [];
}
const events = [];
let hasMore = true;
do {
const response = await httpClient.sendRequest<{
events: { record_event_data: { data: Record<string, any> } }[];
next_page_token: string;
}>({
method: HttpMethod.POST,
url: `${SMARTSUITE_WEBHOOKS_API_URL}${API_ENDPOINTS.LIST_EVENTS}`,
body: {
webhook_id: webhookPayload.webhookId,
page_size: '50',
page_token: pageToken,
},
headers: {
Authorization: `Token ${context.auth.props.apiKey}`,
'ACCOUNT-ID': context.auth.props.accountId,
},
});
pageToken = response.body.next_page_token;
const items = response.body.events ?? [];
events.push(...items);
hasMore = items.length > 0;
} while (hasMore);
await context.store.put('pageToken', pageToken);
const tableResponse = await smartSuiteApiCall<{
structure: TableStucture[];
}>({
apiKey: context.auth.props.apiKey,
accountId: context.auth.props.accountId,
method: HttpMethod.GET,
resourceUri: `/applications/${context.propsValue.tableId}`,
});
const tableSchema = tableResponse.structure;
return events.map((event) => transformRecordFields(tableSchema, event.record_event_data.data));
},
sampleData: {
Title: 'First Record',
Description: {
data: {
type: 'doc',
content: [
{
type: 'paragraph',
attrs: {
textAlign: 'left',
size: 'medium',
},
content: [
{
type: 'text',
text: 'xxzxzxzxzxz',
},
],
},
{
type: 'paragraph',
attrs: {
textAlign: 'left',
size: 'medium',
},
content: [
{
type: 'text',
text: 'xzxzxz',
},
],
},
{
type: 'paragraph',
attrs: {
textAlign: 'left',
size: 'medium',
},
content: [
{
type: 'text',
text: 'xzxz',
},
],
},
],
},
html: '<div class="rendered"><p class="align-left" >xxzxzxzxzxz</p><p class="align-left" >xzxzxz</p><p class="align-left" >xzxz</p></div>',
preview: 'xxzxzxzxzxz\n xzxzxz\n xzxz',
yjsData: '',
},
Status: {
value: 'backlog',
updated_on: '2025-05-25T14:52:17.110000Z',
},
'First Created': {
on: '2025-05-25T14:52:16.977000Z',
by: '682c72c82336bf787bb5c7a0',
},
'Last Updated': {
on: '2025-05-26T10:52:14.987027Z',
by: '682c72c82336bf787bb5c7a0',
},
'Followed by': [],
'Open Comments': 0,
'Auto Number': 1,
'text-field': 'text',
'Text Area': 'area',
Number: '12.0',
'Number Slider': 33,
Percent: '12.0',
Currency: '12',
'Yes / No': true,
'Single Select': '3u0Cl',
'Multiple Select': ['bZfFn', 'LvQIv'],
Date: {
date: '2025-05-30T00:00:00Z',
include_time: false,
},
'Full Name': {
title: '',
first_name: 'john',
middle_name: '',
last_name: 'doe',
sys_root: 'john doe',
},
Email: ['johndoe@gmail.com'],
Phone: [
{
phone_country: 'IN',
phone_number: '',
phone_extension: '',
phone_type: 2,
sys_root: '',
sys_title: '',
},
],
Address: {
location_address: '',
location_address2: '',
location_zip: '',
location_country: '',
location_state: '',
location_city: '',
location_longitude: '72.2',
location_latitude: '21.12',
sys_root: '',
},
Link: ['https://github.com'],
'Files and Images': [
{
handle: 'CeRMEqhySiFboDMkiZlx',
metadata: {
container: 'smart-suite-media',
filename: 'spotify.png',
key: 'PAfWmgwRnOhw6KJygepi_spotify.png',
mimetype: 'image/png',
size: 23422,
},
transform_options: {},
created_on: '2025-05-26T10:47:12.586000Z',
updated_on: '2025-05-26T10:47:12.586000Z',
description: '',
video_conversion_status: '',
video_thumbnail_handle: '',
converted_video_handle: '',
file_type: 'image',
icon: 'image',
},
{
handle: 'GUQyUrvYQrpswR97N8jT',
metadata: {
container: 'smart-suite-media',
filename: 'zagomail.png',
key: 'CSHRsjZRVS6HIFvJEfqQ_zagomail.png',
mimetype: 'image/png',
size: 96995,
},
transform_options: {},
created_on: '2025-05-26T10:49:41.891000Z',
updated_on: '2025-05-26T10:49:41.891000Z',
description: '',
video_conversion_status: '',
video_thumbnail_handle: '',
converted_video_handle: '',
file_type: 'image',
icon: 'image',
},
{
handle: 'eUhDadE9Q3yFz3XLCEgC',
metadata: {
container: 'smart-suite-media',
filename: 'coda.png',
key: 'BrE3gQheS108HgFd1HYT_coda.png',
mimetype: 'image/png',
size: 880,
},
transform_options: {},
created_on: '2025-05-26T10:52:14.981371Z',
updated_on: '2025-05-26T10:52:14.981377Z',
description: '',
video_conversion_status: '',
video_thumbnail_handle: '',
converted_video_handle: '',
file_type: 'image',
icon: 'image',
},
],
SmartDoc: {
data: {},
html: '',
preview: '',
yjsData: 'AAA=',
},
'Link to Tasks': ['682c72c84386b2737cab1bd0', '682c72c84386b2737cab1bcf'],
Time: '00:15:00',
'Date Range': {
from_date: {
date: '2025-05-25T00:00:00Z',
include_time: false,
},
to_date: {
date: '2025-05-29T00:00:00Z',
include_time: false,
},
},
'Percent Complete': 43,
'Status 1': {
value: 'backlog',
updated_on: '2025-05-25T14:52:17.111000Z',
},
'Due Date': {
from_date: {
date: null,
include_time: false,
},
to_date: {
date: '2025-05-30T00:00:00Z',
include_time: false,
},
status_is_completed: false,
status_updated_on: '2025-05-25T14:52:17.110000Z',
},
'Assigned To': ['682c72c82336bf787bb5c7a0'],
Duration: '60.0',
'Time Tracking Log': {
time_track_logs: [],
total_duration: 0,
},
Checklist: {
items: [
{
id: 'f93c6845-5823-4d73-945c-f10038125ae1',
content: {
data: {
type: 'doc',
content: [
{
type: 'paragraph',
attrs: {
textAlign: 'left',
size: 'medium',
},
content: [
{
type: 'text',
text: 'ss',
},
],
},
],
},
html: '<div class="rendered"><p class="align-left" >ss</p></div>',
preview: 'ss',
},
completed: false,
assignee: null,
due_date: null,
completed_at: null,
},
],
total_items: 1,
completed_items: 0,
},
Rating: 5,
Vote: {
total_votes: 0,
votes: [],
},
Tag: ['68333302894412d3ffa5f55a'],
'Record ID': '68332ea07e87b585dca5f3da',
Signature: {
text: '',
image_base64: '',
},
Count: '2',
'Sub-Items': {
count: 0,
items: [],
},
Button: null,
'Color Picker': [
{
value: '#715E5E',
},
],
'IP Address': [
{
address: '192.121.0.0',
country_code: 'gb',
},
],
Rollup: '9.0',
Lookup: [['Phase Gate'], ['Market Research and Design Conceptualization']],
id: '68332ea07e87b585dca5f3da',
application_slug: 'sc4keiie',
application_id: '682c745daf3f33a521fc8c8c',
ranking: {
default: 'aaaaaaaouq',
},
deleted_date: {
date: null,
include_time: false,
},
deleted_by: null,
},
});

View File

@@ -0,0 +1,19 @@
{
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"module": "commonjs",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
}
]
}

View File

@@ -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"]
}