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,50 @@
{
"**Enter your Ninox Personal Access Token (API key).**\n\n---\n\n### How to obtain your API key\n\n1. Visit [ninox.com](https://ninox.com) and log in.\n2. Click the **Start Ninox** button to open the web app.\n3. In the top-right corner, click the **Actions** gear icon.\n4. Select **Integrations** from the drop-down menu.\n5. In the pop-up window, click the **Generate** button.\n6. Copy the API key to your clipboard and paste it here.\n": "**Geben Sie Ihren Ninox Persönlichen Zugangs-Token (API-Schlüssel) ein.**\n\n---\n\n### Wie Sie Ihren API-Schlüssel\n\nerhalten. Besuche [ninox.com](https://ninox.com) und logge dich ein.\n2. Klicke auf den **Starte Ninox** Button um die Web-App zu öffnen.\n3. Klicke in der oberen rechten Ecke auf das Getriebesymbol **Actions**\n4. Wähle **Integrations** aus dem Dropdown-Menü.\n5. Klicken Sie im Popup-Fenster auf die **Erstellen** Schaltfläche.\n6. Kopieren Sie den API-Schlüssel in Ihre Zwischenablage und fügen Sie ihn hier ein.\n",
"Create Record": "Datensatz erstellen",
"Update Record": "Datensatz aktualisieren",
"Delete Record": "Datensatz löschen",
"Upload File": "Datei hochladen",
"Download File from Record": "Datei von Datensatz herunterladen",
"Find Record": "Datensatz finden",
"List Files from Record": "Dateien aus Datensatz auflisten",
"Custom API Call": "Eigener API-Aufruf",
"Creates a new record into a specified table.": "Erstellt einen neuen Datensatz in einer angegebenen Tabelle.",
"Updates fields on an existing record.": "Aktualisiere Felder für einen existierenden Datensatz.",
"Deletes a record from a table.": "Löscht einen Datensatz aus einer Tabelle.",
"Attach a file to a record.": "Eine Datei an einen Datensatz anhängen.",
"Downloads a file attached to a record.": "Lädt eine Datei herunter, die einem Datensatz angehängt ist.",
"Finds records by field values.": "Findet Datensätze nach Feldwerten.",
"List files attached to a specific record (without downloading) for management.": "Listet Dateien auf, die an einen bestimmten Datensatz angehängt sind (ohne Download) für die Verwaltung.",
"Make a custom API call to a specific endpoint": "Einen benutzerdefinierten API-Aufruf an einen bestimmten Endpunkt machen",
"Team ID": "Team-ID",
"Database ID": "Datenbank-ID",
"Table ID": "Table ID",
"Record Fields": "Datensatzfelder",
"Record ID": "Datensatz-ID",
"File": "Datei",
"File ID": "Datei-ID",
"Table Field": "Tabellenfeld",
"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)",
"Select the team containing the database.": "Wählen Sie das Team, das die Datenbank enthält.",
"Select the database containing the table.": "Wählen Sie die Datenbank, die die Tabelle enthält.",
"Select the table": "Tabelle auswählen",
"The file to upload to the record.": "Die Datei, die in den Datensatz hochgeladen wird.",
"The value to search for in the specified field.": "Der zu suchende Wert im angegebenen Feld.",
"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",
"Triggers when a new record is created in a table.": "Wird ausgelöst, wenn ein neuer Datensatz in einer Tabelle erstellt wird."
}

View File

@@ -0,0 +1,50 @@
{
"**Enter your Ninox Personal Access Token (API key).**\n\n---\n\n### How to obtain your API key\n\n1. Visit [ninox.com](https://ninox.com) and log in.\n2. Click the **Start Ninox** button to open the web app.\n3. In the top-right corner, click the **Actions** gear icon.\n4. Select **Integrations** from the drop-down menu.\n5. In the pop-up window, click the **Generate** button.\n6. Copy the API key to your clipboard and paste it here.\n": "**Introduce tu token de acceso personal (Ninox).**\n\n---\n\n### Cómo obtener tu clave API\n\n1. Visita [ninox.com](https://ninox.com) e inicia sesión.\n2. Haz clic en el botón **Iniciar Ninox** para abrir la aplicación web.\n3. En la esquina superior derecha, haz clic en el icono de engranaje **Acciones**.\n4. Selecciona **Integraciones** en el menú desplegable.\n5. En la ventana emergente, haz clic en el botón **Generar**.\n6. Copia la clave API en tu portapapeles y pégala aquí.\n",
"Create Record": "Crear registro",
"Update Record": "Actualizar registro",
"Delete Record": "Eliminar registro",
"Upload File": "Subir archivo",
"Download File from Record": "Descargar archivo desde el registro",
"Find Record": "Buscar registro",
"List Files from Record": "Lista de archivos desde el registro",
"Custom API Call": "Llamada API personalizada",
"Creates a new record into a specified table.": "Crea un nuevo registro en una tabla especificada.",
"Updates fields on an existing record.": "Actualiza campos en un registro existente.",
"Deletes a record from a table.": "Elimina un registro de una tabla.",
"Attach a file to a record.": "Adjuntar un archivo a un registro.",
"Downloads a file attached to a record.": "Descargue un archivo adjunto a un registro.",
"Finds records by field values.": "Encuentra registros por valores de campo.",
"List files attached to a specific record (without downloading) for management.": "Listar archivos adjuntos a un registro específico (sin descargar) para su gestión.",
"Make a custom API call to a specific endpoint": "Hacer una llamada API personalizada a un extremo específico",
"Team ID": "ID de equipo",
"Database ID": "ID de base de datos",
"Table ID": "Table ID",
"Record Fields": "Campos de registro",
"Record ID": "ID de registro",
"File": "Archivo",
"File ID": "ID de archivo",
"Table Field": "Campo de tabla",
"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)",
"Select the team containing the database.": "Seleccione el equipo que contiene la base de datos.",
"Select the database containing the table.": "Seleccione la base de datos que contiene la tabla.",
"Select the table": "Seleccione la tabla",
"The file to upload to the record.": "El archivo a subir al registro.",
"The value to search for in the specified field.": "El valor por el que buscar en el campo especificado.",
"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",
"Triggers when a new record is created in a table.": "Se activa cuando se crea un nuevo registro en una tabla."
}

View File

@@ -0,0 +1,50 @@
{
"**Enter your Ninox Personal Access Token (API key).**\n\n---\n\n### How to obtain your API key\n\n1. Visit [ninox.com](https://ninox.com) and log in.\n2. Click the **Start Ninox** button to open the web app.\n3. In the top-right corner, click the **Actions** gear icon.\n4. Select **Integrations** from the drop-down menu.\n5. In the pop-up window, click the **Generate** button.\n6. Copy the API key to your clipboard and paste it here.\n": "**Entrez votre jeton d'accès personnel Ninox (clé API).**\n\n---\n\n### Comment obtenir votre clé API\n\n1. Visitez [ninox.com](https://ninox.com) et connectez-vous.\n2. Cliquez sur le bouton **Démarrer Ninox** pour ouvrir l'application web.\n3. Dans le coin supérieur droit, cliquez sur l'icône d'engrenage **Actions**.\n4. Sélectionnez **Intégrations** dans le menu déroulant.\n5. Dans la fenêtre pop-up, cliquez sur le bouton **Générer**.\n6. Copiez la clé API dans votre presse-papiers et collez-la ici.\n",
"Create Record": "Créer un enregistrement",
"Update Record": "Mettre à jour l'enregistrement",
"Delete Record": "Supprimer l'enregistrement",
"Upload File": "Charger un fichier",
"Download File from Record": "Télécharger le fichier depuis l'enregistrement",
"Find Record": "Rechercher un enregistrement",
"List Files from Record": "Lister les fichiers de l'enregistrement",
"Custom API Call": "Appel API personnalisé",
"Creates a new record into a specified table.": "Crée un nouvel enregistrement dans une table spécifiée.",
"Updates fields on an existing record.": "Met à jour les champs d'un enregistrement existant.",
"Deletes a record from a table.": "Supprime un enregistrement d'une table.",
"Attach a file to a record.": "Joindre un fichier à un enregistrement.",
"Downloads a file attached to a record.": "Télécharge un fichier attaché à un enregistrement.",
"Finds records by field values.": "Trouve les enregistrements par valeur de champ.",
"List files attached to a specific record (without downloading) for management.": "Liste les fichiers attachés à un enregistrement spécifique (sans téléchargement) pour la gestion.",
"Make a custom API call to a specific endpoint": "Passez un appel API personnalisé à un point de terminaison spécifique",
"Team ID": "ID d'équipe",
"Database ID": "ID de la base de données",
"Table ID": "Table ID",
"Record Fields": "Champs d'enregistrement",
"Record ID": "ID de l'enregistrement",
"File": "Ficher",
"File ID": "ID du fichier",
"Table Field": "Champ de table",
"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'attente (en secondes)",
"Select the team containing the database.": "Sélectionnez l'équipe contenant la base de données.",
"Select the database containing the table.": "Sélectionnez la base de données contenant la table.",
"Select the table": "Sélectionnez la table",
"The file to upload to the record.": "Le fichier à télécharger dans l'enregistrement.",
"The value to search for in the specified field.": "La valeur à rechercher dans le champ spécifié.",
"Authorization headers are injected automatically from your connection.": "Les en-têtes d'autorisation sont injectés automatiquement à partir de votre connexion.",
"Enable for files like PDFs, images, etc..": "Activer pour les fichiers comme les PDFs, les images, etc.",
"GET": "OBTENIR",
"POST": "POSTER",
"PATCH": "PATCH",
"PUT": "EFFACER",
"DELETE": "SUPPRIMER",
"HEAD": "TÊTE",
"New Record": "Nouvel enregistrement",
"Triggers when a new record is created in a table.": "Déclenche lorsqu'un nouvel enregistrement est créé dans une table."
}

View File

@@ -0,0 +1,50 @@
{
"**Enter your Ninox Personal Access Token (API key).**\n\n---\n\n### How to obtain your API key\n\n1. Visit [ninox.com](https://ninox.com) and log in.\n2. Click the **Start Ninox** button to open the web app.\n3. In the top-right corner, click the **Actions** gear icon.\n4. Select **Integrations** from the drop-down menu.\n5. In the pop-up window, click the **Generate** button.\n6. Copy the API key to your clipboard and paste it here.\n": "**Enter your Ninox Personal Access Token (API key).**\n\n---\n\n### How to obtain your API key\n\n1. Visit [ninox.com](https://ninox.com) and log in.\n2. Click the **Start Ninox** button to open the web app.\n3. In the top-right corner, click the **Actions** gear icon.\n4. Select **Integrations** from the drop-down menu.\n5. In the pop-up window, click the **Generate** button.\n6. Copy the API key to your clipboard and paste it here.\n",
"Create Record": "レコードを作成",
"Update Record": "更新記録",
"Delete Record": "レコードを削除",
"Upload File": "ファイルをアップロード",
"Download File from Record": "レコードからファイルをダウンロード",
"Find Record": "レコードを検索",
"List Files from Record": "レコードからのファイルの一覧",
"Custom API Call": "カスタムAPI通話",
"Creates a new record into a specified table.": "指定したテーブルに新しいレコードを作成します。",
"Updates fields on an existing record.": "既存のレコードのフィールドを更新します。",
"Deletes a record from a table.": "テーブルからレコードを削除します。",
"Attach a file to a record.": "ファイルをレコードに添付します。",
"Downloads a file attached to a record.": "レコードに添付されたファイルをダウンロードします。",
"Finds records by field values.": "項目値でレコードを検索します。",
"List files attached to a specific record (without downloading) for management.": "管理用に特定のレコードに添付されたファイルを一覧表示します。",
"Make a custom API call to a specific endpoint": "特定のエンドポイントへのカスタム API コールを実行します。",
"Team ID": "チームID",
"Database ID": "データベースID",
"Table ID": "Table ID",
"Record Fields": "レコードフィールド",
"Record ID": "レコードID",
"File": "ファイル",
"File ID": "ファイルID",
"Table Field": "テーブルフィールド",
"Search Value": "検索値",
"Method": "方法",
"Headers": "ヘッダー",
"Query Parameters": "クエリパラメータ",
"Body": "本文",
"Response is Binary ?": "応答はバイナリですか?",
"No Error on Failure": "失敗時にエラーはありません",
"Timeout (in seconds)": "タイムアウト(秒)",
"Select the team containing the database.": "データベースを含むチームを選択します。",
"Select the database containing the table.": "表を含むデータベースを選択します。",
"Select the table": "テーブルを選択",
"The file to upload to the record.": "レコードにアップロードするファイル",
"The value to search for in the specified field.": "指定したフィールドで検索する値。",
"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": "新しいレコード",
"Triggers when a new record is created in a table.": "テーブルに新しいレコードが作成されたときにトリガーされます。"
}

View File

@@ -0,0 +1,50 @@
{
"**Enter your Ninox Personal Access Token (API key).**\n\n---\n\n### How to obtain your API key\n\n1. Visit [ninox.com](https://ninox.com) and log in.\n2. Click the **Start Ninox** button to open the web app.\n3. In the top-right corner, click the **Actions** gear icon.\n4. Select **Integrations** from the drop-down menu.\n5. In the pop-up window, click the **Generate** button.\n6. Copy the API key to your clipboard and paste it here.\n": "**Voer je Ninox persoonlijke toegangstoken (API-sleutel).**\n\n---\n\n### Hoe je je API-sleutel\n\n1 te verkrijgen. Bezoek [ninox.com](https://ninox.com) en log in.\n2. Klik op de **Start Ninox** knop om de webapp te openen.\n3. Klik in de rechterbovenhoek op het **Acties** tandwielpictogram.\n4. Selecteer **Integraties** in het drop-down menu.\n5. In het pop-upvenster, klik op de knop **genereren**.\n6. Kopieer de API-sleutel naar het klembord en plak deze hier.\n",
"Create Record": "Record Maken",
"Update Record": "Update Record",
"Delete Record": "Record verwijderen",
"Upload File": "Bestand uploaden",
"Download File from Record": "Bestand downloaden uit Record",
"Find Record": "Vind Record",
"List Files from Record": "Lijst van bestanden uit record",
"Custom API Call": "Custom API Call",
"Creates a new record into a specified table.": "Maakt een nieuwe record in een opgegeven tabel.",
"Updates fields on an existing record.": "Velden van een bestaand record bijwerken.",
"Deletes a record from a table.": "Verwijdert een record van een tabel.",
"Attach a file to a record.": "Voeg een bestand toe aan een record.",
"Downloads a file attached to a record.": "Downloads een bestand als een record.",
"Finds records by field values.": "Gevonden records per veld waarden.",
"List files attached to a specific record (without downloading) for management.": "Lijst van bestanden die zijn gekoppeld aan een specifiek record (zonder download) voor beheer.",
"Make a custom API call to a specific endpoint": "Maak een aangepaste API call naar een specifiek eindpunt",
"Team ID": "Team ID",
"Database ID": "Database ID",
"Table ID": "Table ID",
"Record Fields": "Record velden",
"Record ID": "Record ID",
"File": "Bestand",
"File ID": "Bestand ID",
"Table Field": "Tabel veld",
"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)",
"Select the team containing the database.": "Selecteer het team dat de database bevat.",
"Select the database containing the table.": "Selecteer de database met de tabel.",
"Select the table": "Selecteer de tabel",
"The file to upload to the record.": "Het bestand om naar de record te uploaden.",
"The value to search for in the specified field.": "De waarde waarnaar gezocht moet worden in het opgegeven veld.",
"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",
"Triggers when a new record is created in a table.": "Triggert wanneer een nieuwe record wordt aangemaakt in een tabel."
}

View File

@@ -0,0 +1,50 @@
{
"**Enter your Ninox Personal Access Token (API key).**\n\n---\n\n### How to obtain your API key\n\n1. Visit [ninox.com](https://ninox.com) and log in.\n2. Click the **Start Ninox** button to open the web app.\n3. In the top-right corner, click the **Actions** gear icon.\n4. Select **Integrations** from the drop-down menu.\n5. In the pop-up window, click the **Generate** button.\n6. Copy the API key to your clipboard and paste it here.\n": "**Digite sua Token de Acesso Pessoal Ninox (chave de API).**\n\n---\n\n### Como obter sua chave de API\n\n1. Visite [ninox.com](https://ninox.com) e entre nele.\n2. Clique no botão **Iniciar Ninox** para abrir o aplicativo web.\n3. No canto superior direito, clique no ícone de engrenagem **Ações**.\n4. Selecione **integrações** no menu suspenso.\n5. Na janela pop-up, clique no botão **Gerar**.\n6. Copie a chave da API para a sua área de transferência e cole-o aqui.\n",
"Create Record": "Criar Registro",
"Update Record": "Atualizar Registro",
"Delete Record": "Excluir registro",
"Upload File": "Enviar Arquivo",
"Download File from Record": "Baixar Arquivo de Gravação",
"Find Record": "Localizar Registro",
"List Files from Record": "Listar Arquivos do Registro",
"Custom API Call": "Chamada de API personalizada",
"Creates a new record into a specified table.": "Cria um novo registro em uma tabela especificada.",
"Updates fields on an existing record.": "Atualiza campos em um registro existente.",
"Deletes a record from a table.": "Exclui um registro de uma tabela.",
"Attach a file to a record.": "Anexar um arquivo a um registro.",
"Downloads a file attached to a record.": "Descarrega um arquivo anexado a um registro.",
"Finds records by field values.": "Localiza registros por valores de campo.",
"List files attached to a specific record (without downloading) for management.": "Lista de arquivos anexados a um registro específico (sem baixar) para o gerenciamento.",
"Make a custom API call to a specific endpoint": "Faça uma chamada de API personalizada para um ponto de extremidade específico",
"Team ID": "ID da Equipe",
"Database ID": "ID do banco",
"Table ID": "Table ID",
"Record Fields": "Recorde Campos",
"Record ID": "ID do Registro",
"File": "Arquivo",
"File ID": "ID do arquivo",
"Table Field": "Campo da tabela",
"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)",
"Select the team containing the database.": "Selecionar a equipe que contém o banco de dados.",
"Select the database containing the table.": "Selecione o banco de dados que contém a tabela.",
"Select the table": "Selecione a tabela",
"The file to upload to the record.": "O arquivo a ser enviado para o registro.",
"The value to search for in the specified field.": "O valor a procurar no campo especificado.",
"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",
"Triggers when a new record is created in a table.": "Dispara quando um novo registro é criado em uma tabela."
}

View File

@@ -0,0 +1,49 @@
{
"Ninox": "Ninox",
"**Enter your Ninox Personal Access Token (API key).**\n\n---\n\n### How to obtain your API key\n\n1. Visit [ninox.com](https://ninox.com) and log in.\n2. Click the **Start Ninox** button to open the web app.\n3. In the top-right corner, click the **Actions** gear icon.\n4. Select **Integrations** from the drop-down menu.\n5. In the pop-up window, click the **Generate** button.\n6. Copy the API key to your clipboard and paste it here.\n": "**Введите ваш Ninox персональный токен доступа (API ключ).**\n\n---\n\n### Как получить ваш API ключ\n\n1. Посетите [ninox.com](https://ninox.com) и войдите в систему.\n2. Нажмите кнопку **Start Ninox**, чтобы открыть веб-приложение.\n3. В правом верхнем углу нажмите на значок шестеренки **Действия**.\n4. Выберите **Интеграции** из выпадающего меню.\n5. В всплывающем окне нажмите кнопку **Создать**.\n6. Скопируйте ключ API в буфер обмена и вставьте его здесь.\n",
"Create Record": "Создать запись",
"Update Record": "Обновить запись",
"Delete Record": "Удалить запись",
"Upload File": "Загрузить файл",
"Download File from Record": "Загрузить файл из записи",
"Find Record": "Найти запись",
"List Files from Record": "Список файлов из записи",
"Custom API Call": "Пользовательский вызов API",
"Creates a new record into a specified table.": "Создает новую запись в указанной таблице.",
"Updates fields on an existing record.": "Обновляет поля для существующей записи.",
"Deletes a record from a table.": "Удаляет запись из таблицы.",
"Attach a file to a record.": "Прикрепить файл к записи.",
"Downloads a file attached to a record.": "Загружает файл, прикрепленный к записи.",
"Finds records by field values.": "Поиск записей по значениям поля.",
"List files attached to a specific record (without downloading) for management.": "Список файлов, прикрепленных к конкретной записи (без загрузки) для управления.",
"Make a custom API call to a specific endpoint": "Сделать пользовательский API вызов к определенной конечной точке",
"Team ID": "ID команды",
"Database ID": "ID базы данных",
"Table ID": "Table ID",
"Record Fields": "Поля записи",
"Record ID": "ID записи",
"File": "Файл",
"File ID": "ID файла",
"Table Field": "Поле таблицы",
"Search Value": "Поисковое значение",
"Method": "Метод",
"Headers": "Заголовки",
"Query Parameters": "Параметры запроса",
"Body": "Тело",
"No Error on Failure": "Нет ошибок при ошибке",
"Timeout (in seconds)": "Таймаут (в секундах)",
"Select the team containing the database.": "Выберите команду, содержащую базу данных.",
"Select the database containing the table.": "Выберите базу данных, содержащую таблицу.",
"Select the table": "Выберите таблицу",
"The file to upload to the record.": "Файл для загрузки в запись.",
"The value to search for in the specified field.": "Значение для поиска в указанном поле.",
"Authorization headers are injected automatically from your connection.": "Заголовки авторизации включаются автоматически из вашего соединения.",
"GET": "ПОЛУЧИТЬ",
"POST": "ПОСТ",
"PATCH": "ПАТЧ",
"PUT": "ПОКУПИТЬ",
"DELETE": "УДАЛИТЬ",
"HEAD": "HEAD",
"New Record": "Новая запись",
"Triggers when a new record is created in a table.": "Триггеры при создании новой записи в таблице."
}

View File

@@ -0,0 +1,50 @@
{
"**Enter your Ninox Personal Access Token (API key).**\n\n---\n\n### How to obtain your API key\n\n1. Visit [ninox.com](https://ninox.com) and log in.\n2. Click the **Start Ninox** button to open the web app.\n3. In the top-right corner, click the **Actions** gear icon.\n4. Select **Integrations** from the drop-down menu.\n5. In the pop-up window, click the **Generate** button.\n6. Copy the API key to your clipboard and paste it here.\n": "**Enter your Ninox Personal Access Token (API key).**\n\n---\n\n### How to obtain your API key\n\n1. Visit [ninox.com](https://ninox.com) and log in.\n2. Click the **Start Ninox** button to open the web app.\n3. In the top-right corner, click the **Actions** gear icon.\n4. Select **Integrations** from the drop-down menu.\n5. In the pop-up window, click the **Generate** button.\n6. Copy the API key to your clipboard and paste it here.\n",
"Create Record": "Create Record",
"Update Record": "Update Record",
"Delete Record": "Delete Record",
"Upload File": "Upload File",
"Download File from Record": "Download File from Record",
"Find Record": "Find Record",
"List Files from Record": "List Files from Record",
"Custom API Call": "Custom API Call",
"Creates a new record into a specified table.": "Creates a new record into a specified table.",
"Updates fields on an existing record.": "Updates fields on an existing record.",
"Deletes a record from a table.": "Deletes a record from a table.",
"Attach a file to a record.": "Attach a file to a record.",
"Downloads a file attached to a record.": "Downloads a file attached to a record.",
"Finds records by field values.": "Finds records by field values.",
"List files attached to a specific record (without downloading) for management.": "List files attached to a specific record (without downloading) for management.",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Team ID": "Team ID",
"Database ID": "Database ID",
"Table ID": "Table ID",
"Record Fields": "Record Fields",
"Record ID": "Record ID",
"File": "File",
"File ID": "File ID",
"Table Field": "Table Field",
"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)",
"Select the team containing the database.": "Select the team containing the database.",
"Select the database containing the table.": "Select the database containing the table.",
"Select the table": "Select the table",
"The file to upload to the record.": "The file to upload to the record.",
"The value to search for in the specified field.": "The value to search for in the specified field.",
"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",
"Triggers when a new record is created in a table.": "Triggers when a new record is created in a table."
}

View File

@@ -0,0 +1,49 @@
{
"Ninox": "Ninox",
"**Enter your Ninox Personal Access Token (API key).**\n\n---\n\n### How to obtain your API key\n\n1. Visit [ninox.com](https://ninox.com) and log in.\n2. Click the **Start Ninox** button to open the web app.\n3. In the top-right corner, click the **Actions** gear icon.\n4. Select **Integrations** from the drop-down menu.\n5. In the pop-up window, click the **Generate** button.\n6. Copy the API key to your clipboard and paste it here.\n": "**Enter your Ninox Personal Access Token (API key).**\n\n---\n\n### How to obtain your API key\n\n1. Visit [ninox.com](https://ninox.com) and log in.\n2. Click the **Start Ninox** button to open the web app.\n3. In the top-right corner, click the **Actions** gear icon.\n4. Select **Integrations** from the drop-down menu.\n5. In the pop-up window, click the **Generate** button.\n6. Copy the API key to your clipboard and paste it here.\n",
"Create Record": "Create Record",
"Update Record": "Update Record",
"Delete Record": "Delete Record",
"Upload File": "Upload File",
"Download File from Record": "Download File from Record",
"Find Record": "Find Record",
"List Files from Record": "List Files from Record",
"Custom API Call": "Custom API Call",
"Creates a new record into a specified table.": "Creates a new record into a specified table.",
"Updates fields on an existing record.": "Updates fields on an existing record.",
"Deletes a record from a table.": "Deletes a record from a table.",
"Attach a file to a record.": "Attach a file to a record.",
"Downloads a file attached to a record.": "Downloads a file attached to a record.",
"Finds records by field values.": "Finds records by field values.",
"List files attached to a specific record (without downloading) for management.": "List files attached to a specific record (without downloading) for management.",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Team ID": "Team ID",
"Database ID": "Database ID",
"Table ID": "Table ID",
"Record Fields": "Record Fields",
"Record ID": "Record ID",
"File": "File",
"File ID": "File ID",
"Table Field": "Table Field",
"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)",
"Select the team containing the database.": "Select the team containing the database.",
"Select the database containing the table.": "Select the database containing the table.",
"Select the table": "Select the table",
"The file to upload to the record.": "The file to upload to the record.",
"The value to search for in the specified field.": "The value to search for in the specified field.",
"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",
"Triggers when a new record is created in a table.": "Triggers when a new record is created in a table."
}

View File

@@ -0,0 +1,50 @@
{
"**Enter your Ninox Personal Access Token (API key).**\n\n---\n\n### How to obtain your API key\n\n1. Visit [ninox.com](https://ninox.com) and log in.\n2. Click the **Start Ninox** button to open the web app.\n3. In the top-right corner, click the **Actions** gear icon.\n4. Select **Integrations** from the drop-down menu.\n5. In the pop-up window, click the **Generate** button.\n6. Copy the API key to your clipboard and paste it here.\n": "**Enter your Ninox Personal Access Token (API key).**\n\n---\n\n### How to obtain your API key\n\n1. Visit [ninox.com](https://ninox.com) and log in.\n2. Click the **Start Ninox** button to open the web app.\n3. In the top-right corner, click the **Actions** gear icon.\n4. Select **Integrations** from the drop-down menu.\n5. In the pop-up window, click the **Generate** button.\n6. Copy the API key to your clipboard and paste it here.\n",
"Create Record": "Create Record",
"Update Record": "Update Record",
"Delete Record": "Delete Record",
"Upload File": "Upload File",
"Download File from Record": "Download File from Record",
"Find Record": "Find Record",
"List Files from Record": "List Files from Record",
"Custom API Call": "自定义 API 呼叫",
"Creates a new record into a specified table.": "Creates a new record into a specified table.",
"Updates fields on an existing record.": "Updates fields on an existing record.",
"Deletes a record from a table.": "Deletes a record from a table.",
"Attach a file to a record.": "Attach a file to a record.",
"Downloads a file attached to a record.": "Downloads a file attached to a record.",
"Finds records by field values.": "Finds records by field values.",
"List files attached to a specific record (without downloading) for management.": "List files attached to a specific record (without downloading) for management.",
"Make a custom API call to a specific endpoint": "将一个自定义 API 调用到一个特定的终点",
"Team ID": "Team ID",
"Database ID": "Database ID",
"Table ID": "Table ID",
"Record Fields": "Record Fields",
"Record ID": "Record ID",
"File": "文件",
"File ID": "File ID",
"Table Field": "Table Field",
"Search Value": "搜索值",
"Method": "方法",
"Headers": "信头",
"Query Parameters": "查询参数",
"Body": "正文内容",
"Response is Binary ?": "Response is Binary ?",
"No Error on Failure": "失败时没有错误",
"Timeout (in seconds)": "超时(秒)",
"Select the team containing the database.": "Select the team containing the database.",
"Select the database containing the table.": "Select the database containing the table.",
"Select the table": "Select the table",
"The file to upload to the record.": "The file to upload to the record.",
"The value to search for in the specified field.": "The value to search for in the specified field.",
"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",
"Triggers when a new record is created in a table.": "Triggers when a new record is created in a table."
}

View File

@@ -0,0 +1,39 @@
import { createPiece } from '@activepieces/pieces-framework';
import { NinoxAuth } from './lib/common/auth';
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 { downloadFileFromRecord } from './lib/actions/download-file-from-record-';
import { findRecord } from './lib/actions/find-record';
import { listFilesFromRecord } from './lib/actions/list-files-from-record';
import { newRecord } from './lib/triggers/new-record';
import { createCustomApiCallAction } from '@activepieces/pieces-common';
import { BASE_URL } from './lib/common/client';
export const ninox = createPiece({
displayName: 'Ninox',
auth: NinoxAuth,
minimumSupportedRelease: '0.36.1',
logoUrl: 'https://cdn.activepieces.com/pieces/ninox.png',
authors: ['Sanket6652'],
actions: [
createRecord,
updateRecord,
deleteRecord,
uploadFile,
downloadFileFromRecord,
findRecord,
listFilesFromRecord,
createCustomApiCallAction({
auth: NinoxAuth,
baseUrl: () => BASE_URL,
authMapping: async (auth) => {
return {
Authorization: `Bearer ${auth}`,
};
},
}),
],
triggers: [newRecord],
});

View File

@@ -0,0 +1,49 @@
import { createAction } from '@activepieces/pieces-framework';
import { NinoxAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
import {
teamidDropdown,
databaseIdDropdown,
tableIdDropdown,
tableFields,
} from '../common/props';
export const createRecord = createAction({
auth: NinoxAuth,
name: 'createRecord',
displayName: 'Create Record',
description: 'Creates a new record into a specified table.',
props: {
teamid: teamidDropdown,
dbid: databaseIdDropdown,
tid: tableIdDropdown,
fields: tableFields,
},
async run({ auth, propsValue }) {
const { teamid, dbid, tid, fields } = propsValue;
const path = `/teams/${teamid}/databases/${dbid}/tables/${tid}/records`;
// Filter out empty values and prepare the record data
const recordData: Record<string, any> = {};
Object.keys(fields).forEach((key) => {
if (fields[key] !== undefined && fields[key] !== null && fields[key] !== '') {
recordData[key] = fields[key];
}
});
const requestBody = {
_upsert: true,
fields: recordData,
};
try {
const response = await makeRequest(auth.secret_text, HttpMethod.POST, path, requestBody);
return response;
} catch (error) {
throw new Error(`Failed to create record: ${error}`);
}
},
});

View File

@@ -0,0 +1,36 @@
import { createAction } from '@activepieces/pieces-framework';
import { NinoxAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
import {
teamidDropdown,
databaseIdDropdown,
tableIdDropdown,
recordIdDropdown,
} from '../common/props';
export const deleteRecord = createAction({
auth: NinoxAuth,
name: 'deleteRecord',
displayName: 'Delete Record',
description: 'Deletes a record from a table.',
props: {
teamid: teamidDropdown,
dbid: databaseIdDropdown,
tid: tableIdDropdown,
recordId: recordIdDropdown,
},
async run({ auth, propsValue }) {
const { teamid, dbid, tid, recordId } = propsValue;
const path = `/teams/${teamid}/databases/${dbid}/tables/${tid}/records/${recordId}`;
try {
await makeRequest(auth.secret_text, HttpMethod.DELETE, path);
return { success: true, message: 'Record deleted successfully' };
} catch (error) {
throw new Error(`Failed to delete record: ${error}`);
}
},
});

View File

@@ -0,0 +1,58 @@
import { createAction } from '@activepieces/pieces-framework';
import { NinoxAuth } from '../common/auth';
import { BASE_URL, makeRequest } from '../common/client';
import { AuthenticationType, httpClient, HttpMethod } from '@activepieces/pieces-common';
import {
teamidDropdown,
databaseIdDropdown,
tableIdDropdown,
recordIdDropdown,
filenameDropdown,
} from '../common/props';
export const downloadFileFromRecord = createAction({
auth: NinoxAuth,
name: 'downloadFileFromRecord',
displayName: 'Download File from Record',
description: 'Downloads a file attached to a record.',
props: {
teamid: teamidDropdown,
dbid: databaseIdDropdown,
tid: tableIdDropdown,
rid: recordIdDropdown,
file: filenameDropdown,
},
async run({ auth, propsValue, files }) {
const { teamid, dbid, tid, rid, file } = propsValue;
const path = `/teams/${teamid}/databases/${dbid}/tables/${tid}/records/${rid}/files/${file}`;
try {
const fileMetadata = await makeRequest<{ name: string }>(
auth.secret_text,
HttpMethod.GET,
`${path}/metadata`,
);
const response = await httpClient.sendRequest({
method: HttpMethod.GET,
url: BASE_URL + path,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.secret_text,
},
responseType: 'arraybuffer',
});
return {
...fileMetadata,
file: await files.write({
data: Buffer.from(response.body),
fileName: fileMetadata.name,
}),
};
} catch (error) {
throw new Error(`Failed to download file: ${error}`);
}
},
});

View File

@@ -0,0 +1,48 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { NinoxAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
import {
teamidDropdown,
databaseIdDropdown,
tableIdDropdown,
tablefieldDropdown,
} from '../common/props';
export const findRecord = createAction({
auth: NinoxAuth,
name: 'findRecord',
displayName: 'Find Record',
description: 'Finds records by field values.',
props: {
teamid: teamidDropdown,
dbid: databaseIdDropdown,
tid: tableIdDropdown,
searchField: tablefieldDropdown,
searchValue: Property.ShortText({
displayName: 'Search Value',
description: 'The value to search for in the specified field.',
required: true,
}),
},
async run({ auth, propsValue }) {
const { teamid, dbid, tid, searchField, searchValue } = propsValue;
const path = `/teams/${teamid}/databases/${dbid}/tables/${tid}/record`;
try {
const response = await makeRequest(auth.secret_text, HttpMethod.POST, path, {
filters: { [searchField as string]: searchValue },
});
const found = Array.isArray(response) && response.length === 0 ? false : true;
return {
found,
data: found ? response : {},
};
} catch (error) {
throw new Error(`Failed to find records: ${error}`);
}
},
});

View File

@@ -0,0 +1,45 @@
import { createAction } from '@activepieces/pieces-framework';
import { NinoxAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
import { teamidDropdown, databaseIdDropdown, tableIdDropdown, recordIdDropdown } from '../common/props';
export const listFilesFromRecord = createAction({
auth: NinoxAuth,
name: 'listFilesFromRecord',
displayName: 'List Files from Record',
description: 'List files attached to a specific record (without downloading) for management.',
props: {
teamid: teamidDropdown,
dbid: databaseIdDropdown,
tid: tableIdDropdown,
rid: recordIdDropdown,
},
async run({ auth, propsValue }) {
const { teamid, dbid, tid, rid } = propsValue;
const path = `/teams/${teamid}/databases/${dbid}/tables/${tid}/records/${rid}/files`;
try {
const response = await makeRequest<any>(
auth.secret_text,
HttpMethod.GET,
path
);
// Process the file metadata
const files = Array.isArray(response) ? response : [];
return {
success: true,
message: `Found ${files.length} file(s) attached to the record`,
files: files,
totalFiles: files.length,
recordId: rid,
};
} catch (error) {
throw new Error(`Failed to list files from record: ${error}`);
}
},
});

View File

@@ -0,0 +1,48 @@
import { createAction } from '@activepieces/pieces-framework';
import { NinoxAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
import {
teamidDropdown,
databaseIdDropdown,
tableIdDropdown,
recordIdDropdown,
tableFields,
} from '../common/props';
export const updateRecord = createAction({
auth: NinoxAuth,
name: 'updateRecord',
displayName: 'Update Record',
description: 'Updates fields on an existing record.',
props: {
teamid: teamidDropdown,
dbid: databaseIdDropdown,
tid: tableIdDropdown,
rid: recordIdDropdown,
fields: tableFields,
},
async run({ auth, propsValue }) {
const { teamid, dbid, tid, rid, fields } = propsValue;
const path = `/teams/${teamid}/databases/${dbid}/tables/${tid}/records/${rid}`;
// Filter out empty values and prepare the record data
const recordData: Record<string, any> = {};
Object.keys(fields).forEach((key) => {
if (fields[key] !== undefined && fields[key] !== null && fields[key] !== '') {
recordData[key] = fields[key];
}
});
try {
const response = await makeRequest(auth.secret_text, HttpMethod.PUT, path, {
fields: recordData,
});
return response;
} catch (error) {
throw new Error(`Failed to update record: ${error}`);
}
},
});

View File

@@ -0,0 +1,60 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { NinoxAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
import {
teamidDropdown,
databaseIdDropdown,
tableIdDropdown,
recordIdDropdown,
} from '../common/props';
import mime from 'mime-types';
export const uploadFile = createAction({
auth: NinoxAuth,
name: 'uploadFile',
displayName: 'Upload File',
description: 'Attach a file to a record.',
props: {
teamid: teamidDropdown,
dbid: databaseIdDropdown,
tid: tableIdDropdown,
rid: recordIdDropdown,
file: Property.File({
displayName: 'File',
description: 'The file to upload to the record.',
required: true,
}),
},
async run({ auth, propsValue }) {
const { teamid, dbid, tid, rid, file } = propsValue;
const path = `/teams/${teamid}/databases/${dbid}/tables/${tid}/records/${rid}/files`;
try {
// Determine MIME type from file extension
const mimeType = file.extension
? mime.lookup(file.extension) || 'application/octet-stream'
: 'application/octet-stream';
// Create FormData for multipart/form-data upload
const formData = new FormData();
const blob = new Blob([file.data as unknown as ArrayBuffer], { type: mimeType });
formData.append('file', blob, file.filename);
const response = await makeRequest(
auth.secret_text,
HttpMethod.POST,
path,
formData,
'multipart/form-data',
);
return {
success: true,
response: response,
};
} catch (error) {
throw new Error(`Failed to upload file: ${error}`);
}
},
});

View File

@@ -0,0 +1,43 @@
import { PieceAuth } from "@activepieces/pieces-framework";
import { makeRequest } from "./client";
import { HttpMethod } from "@activepieces/pieces-common";
export const NinoxAuth = PieceAuth.SecretText({
displayName: 'Ninox API Key',
description: `**Enter your Ninox Personal Access Token (API key).**
---
### How to obtain your API key
1. Visit [ninox.com](https://ninox.com) and log in.
2. Click the **Start Ninox** button to open the web app.
3. In the top-right corner, click the **Actions** gear icon.
4. Select **Integrations** from the drop-down menu.
5. In the pop-up window, click the **Generate** button.
6. Copy the API key to your clipboard and paste it here.
`,
required: true,
validate: async ({ auth }) => {
if (auth) {
try {
await makeRequest(auth as string, HttpMethod.GET, '/teams', {});
return {
valid: true,
}
} catch (error) {
return {
valid: false,
error: 'Invalid Api Key'
}
}
}
return {
valid: false,
error: 'Invalid Api Key'
}
},
})

View File

@@ -0,0 +1,40 @@
import { HttpMethod, QueryParams, httpClient } from '@activepieces/pieces-common';
export const BASE_URL = `https://api.ninox.com/v1`;
export async function makeRequest<T>(
api_key: string,
method: HttpMethod,
path: string,
body?: unknown,
headers?: Record<string, string> | string,
) {
try {
let mergedHeaders: Record<string, string> = {
'Authorization': `Bearer ${api_key}`,
'Content-Type': 'application/json',
};
if (typeof headers === 'string') {
mergedHeaders['Content-Type'] = headers;
} else if (typeof headers === 'object' && headers !== null) {
mergedHeaders = {
...mergedHeaders,
...headers,
};
}
const response = await httpClient.sendRequest<T>({
method,
url: `${BASE_URL}${path}`,
headers: mergedHeaders,
body,
});
return response.body;
} catch (error: any) {
throw new Error(`Unexpected error: ${error.message || String(error)}`);
}
}

View File

@@ -0,0 +1,347 @@
import { Property } from '@activepieces/pieces-framework';
import { makeRequest } from './client';
import { HttpMethod } from '@activepieces/pieces-common';
import { NinoxAuth } from './auth';
export const teamidDropdown = Property.Dropdown({
auth: NinoxAuth,
displayName: 'Team ID',
description: 'Select the team containing the database.',
required: true,
refreshers: [],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first.',
};
}
try {
const teams = await makeRequest<{ id: string; name: string }[]>(
auth.secret_text,
HttpMethod.GET,
'/teams',
);
return {
disabled: false,
options: teams.map((team) => ({
label: team.name,
value: team.id,
})),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Error loading teams',
};
}
},
});
export const databaseIdDropdown = Property.Dropdown({
auth: NinoxAuth,
displayName: 'Database ID',
description: 'Select the database containing the table.',
required: true,
refreshers: ['teamid'],
options: async ({ auth, teamid }) => {
if (!auth || !teamid) {
return {
disabled: true,
options: [],
placeholder: 'Please select a team first.',
};
}
try {
const databases = await makeRequest<{ id: string; name: string }[]>(
auth.secret_text,
HttpMethod.GET,
`/teams/${teamid}/databases`,
);
return {
disabled: false,
options: databases.map((db) => ({
label: db.name,
value: db.id,
})),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Error loading databases',
};
}
},
});
export const tableIdDropdown = Property.Dropdown({
auth: NinoxAuth,
displayName: 'Table ID',
description: 'Select the table',
required: true,
refreshers: ['teamid', 'dbid'],
options: async ({ auth, teamid, dbid }) => {
if (!auth || !teamid || !dbid) {
return {
disabled: true,
options: [],
placeholder: 'Please select a database first.',
};
}
try {
const tables = await makeRequest<{ id: string; name: string }[]>(
auth.secret_text,
HttpMethod.GET,
`/teams/${teamid}/databases/${dbid}/tables`,
);
return {
disabled: false,
options: tables.map((table) => ({
label: table.name,
value: table.id,
})),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Error loading tables',
};
}
},
});
export const recordIdDropdown = Property.Dropdown({
auth: NinoxAuth,
displayName: 'Record ID',
required: true,
refreshers: ['teamid', 'dbid', 'tid'],
options: async ({ auth, teamid, dbid, tid }) => {
if (!auth || !teamid || !dbid || !tid) {
return {
disabled: true,
options: [],
placeholder: 'Please select a table first',
};
}
try {
const records = await makeRequest<{ id: number }[]>(
auth.secret_text,
HttpMethod.GET,
`/teams/${teamid}/databases/${dbid}/tables/${tid}/records`,
);
return {
disabled: false,
options: records.map((record) => ({
label: `Record ${record.id}`,
value: record.id,
})),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Error loading records',
};
}
},
});
export const filenameDropdown = Property.Dropdown({
auth: NinoxAuth,
displayName: 'File ID',
required: true,
refreshers: ['teamid', 'dbid', 'tid', 'rid'],
options: async ({ auth, teamid, dbid, tid, rid }) => {
if (!auth || !teamid || !dbid || !tid || !rid) {
return {
disabled: true,
options: [],
placeholder: 'Please select a table first',
};
}
try {
const records = await makeRequest<{ name: string }[]>(
auth.secret_text,
HttpMethod.GET,
`/teams/${teamid}/databases/${dbid}/tables/${tid}/records/${rid}/files`,
);
return {
disabled: false,
options: records.map((record) => ({
label: record.name,
value: record.name,
})),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Error loading records',
};
}
},
});
export const tableFields = Property.DynamicProperties({
auth: NinoxAuth,
displayName: 'Record Fields',
required: true,
refreshers: ['teamid', 'dbid', 'tid'],
props: async ({ auth, teamid, dbid, tid }) => {
if (!auth || !teamid || !dbid || !tid) {
return {};
}
try {
// 1. Get the table schema (all possible fields)
const tableSchemaResponse = await makeRequest<{
fields: { id: string; name: string; type: string; choices: { caption: string }[] }[];
}>(
auth as unknown as string,
HttpMethod.GET,
`/teams/${teamid}/databases/${dbid}/tables/${tid}`,
);
const schemaFields = tableSchemaResponse.fields || [];
const fields: Record<string, any> = {};
// 2. For each field in the schema, create an empty property
for (const field of schemaFields) {
const fieldName = field.name;
const fieldType = field.type;
if (fieldName === 'id' || fieldName === '_id') continue;
switch (fieldType) {
case 'string':
case 'html':
case 'link':
case 'location':
case 'email':
case 'phone':
case 'color':
fields[fieldName] = Property.ShortText({
displayName: fieldName,
required: false,
});
break;
case 'time':
fields[fieldName] = Property.ShortText({
displayName: fieldName,
required: false,
description: 'HH:mm:ss format.',
});
break;
case 'number':
fields[fieldName] = Property.Number({
displayName: fieldName,
required: false,
});
break;
case 'boolean':
fields[fieldName] = Property.Checkbox({
displayName: fieldName,
required: false,
});
break;
case 'choice':
fields[fieldName] = Property.StaticDropdown({
displayName: fieldName,
required: false,
options: {
disabled: false,
options: field.choices.map((choice) => ({
label: choice.caption,
value: choice.caption,
})),
},
});
break;
case 'multi':
fields[fieldName] = Property.StaticMultiSelectDropdown({
displayName: fieldName,
required: false,
options: {
disabled: false,
options: field.choices.map((choice) => ({
label: choice.caption,
value: choice.caption,
})),
},
});
break;
case 'date':
case 'timestamp':
fields[fieldName] = Property.DateTime({
displayName: fieldName,
required: false,
});
break;
default:
break;
}
}
return fields;
} catch (error) {
return {};
}
},
});
export const tablefieldDropdown = Property.Dropdown({
auth: NinoxAuth,
displayName: 'Table Field',
required: true,
refreshers: ['teamid', 'dbid', 'tid'],
options: async ({ auth, teamid, dbid, tid }) => {
if (!auth || !teamid || !dbid) {
return {
disabled: true,
options: [],
placeholder: 'Please select a database first',
};
}
try {
const tableSchemaResponse = await makeRequest<{
fields: { id: string; name: string; type: string; choices: { caption: string }[] }[];
}>(
auth as unknown as string,
HttpMethod.GET,
`/teams/${teamid}/databases/${dbid}/tables/${tid}`,
);
const schemaFields = tableSchemaResponse.fields || [];
return {
disabled: false,
options: schemaFields.map((field) => ({
label: field.name,
value: field.id,
})),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Error loading tables',
};
}
},
});

View File

@@ -0,0 +1,94 @@
import {
AuthenticationType,
DedupeStrategy,
httpClient,
HttpMethod,
Polling,
pollingHelper,
QueryParams,
} from '@activepieces/pieces-common';
import {
AppConnectionValueForAuthProperty,
StaticPropsValue,
TriggerStrategy,
createTrigger,
} from '@activepieces/pieces-framework';
import { BASE_URL } from '../common/client';
import { NinoxAuth } from '../common/auth';
import { teamidDropdown, databaseIdDropdown, tableIdDropdown } from '../common/props';
const props = {
teamid: teamidDropdown,
dbid: databaseIdDropdown,
tid: tableIdDropdown,
};
const polling: Polling<AppConnectionValueForAuthProperty<typeof NinoxAuth>, StaticPropsValue<typeof props>> = {
strategy: DedupeStrategy.LAST_ITEM,
async items({ auth, propsValue, lastItemId }) {
const { teamid, dbid, tid } = propsValue;
const isTest = lastItemId === null;
const qs:QueryParams = { new: 'true', perPage: isTest ? '10' : '100', page: '0'}
if(lastItemId) qs['sinceId'] = String(lastItemId)
const response = await httpClient.sendRequest<Array<{ id: number }>>({
method: HttpMethod.GET,
url: BASE_URL + `/teams/${teamid}/databases/${dbid}/tables/${tid}/records`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.secret_text,
},
queryParams: qs,
});
return response.body.map((record) => ({
id: record.id,
data: record,
}));
},
};
export const newRecord = createTrigger({
auth: NinoxAuth,
name: 'newRecord',
displayName: 'New Record',
description: 'Triggers when a new record is created in a table.',
props,
sampleData: {
id: 10,
sequence: 45,
createdAt: '2025-07-18T11:19:58',
createdBy: 'BwqY7B4K9KidHBuEs',
modifiedAt: '2025-07-18T11:20:01',
modifiedBy: 'BwqY7B4K9KidHBuEs',
fields: {
'text-field': 'test',
'Rich text': '',
Location: '',
},
},
type: TriggerStrategy.POLLING,
async onEnable(context) {
await pollingHelper.onEnable(polling, {
auth: context.auth,
store: context.store,
propsValue: context.propsValue,
});
},
async onDisable(context) {
await pollingHelper.onDisable(polling, {
auth: context.auth,
store: context.store,
propsValue: context.propsValue,
});
},
async test(context) {
return await pollingHelper.test(polling, context);
},
async run(context) {
return await pollingHelper.poll(polling, context);
},
});