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-confluence
This library was generated with [Nx](https://nx.dev).
## Building
Run `nx build pieces-confluence` to build the library.

View File

@@ -0,0 +1,7 @@
{
"name": "@activepieces/piece-confluence",
"version": "0.1.10",
"dependencies": {
"xml2js": "0.6.2"
}
}

View File

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

View File

@@ -0,0 +1,45 @@
{
"Account Email": "Konto-E-Mail",
"API token": "API token",
"Confluence Domain": "Konfluenz-Domäne",
"Account email for basic auth": "Account-E-Mail für Basis-Authentifizierung",
"API token for basic auth": "API-Token für Basis-Authentifizierung",
"Example value - https://your-domain.atlassian.net": "Beispielwert - https://your-domain.atlassian.net",
"Please refer to this guide to get your api credentials: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account": "Bitte lesen Sie diese Anleitung, um Ihre Api Zugangsdaten zu erhalten: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account",
"Get Page Content": "Get Page Content",
"Create Page from Template": "Seite aus Vorlage erstellen",
"Custom API Call": "Eigener API-Aufruf",
"Get page content and optionally all its descendants": "Seiteninhalt und optional alle Nachkommen abrufen",
"Creates a new page from a template with the given title and variables.": "Erstellt eine neue Seite aus einer Vorlage mit dem angegebenen Titel und Variablen.",
"Make a custom API call to a specific endpoint": "Einen benutzerdefinierten API-Aufruf an einen bestimmten Endpunkt machen",
"Page ID": "Seiten-ID",
"Include Descendants ?": "Nachfahren einbeziehen ?",
"Dynamic Properties": "Dynamische Eigenschaften",
"Space": "Raum",
"Template": "Vorlage",
"Parent Folder": "Eltern-Ordner",
"Title": "Titel",
"Status": "Status",
"Template Variables": "Template-Variablen",
"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)",
"Get this from the page URL of your Confluence Cloud": "Holen Sie sich dies von der URL Ihrer Confluence Cloud",
"If checked, will fetch all child pages recursively.": "Wenn aktiviert, werden alle Unterseiten rekursiv abgerufen.",
"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..",
"Published ": "Veröffentlicht ",
"Draft": "Entwurf",
"GET": "ERHALTEN",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "LÖSCHEN",
"HEAD": "HEAD",
"New Page": "Neue Seite",
"Triggers when a new page is created.": "Wird ausgelöst, wenn eine neue Seite erstellt wird."
}

View File

@@ -0,0 +1,45 @@
{
"Account Email": "Email de cuenta",
"API token": "API token",
"Confluence Domain": "Dominio de Confluencia",
"Account email for basic auth": "Email de cuenta para la autenticación básica",
"API token for basic auth": "Token API para autenticación básica",
"Example value - https://your-domain.atlassian.net": "Valor de ejemplo - https://your-domain.atlassian.net",
"Please refer to this guide to get your api credentials: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account": "Por favor, consulta esta guía para obtener tus credenciales de api: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account",
"Get Page Content": "Get Page Content",
"Create Page from Template": "Crear página desde plantilla",
"Custom API Call": "Llamada API personalizada",
"Get page content and optionally all its descendants": "Obtener contenido de página y opcionalmente todos sus descendientes",
"Creates a new page from a template with the given title and variables.": "Crea una nueva página desde una plantilla con el título y las variables dadas.",
"Make a custom API call to a specific endpoint": "Hacer una llamada API personalizada a un extremo específico",
"Page ID": "ID de página",
"Include Descendants ?": "¿Incluye a los descendientes?",
"Dynamic Properties": "Propiedades dinámicas",
"Space": "Espacio",
"Template": "Plantilla",
"Parent Folder": "Carpeta padre",
"Title": "Título",
"Status": "Estado",
"Template Variables": "Variables de Plantilla",
"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)",
"Get this from the page URL of your Confluence Cloud": "Obtén esto de la URL de la página de tu Confluence Cloud",
"If checked, will fetch all child pages recursively.": "Si está marcado, se obtendrán todas las páginas hijas de forma recursiva.",
"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.",
"Published ": "Publicado ",
"Draft": "Borrador",
"GET": "RECOGER",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "BORRAR",
"HEAD": "LIMPIO",
"New Page": "Nueva página",
"Triggers when a new page is created.": "Dispara cuando se crea una nueva página."
}

View File

@@ -0,0 +1,45 @@
{
"Account Email": "E-mail du compte",
"API token": "API token",
"Confluence Domain": "Domaine de Confluence",
"Account email for basic auth": "E-mail du compte pour l'authentification de base",
"API token for basic auth": "Jeton d'API pour l'authentification de base",
"Example value - https://your-domain.atlassian.net": "Valeur de l'exemple - https://votre-domaine.atlassian.net",
"Please refer to this guide to get your api credentials: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account": "Veuillez vous référer à ce guide pour obtenir vos identifiants api : https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account",
"Get Page Content": "Get Page Content",
"Create Page from Template": "Créer une page à partir du modèle",
"Custom API Call": "Appel API personnalisé",
"Get page content and optionally all its descendants": "Obtenir le contenu de la page et, optionnellement, tous ses descendants",
"Creates a new page from a template with the given title and variables.": "Crée une nouvelle page à partir d'un modèle avec le titre et les variables donnés.",
"Make a custom API call to a specific endpoint": "Passez un appel API personnalisé à un point de terminaison spécifique",
"Page ID": "ID de la page",
"Include Descendants ?": "Inclure les descendants ?",
"Dynamic Properties": "Propriétés dynamiques",
"Space": "Espace libre",
"Template": "Gabarit",
"Parent Folder": "Dossier parent",
"Title": "Titre de la page",
"Status": "Statut",
"Template Variables": "Variables de modèle",
"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)",
"Get this from the page URL of your Confluence Cloud": "Récupérez ceci à partir de l'URL de la page de votre Cloud Confluence",
"If checked, will fetch all child pages recursively.": "Si cette case est cochée, toutes les pages enfants seront récupérées récursivement.",
"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.",
"Published ": "Publié ",
"Draft": "Brouillon",
"GET": "OBTENIR",
"POST": "POSTER",
"PATCH": "PATCH",
"PUT": "EFFACER",
"DELETE": "SUPPRIMER",
"HEAD": "TÊTE",
"New Page": "Nouvelle page",
"Triggers when a new page is created.": "Déclenche quand une nouvelle page est créée."
}

View File

@@ -0,0 +1,45 @@
{
"Account Email": "アカウントのメールアドレス",
"API token": "API token",
"Confluence Domain": "Confluence Domain",
"Account email for basic auth": "ベーシック認証用のアカウントメールアドレス",
"API token for basic auth": "基本的な認証のためのAPIトークン",
"Example value - https://your-domain.atlassian.net": "値の例 - https://your-domain.atlassian.net",
"Please refer to this guide to get your api credentials: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account": "あなたのapi認証情報を取得するには、このガイドを参照してください: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account",
"Get Page Content": "Get Page Content",
"Create Page from Template": "テンプレートからページを作成",
"Custom API Call": "カスタムAPI通話",
"Get page content and optionally all its descendants": "ページコンテンツを取得し、必要に応じてその子孫をすべて取得します",
"Creates a new page from a template with the given title and variables.": "指定されたタイトルと変数を持つテンプレートから新しいページを作成します。",
"Make a custom API call to a specific endpoint": "特定のエンドポイントへのカスタム API コールを実行します。",
"Page ID": "ページID",
"Include Descendants ?": "子孫を含む ?",
"Dynamic Properties": "動的プロパティ",
"Space": "スペース",
"Template": "テンプレート",
"Parent Folder": "親フォルダ",
"Title": "タイトル",
"Status": "Status",
"Template Variables": "テンプレート変数",
"Method": "方法",
"Headers": "ヘッダー",
"Query Parameters": "クエリパラメータ",
"Body": "本文",
"Response is Binary ?": "応答はバイナリですか?",
"No Error on Failure": "失敗時にエラーはありません",
"Timeout (in seconds)": "タイムアウト(秒)",
"Get this from the page URL of your Confluence Cloud": "Confluence CloudのページURLから入手する",
"If checked, will fetch all child pages recursively.": "チェックした場合、すべての子ページを再帰的に取得します。",
"Authorization headers are injected automatically from your connection.": "認証ヘッダは接続から自動的に注入されます。",
"Enable for files like PDFs, images, etc..": "PDF、画像などのファイルを有効にします。",
"Published ": "公開済み ",
"Draft": "下書き",
"GET": "取得",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "削除",
"HEAD": "頭",
"New Page": "新しいページ",
"Triggers when a new page is created.": "新しいページが作成されたときにトリガーします。"
}

View File

@@ -0,0 +1,45 @@
{
"Account Email": "Account e-mail",
"API token": "API token",
"Confluence Domain": "Confluence Domein",
"Account email for basic auth": "Account e-mail voor basis authenticatie",
"API token for basic auth": "API token voor basis authenticatie",
"Example value - https://your-domain.atlassian.net": "Voorbeeldwaarde - https://uw-domein.atlassian.net",
"Please refer to this guide to get your api credentials: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account": "Raadpleeg deze handleiding om uw api referenties te krijgen: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account",
"Get Page Content": "Get Page Content",
"Create Page from Template": "Maak pagina van sjabloon",
"Custom API Call": "Custom API Call",
"Get page content and optionally all its descendants": "Pagina-inhoud en optioneel al zijn afstammelingen ophalen",
"Creates a new page from a template with the given title and variables.": "Maakt een nieuwe pagina van een template met de opgegeven titel en variabelen.",
"Make a custom API call to a specific endpoint": "Maak een aangepaste API call naar een specifiek eindpunt",
"Page ID": "Pagina ID",
"Include Descendants ?": "Inclusief Descendants ?",
"Dynamic Properties": "Dynamische eigenschappen",
"Space": "Spatiebalk",
"Template": "Sjabloon",
"Parent Folder": "Bovenliggende map",
"Title": "Aanspreektitel",
"Status": "status",
"Template Variables": "Template variabelen",
"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)",
"Get this from the page URL of your Confluence Cloud": "Verkrijg dit van de pagina-URL van je Confluence Cloud",
"If checked, will fetch all child pages recursively.": "Indien aangevinkt, worden alle onderliggende pagina's recursief opgehaald.",
"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..",
"Published ": "Gepubliceerd ",
"Draft": "Concept",
"GET": "KRIJG",
"POST": "POSTE",
"PATCH": "BEKIJK",
"PUT": "PUT",
"DELETE": "VERWIJDEREN",
"HEAD": "HOOFD",
"New Page": "Nieuwe pagina",
"Triggers when a new page is created.": "Triggers wanneer een nieuwe pagina is aangemaakt."
}

View File

@@ -0,0 +1,45 @@
{
"Account Email": "Email do Cliente",
"API token": "API token",
"Confluence Domain": "Domínio de Confluência",
"Account email for basic auth": "E-mail da conta para autenticação básica",
"API token for basic auth": "Token de API para autenticação básica",
"Example value - https://your-domain.atlassian.net": "Exemplo de valor - https://seu-dominio.atlassian.net",
"Please refer to this guide to get your api credentials: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account": "Por favor, consulte este guia para obter suas credenciais de api: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account",
"Get Page Content": "Get Page Content",
"Create Page from Template": "Criar página a partir do Modelo",
"Custom API Call": "Chamada de API personalizada",
"Get page content and optionally all its descendants": "Obtenha o conteúdo da página e, opcionalmente, todos os seus descendentes",
"Creates a new page from a template with the given title and variables.": "Cria uma nova página a partir de um modelo com o título e as variáveis fornecidos.",
"Make a custom API call to a specific endpoint": "Faça uma chamada de API personalizada para um ponto de extremidade específico",
"Page ID": "ID da Página",
"Include Descendants ?": "Incluir Descendentes ?",
"Dynamic Properties": "Propriedades Dinâmicas",
"Space": "Sala",
"Template": "Modelo",
"Parent Folder": "Pasta pai",
"Title": "Título",
"Status": "Estado",
"Template Variables": "Variáveis de Template",
"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)",
"Get this from the page URL of your Confluence Cloud": "Obter isto na URL da página de sua Nuvem de Confluência",
"If checked, will fetch all child pages recursively.": "Se marcado, irá buscar todas as páginas filhas recursivamente.",
"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..",
"Published ": "Publicado ",
"Draft": "Rascunho",
"GET": "OBTER",
"POST": "POSTAR",
"PATCH": "COMPRAR",
"PUT": "COLOCAR",
"DELETE": "EXCLUIR",
"HEAD": "CABEÇA",
"New Page": "Nova Página",
"Triggers when a new page is created.": "Dispara quando uma nova página é criada."
}

View File

@@ -0,0 +1,44 @@
{
"Confluence": "Confluence",
"Account Email": "Email клиента",
"API token": "API token",
"Confluence Domain": "Домен доверия",
"Account email for basic auth": "Email аккаунта для базовой авторизации",
"API token for basic auth": "API токен для базовой авторизации",
"Example value - https://your-domain.atlassian.net": "Пример значения - https://your-domain.atlassian.net",
"Please refer to this guide to get your api credentials: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account": "Пожалуйста, обратитесь к этому руководству, чтобы получить ваши учётные данные api: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account",
"Get Page Content": "Get Page Content",
"Create Page from Template": "Создать страницу из шаблона",
"Custom API Call": "Пользовательский вызов API",
"Get page content and optionally all its descendants": "Получить содержимое страницы и по желанию все ее потомки",
"Creates a new page from a template with the given title and variables.": "Создает новую страницу из шаблона с заданным заголовком и переменными.",
"Make a custom API call to a specific endpoint": "Сделать пользовательский API вызов к определенной конечной точке",
"Page ID": "ID страницы",
"Include Descendants ?": "Включить потомков ?",
"Dynamic Properties": "Динамические свойства",
"Space": "Пространство",
"Template": "Шаблон",
"Parent Folder": "Родительская папка",
"Title": "Заголовок",
"Status": "Статус",
"Template Variables": "Переменные шаблона",
"Method": "Метод",
"Headers": "Заголовки",
"Query Parameters": "Параметры запроса",
"Body": "Тело",
"No Error on Failure": "Нет ошибок при ошибке",
"Timeout (in seconds)": "Таймаут (в секундах)",
"Get this from the page URL of your Confluence Cloud": "Получить это со страницы вашего облака Confluence Cloud",
"If checked, will fetch all child pages recursively.": "При отмеченной опции все дочерние страницы будут загружены рекурсивно.",
"Authorization headers are injected automatically from your connection.": "Заголовки авторизации включаются автоматически из вашего соединения.",
"Published ": "Опубликовано ",
"Draft": "Черновик",
"GET": "ПОЛУЧИТЬ",
"POST": "ПОСТ",
"PATCH": "ПАТЧ",
"PUT": "ПОКУПИТЬ",
"DELETE": "УДАЛИТЬ",
"HEAD": "HEAD",
"New Page": "Новая страница",
"Triggers when a new page is created.": "Включает при создании новой страницы."
}

View File

@@ -0,0 +1,45 @@
{
"Account Email": "Account Email",
"API token": "API token",
"Confluence Domain": "Confluence Domain",
"Account email for basic auth": "Account email for basic auth",
"API token for basic auth": "API token for basic auth",
"Example value - https://your-domain.atlassian.net": "Example value - https://your-domain.atlassian.net",
"Please refer to this guide to get your api credentials: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account": "Please refer to this guide to get your api credentials: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account",
"Get Page Content": "Get Page Content",
"Create Page from Template": "Create Page from Template",
"Custom API Call": "Custom API Call",
"Get page content and optionally all its descendants": "Get page content and optionally all its descendants",
"Creates a new page from a template with the given title and variables.": "Creates a new page from a template with the given title and variables.",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Page ID": "Page ID",
"Include Descendants ?": "Include Descendants ?",
"Dynamic Properties": "Dynamic Properties",
"Space": "Space",
"Template": "Template",
"Parent Folder": "Parent Folder",
"Title": "Title",
"Status": "Status",
"Template Variables": "Template Variables",
"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)",
"Get this from the page URL of your Confluence Cloud": "Get this from the page URL of your Confluence Cloud",
"If checked, will fetch all child pages recursively.": "If checked, will fetch all child pages recursively.",
"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..",
"Published ": "Published ",
"Draft": "Draft",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"New Page": "New Page",
"Triggers when a new page is created.": "Triggers when a new page is created."
}

View File

@@ -0,0 +1,44 @@
{
"Confluence": "Confluence",
"Account Email": "Account Email",
"API token": "API token",
"Confluence Domain": "Confluence Domain",
"Account email for basic auth": "Account email for basic auth",
"API token for basic auth": "API token for basic auth",
"Example value - https://your-domain.atlassian.net": "Example value - https://your-domain.atlassian.net",
"Please refer to this guide to get your api credentials: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account": "Please refer to this guide to get your api credentials: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account",
"Get Page Content": "Get Page Content",
"Create Page from Template": "Create Page from Template",
"Custom API Call": "Custom API Call",
"Get page content and optionally all its descendants": "Get page content and optionally all its descendants",
"Creates a new page from a template with the given title and variables.": "Creates a new page from a template with the given title and variables.",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Page ID": "Page ID",
"Include Descendants ?": "Include Descendants ?",
"Dynamic Properties": "Dynamic Properties",
"Space": "Space",
"Template": "Template",
"Parent Folder": "Parent Folder",
"Title": "Title",
"Status": "Status",
"Template Variables": "Template Variables",
"Method": "Method",
"Headers": "Headers",
"Query Parameters": "Query Parameters",
"Body": "Body",
"No Error on Failure": "No Error on Failure",
"Timeout (in seconds)": "Timeout (in seconds)",
"Get this from the page URL of your Confluence Cloud": "Get this from the page URL of your Confluence Cloud",
"If checked, will fetch all child pages recursively.": "If checked, will fetch all child pages recursively.",
"Authorization headers are injected automatically from your connection.": "Authorization headers are injected automatically from your connection.",
"Published ": "Đã xuất bản ",
"Draft": "Bản nháp",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"New Page": "New Page",
"Triggers when a new page is created.": "Triggers when a new page is created."
}

View File

@@ -0,0 +1,45 @@
{
"Account Email": "Account Email",
"API token": "API token",
"Confluence Domain": "Confluence Domain",
"Account email for basic auth": "Account email for basic auth",
"API token for basic auth": "API token for basic auth",
"Example value - https://your-domain.atlassian.net": "Example value - https://your-domain.atlassian.net",
"Please refer to this guide to get your api credentials: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account": "Please refer to this guide to get your api credentials: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account",
"Get Page Content": "Get Page Content",
"Create Page from Template": "Create Page from Template",
"Custom API Call": "自定义 API 呼叫",
"Get page content and optionally all its descendants": "Get page content and optionally all its descendants",
"Creates a new page from a template with the given title and variables.": "Creates a new page from a template with the given title and variables.",
"Make a custom API call to a specific endpoint": "将一个自定义 API 调用到一个特定的终点",
"Page ID": "Page ID",
"Include Descendants ?": "Include Descendants ?",
"Dynamic Properties": "Dynamic Properties",
"Space": "Space",
"Template": "模板",
"Parent Folder": "父文件夹",
"Title": "标题",
"Status": "状态",
"Template Variables": "Template Variables",
"Method": "方法",
"Headers": "信头",
"Query Parameters": "查询参数",
"Body": "正文内容",
"Response is Binary ?": "Response is Binary ?",
"No Error on Failure": "失败时没有错误",
"Timeout (in seconds)": "超时(秒)",
"Get this from the page URL of your Confluence Cloud": "Get this from the page URL of your Confluence Cloud",
"If checked, will fetch all child pages recursively.": "If checked, will fetch all child pages recursively.",
"Authorization headers are injected automatically from your connection.": "授权头自动从您的连接中注入。",
"Enable for files like PDFs, images, etc..": "Enable for files like PDFs, images, etc..",
"Published ": "已发布 ",
"Draft": "草稿",
"GET": "获取",
"POST": "帖子",
"PATCH": "PATCH",
"PUT": "弹出",
"DELETE": "删除",
"HEAD": "黑色",
"New Page": "New Page",
"Triggers when a new page is created.": "Triggers when a new page is created."
}

View File

@@ -0,0 +1,52 @@
import { createPiece, PieceAuth, Property ,PiecePropValueSchema, Piece} from "@activepieces/pieces-framework";
import { getPageContent } from "./lib/actions/get-page-content";
import { newPageTrigger } from "./lib/triggers/new-page";
import { PieceCategory } from "@activepieces/shared";
import { createCustomApiCallAction } from "@activepieces/pieces-common";
import { createPageFromTemplateAction } from "./lib/actions/create-page-from-template";
export const confluenceAuth = PieceAuth.CustomAuth({
description: 'Please refer to this guide to get your api credentials: https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account',
required: true,
props: {
username: PieceAuth.SecretText({
displayName: 'Account Email',
required: true,
description: 'Account email for basic auth',
}),
password: PieceAuth.SecretText({
displayName: 'API token',
required: true,
description: 'API token for basic auth',
}),
confluenceDomain: Property.ShortText({
displayName: 'Confluence Domain',
required: true,
description: 'Example value - https://your-domain.atlassian.net',
}),
},
});
export const confluence = createPiece({
displayName: "Confluence",
auth: confluenceAuth,
minimumSupportedRelease: '0.30.0',
logoUrl: "https://cdn.activepieces.com/pieces/confluence.png",
authors: ["geekyme"],
actions: [getPageContent,createPageFromTemplateAction,
createCustomApiCallAction({
baseUrl:(auth)=>{
return `${ auth?.props.confluenceDomain?? ''}/wiki/api/v2`;
},
auth: confluenceAuth,
authMapping: async (auth) => {
const authValue = auth.props
return {
Authorization: `Basic ${Buffer.from(`${authValue.username}:${authValue.password}`).toString('base64')}`,
};
},
})
],
categories: [PieceCategory.CONTENT_AND_FILES],
triggers: [newPageTrigger],
});

View File

@@ -0,0 +1,82 @@
import { confluenceAuth } from "../../index";
import { createAction, Property } from "@activepieces/pieces-framework";
import { folderIdProp, spaceIdProp, templateIdProp, templateVariablesProp } from "../common/props";
import { confluenceApiCall } from "../common";
import { HttpMethod } from "@activepieces/pieces-common";
export const createPageFromTemplateAction = createAction({
auth:confluenceAuth,
name:'create-page-from-template',
displayName:'Create Page from Template',
description:'Creates a new page from a template with the given title and variables.',
props:{
spaceId:spaceIdProp,
templateId:templateIdProp,
folderId:folderIdProp,
title:Property.ShortText({
displayName:'Title',
required:true,
}),
status:Property.StaticDropdown({
displayName:'Status',
required:true,
defaultValue:'draft',
options:{
disabled:false,
options:[
{
label:'Published ',
value:'current'
},
{
label:'Draft',
value:'draft'
}
]
}
}),
templateVariables:templateVariablesProp,
},
async run(context){
const {spaceId,templateId,title,status,folderId} = context.propsValue;
const variables = context.propsValue.templateVariables ??{};
const template = await confluenceApiCall<{ body: { storage: { value: string } } }>({
domain: context.auth.props.confluenceDomain,
username: context.auth.props.username,
password: context.auth.props.password,
method: HttpMethod.GET,
version: 'v1',
resourceUri: `/template/${templateId}`,
});
const body = template.body.storage.value;
let content = body.replace(/<at:declarations>[\s\S]*?<\/at:declarations>/, "").trim();
Object.entries(variables).forEach(([key, value]) => {
const varRegex = new RegExp(`<at:var at:name=(['"])${key}\\1\\s*\\/?>`, "g");
content = content.replace(varRegex, value);
});
const response = await confluenceApiCall({
domain: context.auth.props.confluenceDomain,
username: context.auth.props.username,
password: context.auth.props.password,
method: HttpMethod.POST,
version: 'v2',
resourceUri: '/pages',
body: {
spaceId:spaceId,
title,
parentId:folderId,
status,
body:{
representation:'storage',
value:content,
}
}
})
return response;
}
})

View File

@@ -0,0 +1,149 @@
import {
createAction,
Property,
DynamicPropsValue,
PiecePropValueSchema,
AppConnectionValueForAuthProperty,
} from '@activepieces/pieces-framework';
import { HttpMethod } from '@activepieces/pieces-common';
import { confluenceAuth } from '../..';
import { confluenceApiCall } from '../common';
interface ConfluencePage {
id: string;
title: string;
body: any;
children?: ConfluencePage[];
}
async function getPageWithContent(
auth: AppConnectionValueForAuthProperty<typeof confluenceAuth>,
pageId: string,
): Promise<ConfluencePage> {
try {
const response = await confluenceApiCall<ConfluencePage>({
domain: auth.props.confluenceDomain,
username: auth.props.username,
password: auth.props.password,
method: HttpMethod.GET,
version: 'v2',
resourceUri: `/pages/${pageId}`,
query: {
'body-format': 'storage',
},
});
return response;
} catch (error) {
throw new Error(
`Failed to fetch page ${pageId}: ${error instanceof Error ? error.message : 'Unknown error'}`,
);
}
}
async function getChildPages(
auth: AppConnectionValueForAuthProperty<typeof confluenceAuth>,
parentId: string,
currentDepth: number,
maxDepth: number,
): Promise<ConfluencePage[]> {
if (currentDepth >= maxDepth) {
return [];
}
try {
const childrenResponse = await confluenceApiCall<{ results: ConfluencePage[] }>({
domain: auth.props.confluenceDomain,
username: auth.props.username,
password: auth.props.password,
method: HttpMethod.GET,
version: 'v2',
resourceUri: `/pages/${parentId}/children`,
});
const childPages = await Promise.all(
childrenResponse.results.map(async (childPage) => {
const pageWithContent = await getPageWithContent(auth, childPage.id);
const children = await getChildPages(auth, childPage.id, currentDepth + 1, maxDepth);
return {
...pageWithContent,
children,
};
}),
);
return childPages;
} catch (error) {
throw new Error(
`Failed to fetch children for page ${parentId}: ${
error instanceof Error ? error.message : 'Unknown error'
}`,
);
}
}
export const getPageContent = createAction({
name: 'getPageContent',
displayName: 'Get Page Content',
description: 'Get page content and optionally all its descendants',
auth: confluenceAuth,
props: {
pageId: Property.ShortText({
displayName: 'Page ID',
description: 'Get this from the page URL of your Confluence Cloud',
required: true,
}),
includeDescendants: Property.Checkbox({
displayName: 'Include Descendants ?',
description: 'If checked, will fetch all child pages recursively.',
required: false,
defaultValue: false,
}),
dynamic: Property.DynamicProperties({
auth: confluenceAuth,
displayName: 'Dynamic Properties',
refreshers: ['includeDescendants'],
required: true,
props: async ({ includeDescendants }) => {
if (!includeDescendants) {
return {};
}
const fields: DynamicPropsValue = {
maxDepth: Property.Number({
displayName: 'Maximum Depth',
description: 'Maximum depth of child pages to fetch.',
required: true,
defaultValue: 5,
}),
};
return fields;
},
}),
},
async run(context) {
try {
const page = await getPageWithContent(context.auth, context.propsValue.pageId);
if (!context.propsValue.includeDescendants) {
return page;
}
const children = await getChildPages(
context.auth,
context.propsValue.pageId,
1,
context.propsValue.dynamic['maxDepth'],
);
return {
...page,
children,
};
} catch (error) {
throw new Error(
`Failed to fetch page ${context.propsValue.pageId}: ${
error instanceof Error ? error.message : 'Unknown error'
}`,
);
}
},
});

View File

@@ -0,0 +1,118 @@
import {
AuthenticationType,
httpClient,
HttpMessageBody,
HttpMethod,
HttpRequest,
QueryParams,
} from '@activepieces/pieces-common';
import { isNil } from '@activepieces/shared';
export type ConfluenceApiCallParams = {
domain: string;
username: string;
password: string;
version: 'v1' | 'v2';
method: HttpMethod;
resourceUri: string;
query?: QueryParams;
body?: any;
};
export type PaginatedResponse<T> = {
results: T[];
_links?: {
next?: string;
};
};
export async function confluenceApiCall<T extends HttpMessageBody>({
domain,
username,
password,
method,
version,
resourceUri,
query,
body,
}: ConfluenceApiCallParams): Promise<T> {
const baseUrl = version === 'v2' ? `${domain}/wiki/api/v2` : `${domain}/wiki/rest/api`;
const request: HttpRequest = {
method,
url: baseUrl + resourceUri,
authentication: {
type: AuthenticationType.BASIC,
username,
password,
},
queryParams: query,
body: body,
};
const response = await httpClient.sendRequest<T>(request);
return response.body;
}
export async function confluencePaginatedApiCall<T extends HttpMessageBody>({
domain,
username,
password,
method,
version,
resourceUri,
query,
body,
}: ConfluenceApiCallParams): Promise<T[]> {
const qs = query ? query : {};
const resultData: T[] = [];
if (version === 'v2') {
let nextUrl = `${domain}/wiki/api/v2${resourceUri}?limit=200`;
do {
const response = await httpClient.sendRequest<PaginatedResponse<T>>({
method,
url: nextUrl,
authentication: {
type: AuthenticationType.BASIC,
username,
password,
},
queryParams: qs,
body,
});
if (isNil(response.body.results)) {
break;
}
resultData.push(...response.body.results);
nextUrl = response.body?._links?.next ? `${domain}${response.body._links.next}` : '';
} while (nextUrl);
} else {
let start = 0;
let hasMoreData = true;
do {
const response = await httpClient.sendRequest<{ results: T[] }>({
method,
url: `${domain}/wiki/rest/api${resourceUri}?start=${start}&limit=100`,
authentication: {
type: AuthenticationType.BASIC,
username,
password,
},
queryParams: qs,
body,
});
if (isNil(response.body.results) || response.body.results.length === 0) {
hasMoreData = false;
} else {
resultData.push(...response.body.results);
start += 100;
}
} while (hasMoreData);
}
return resultData;
}

View File

@@ -0,0 +1,251 @@
import { HttpMethod } from '@activepieces/pieces-common';
import { confluenceApiCall, confluencePaginatedApiCall } from '.';
import { confluenceAuth } from '../../index';
import {
DropdownOption,
DynamicPropsValue,
PiecePropValueSchema,
Property,
} from '@activepieces/pieces-framework';
import { parseStringPromise } from 'xml2js';
export const spaceIdProp = Property.Dropdown({
auth: confluenceAuth,
displayName: 'Space',
refreshers: [],
required: true,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first.',
};
}
const spaces = await confluencePaginatedApiCall<{ id: string; name: string }>({
domain: auth.props.confluenceDomain,
username: auth.props.username,
password: auth.props.password,
version: 'v2',
method: HttpMethod.GET,
resourceUri: '/spaces',
});
const options: DropdownOption<string>[] = [];
for (const space of spaces) {
options.push({
label: space.name,
value: space.id,
});
}
return {
disabled: false,
options,
};
},
});
export const templateIdProp = Property.Dropdown({
displayName: 'Template',
auth: confluenceAuth,
refreshers: ['spaceId'],
required: true,
options: async ({ auth, spaceId }) => {
if (!auth || !spaceId) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first and select a space.',
};
}
const space = await confluenceApiCall<{ id: string; name: string; key: string }>({
domain: auth.props.confluenceDomain,
username: auth.props.username,
password: auth.props.password,
method: HttpMethod.GET,
version: 'v2',
resourceUri: `/spaces/${spaceId}`,
});
const templates = await confluencePaginatedApiCall<{ templateId: string; name: string }>({
domain: auth.props.confluenceDomain,
username: auth.props.username,
password: auth.props.password,
version: 'v1',
method: HttpMethod.GET,
resourceUri: `/template/page`,
query: { spaceKey: space.key },
});
const options: DropdownOption<string>[] = [];
for (const template of templates) {
options.push({
label: template.name,
value: template.templateId,
});
}
return {
disabled: false,
options,
};
},
});
export const folderIdProp = Property.Dropdown({
displayName:'Parent Folder',
auth: confluenceAuth,
refreshers:['spaceId'],
required:false,
options:async ({auth,spaceId})=>{
if (!auth || !spaceId) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first and select a space.',
};
}
const space = await confluenceApiCall<{ id: string; name: string; key: string,homepageId:string }>({
domain: auth.props.confluenceDomain,
username: auth.props.username,
password: auth.props.password,
method: HttpMethod.GET,
version: 'v2',
resourceUri: `/spaces/${spaceId}`,
});
const folders = await confluencePaginatedApiCall<{id:string,title:string}>({
domain:auth.props.confluenceDomain,
username:auth.props.username,
password:auth.props.password,
version:'v1',
method:HttpMethod.GET,
resourceUri:`/content/${space.homepageId}/descendant/folder`,
})
const options:DropdownOption<string>[] = [];
for(const folder of folders){
options.push({
label:folder.title,
value:folder.id
})
}
return{
disabled:false,
options
}
}
})
export const templateVariablesProp = Property.DynamicProperties({
displayName: 'Template Variables',
auth: confluenceAuth,
refreshers: ['templateId'],
required: true,
props: async ({ auth, templateId }) => {
if (!auth) return {};
if (!templateId) return {};
const props: DynamicPropsValue = {};
const response = await confluenceApiCall<{ body: { storage: { value: string } } }>({
domain: auth.props.confluenceDomain,
username: auth.props.username,
password: auth.props.password,
method: HttpMethod.GET,
version: 'v1',
resourceUri: `/template/${templateId}`,
});
const parsedXml = await parseStringPromise(response.body.storage.value, {
explicitArray: false,
});
const declarations = parsedXml['at:declarations'];
if (!declarations) return {};
const variables: Array<{ name: string; type: string; options?: string[] }> = [];
Object.entries(declarations).forEach(([key, value]: [string, any]) => {
const type = key.replace('at:', '');
if (Array.isArray(value)) {
value.forEach((item) => {
if (item['$']) {
const varName = item['$']['at:name'];
let options: string[] | undefined;
if (type === 'list' && item['at:option']) {
options = item['at:option'].map((opt: any) => opt['$']['at:value']);
}
if (varName && type) {
variables.push({
name: varName,
type: type,
options: options,
});
}
}
});
} else if (value['$']) {
const varName = value['$']['at:name'];
let options: string[] | undefined;
if (type === 'list' && value['at:option']) {
options = value['at:option'].map((opt: any) => opt['$']['at:value']);
}
if (varName && type) {
variables.push({
name: varName,
type: type,
options: options,
});
}
}
});
for (const variable of variables) {
switch (variable.type) {
case 'list':
props[variable.name] = Property.StaticDropdown({
displayName: variable.name,
required: false,
defaultValue: '',
options: {
disabled: false,
options: variable.options
? variable.options.map((option) => {
return {
label: option,
value: option,
};
})
: [],
},
});
break;
case 'string':
props[variable.name] = Property.ShortText({
displayName: variable.name,
required: false,
defaultValue: '',
});
break;
case 'textarea':
props[variable.name] = Property.LongText({
displayName: variable.name,
required: false,
defaultValue: '',
});
break;
default:
break;
}
}
return props;
},
});

View File

@@ -0,0 +1,126 @@
import {
createTrigger,
TriggerStrategy,
PiecePropValueSchema,
AppConnectionValueForAuthProperty,
} from '@activepieces/pieces-framework';
import { DedupeStrategy, Polling, pollingHelper, HttpMethod } from '@activepieces/pieces-common';
import { confluenceAuth } from '../../index';
import { confluenceApiCall, confluencePaginatedApiCall, PaginatedResponse } from '../common';
import { isNil } from '@activepieces/shared';
import { spaceIdProp } from '../common/props';
interface ConfluencePage {
id: string;
status: string;
title: string;
spaceId: string;
createdAt: string;
version: {
number: number;
createdAt: string;
};
}
type Props = {
spaceId: string;
};
const polling: Polling<AppConnectionValueForAuthProperty<typeof confluenceAuth>, Props> = {
strategy: DedupeStrategy.TIMEBASED,
async items({ auth, propsValue, lastFetchEpochMS }) {
const pages = [];
if (lastFetchEpochMS === 0) {
const response = await confluenceApiCall<PaginatedResponse<ConfluencePage>>({
domain: auth.props.confluenceDomain,
username: auth.props.username,
password: auth.props.password,
version: 'v2',
method: HttpMethod.GET,
resourceUri: `/spaces/${propsValue.spaceId}/pages`,
query: {
limit: '10',
sort: '-created-date',
},
});
if (isNil(response.results)) {
return [];
}
pages.push(...response.results);
} else {
const response = await confluencePaginatedApiCall<ConfluencePage>({
domain: auth.props.confluenceDomain,
username: auth.props.username,
password: auth.props.password,
method: HttpMethod.GET,
version: 'v2',
resourceUri: `/spaces/${propsValue.spaceId}/pages`,
query: {
sort: '-created-date',
},
});
if (isNil(response)) {
return [];
}
pages.push(...response);
}
return pages.map((page) => {
return {
epochMilliSeconds: new Date(page.createdAt).getTime(),
data: page,
};
});
},
};
export const newPageTrigger = createTrigger({
name: 'new-page',
displayName: 'New Page',
description: 'Triggers when a new page is created.',
auth: confluenceAuth,
type: TriggerStrategy.POLLING,
props: {
spaceId: spaceIdProp,
},
async onEnable(context) {
await pollingHelper.onEnable(polling, context);
},
async onDisable(context) {
await pollingHelper.onDisable(polling, context);
},
async run(context) {
return await pollingHelper.poll(polling, context);
},
async test(context) {
return await pollingHelper.test(polling, context);
},
sampleData: {
parentType: 'page',
parentId: '123456',
spaceId: 'SAMPLE123',
ownerId: '12345678abcd',
lastOwnerId: null,
createdAt: '2024-01-01T12:00:00.000Z',
authorId: '12345678abcd',
position: 1000,
version: {
number: 1,
message: 'Initial version',
minorEdit: false,
authorId: '12345678abcd',
createdAt: '2024-01-01T12:00:00.000Z',
},
body: {},
status: 'current',
title: 'Sample Confluence Page',
id: '987654321',
_links: {
editui: '/pages/resumedraft.action?draftId=987654321',
webui: '/spaces/SAMPLE/pages/987654321/Sample+Confluence+Page',
edituiv2: '/spaces/SAMPLE/pages/edit-v2/987654321',
tinyui: '/x/abcd123',
},
},
});

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