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,47 @@
{
"Content infrastructure for digital teams": "Inhaltsinfrastruktur für digitale Teams",
"Contentful Access Token": "Inhaltliches Zugangs-Token",
"Space": "Raum",
"Environment": "Umgebung",
"Search Records": "Datensätze suchen",
"Get Record": "Datensatz abrufen",
"Create Record": "Datensatz erstellen",
"Custom API Call": "Eigener API-Aufruf",
"Searches for records of a given Content Model": "Sucht nach Datensätzen eines bestimmten Content-Modells",
"Gets a Contentful record for a given Content Model": "Ruft einen inhaltlichen Datensatz für ein bestimmtes Content-Modell ab",
"Creates a new Contentful record for a given Content Model": "Erstellt einen neuen inhaltlichen Datensatz für ein bestimmtes Content-Modell",
"Make a custom API call to a specific endpoint": "Einen benutzerdefinierten API-Aufruf an einen bestimmten Endpunkt machen",
"Content Model": "Inhaltsmodell",
"Content Locale": "Content-Gebietsschema",
"Query Formula": "Abfrageformel",
"Limit": "Limit",
"Skip": "Überspringen",
"Relationship Include Depth": "Relationship Include Tiefe",
"Return Fields": "Rücksendefelder",
"Entity ID": "Entitäts-ID",
"Publish after Creating": "Nach dem Erstellen veröffentlichen",
"Fields": "Felder",
"Method": "Methode",
"Headers": "Kopfzeilen",
"Query Parameters": "Abfrageparameter",
"Body": "Körper",
"Response is Binary ?": "Antwort ist binär?",
"No Error on Failure": "Kein Fehler bei Fehler",
"Timeout (in seconds)": "Timeout (in Sekunden)",
"The query formula to use to search for records. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters for more information": "Die Abfrageformel für die Suche nach Datensätzen. Siehe https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters für weitere Informationen",
"The maximum number of records to return": "Die maximale Anzahl der zurückzusenden Datensätze",
"The number of records to skip": "Anzahl der zu überspringenden Datensätze",
"Number of levels to include for entries and assets. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links": "Anzahl der Ebenen die für Einträge und Assets hinzugefügt werden sollen. Siehe https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links",
"The fields to return for each record.": "Die Felder, die für jeden Datensatz zurückgegeben werden sollen.",
"The ID of the record to get.": "Die ID des zu erhaltenden Datensatzes.",
"Whether or not to publish this record after creating it.": "Gibt an, ob der Datensatz nach dem Erstellen veröffentlicht werden soll.",
"Fields for Content Model": "Felder für Inhaltsmodell",
"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"
}

View File

@@ -0,0 +1,47 @@
{
"Content infrastructure for digital teams": "Infraestructura de contenido para equipos digitales",
"Contentful Access Token": "Token de Acceso Contenido",
"Space": "Espacio",
"Environment": "Entorno",
"Search Records": "Buscar registros",
"Get Record": "Obtener registro",
"Create Record": "Crear registro",
"Custom API Call": "Llamada API personalizada",
"Searches for records of a given Content Model": "Busca registros de un determinado Modelo de Contenido",
"Gets a Contentful record for a given Content Model": "Obtiene un registro de contenido para un determinado Modelo de Contenido",
"Creates a new Contentful record for a given Content Model": "Crea un nuevo registro de contenido para un determinado Modelo de Contenido",
"Make a custom API call to a specific endpoint": "Hacer una llamada API personalizada a un extremo específico",
"Content Model": "Modelo de contenido",
"Content Locale": "Idioma de contenido",
"Query Formula": "Fórmula de consulta",
"Limit": "Límite",
"Skip": "Saltar",
"Relationship Include Depth": "La relación incluye la profundidad",
"Return Fields": "Campos de retorno",
"Entity ID": "ID de entidad",
"Publish after Creating": "Publicar después de crear",
"Fields": "Campos",
"Method": "Método",
"Headers": "Encabezados",
"Query Parameters": "Parámetros de consulta",
"Body": "Cuerpo",
"Response is Binary ?": "¿Respuesta es binaria?",
"No Error on Failure": "No hay ningún error en fallo",
"Timeout (in seconds)": "Tiempo de espera (en segundos)",
"The query formula to use to search for records. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters for more information": "La fórmula de consulta a usar para buscar registros. Vea https://www.contentful.com/developeropers/docs/references/content-delivery-api/#/reference/search-parameters para más información",
"The maximum number of records to return": "El número máximo de registros a devolver",
"The number of records to skip": "El número de registros a omitir",
"Number of levels to include for entries and assets. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links": "Número de niveles a incluir para entradas y activos. Vea https://www.contentful.com/Builopers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links",
"The fields to return for each record.": "Los campos a devolver para cada registro.",
"The ID of the record to get.": "El ID del registro a obtener.",
"Whether or not to publish this record after creating it.": "Si publicar o no este registro después de crearlo.",
"Fields for Content Model": "Campos para Modelo de Contenido",
"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"
}

View File

@@ -0,0 +1,47 @@
{
"Content infrastructure for digital teams": "Infrastructure de contenu pour les équipes numériques",
"Contentful Access Token": "Jeton d'accès au contenu",
"Space": "Espace libre",
"Environment": "Environnement",
"Search Records": "Rechercher des enregistrements",
"Get Record": "Obtenir un enregistrement",
"Create Record": "Créer un enregistrement",
"Custom API Call": "Appel API personnalisé",
"Searches for records of a given Content Model": "Recherche les enregistrements d'un modèle de contenu donné",
"Gets a Contentful record for a given Content Model": "Renvoie un enregistrement Contentful pour un modèle de contenu donné",
"Creates a new Contentful record for a given Content Model": "Crée un nouvel enregistrement Contentful pour un modèle de contenu donné",
"Make a custom API call to a specific endpoint": "Passez un appel API personnalisé à un point de terminaison spécifique",
"Content Model": "Modèle de contenu",
"Content Locale": "Langue du contenu",
"Query Formula": "Formule de requête",
"Limit": "Limite",
"Skip": "Ignorer",
"Relationship Include Depth": "Profondeur de la relation incluse",
"Return Fields": "Champs de retour",
"Entity ID": "ID de l'entité",
"Publish after Creating": "Publier après la création",
"Fields": "Champs",
"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)",
"The query formula to use to search for records. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters for more information": "La formule de requête à utiliser pour rechercher des enregistrements. Voir https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters pour plus d'informations",
"The maximum number of records to return": "Le nombre maximum d'enregistrements à retourner",
"The number of records to skip": "Le nombre d'enregistrements à ignorer",
"Number of levels to include for entries and assets. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links": "Nombre de niveaux à inclure pour les entrées et les actifs. Voir https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links",
"The fields to return for each record.": "Les champs à retourner pour chaque enregistrement.",
"The ID of the record to get.": "L'ID de l'enregistrement à obtenir.",
"Whether or not to publish this record after creating it.": "Si oui ou non publier cet enregistrement après l'avoir créé.",
"Fields for Content Model": "Champs pour le modèle de contenu",
"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"
}

View File

@@ -0,0 +1,47 @@
{
"Content infrastructure for digital teams": "デジタルチームのためのコンテンツインフラストラクチャ",
"Contentful Access Token": "Contentful Access Token",
"Space": "スペース",
"Environment": "環境",
"Search Records": "レコードを検索",
"Get Record": "レコードを取得",
"Create Record": "レコードを作成",
"Custom API Call": "カスタムAPI通話",
"Searches for records of a given Content Model": "指定されたコンテンツモデルのレコードを検索",
"Gets a Contentful record for a given Content Model": "与えられたコンテンツモデルのコンテンツフルレコードを取得します",
"Creates a new Contentful record for a given Content Model": "与えられたコンテンツモデルの新しいコンテンツフルレコードを作成します",
"Make a custom API call to a specific endpoint": "特定のエンドポイントへのカスタム API コールを実行します。",
"Content Model": "コンテンツ モデル",
"Content Locale": "コンテンツの言語",
"Query Formula": "数式をクエリ",
"Limit": "制限",
"Skip": "スキップ",
"Relationship Include Depth": "深さを含む関係",
"Return Fields": "返品フィールド",
"Entity ID": "エンティティID",
"Publish after Creating": "作成後に公開",
"Fields": "フィールド",
"Method": "方法",
"Headers": "ヘッダー",
"Query Parameters": "クエリパラメータ",
"Body": "本文",
"Response is Binary ?": "応答はバイナリですか?",
"No Error on Failure": "失敗時にエラーはありません",
"Timeout (in seconds)": "タイムアウト(秒)",
"The query formula to use to search for records. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters for more information": "レコードを検索するために使用するクエリ式。詳細については、https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters を参照してください。",
"The maximum number of records to return": "返却するレコードの最大数",
"The number of records to skip": "スキップするレコード数",
"Number of levels to include for entries and assets. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links": "Number of levels to include for entries and assets. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links",
"The fields to return for each record.": "各レコードに戻る項目。",
"The ID of the record to get.": "取得するレコードのID。",
"Whether or not to publish this record after creating it.": "作成後にこのレコードを公開するかどうか。",
"Fields for Content Model": "コンテンツ モデルのフィールド",
"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": "頭"
}

View File

@@ -0,0 +1,47 @@
{
"Content infrastructure for digital teams": "Infrastructuur voor digitale teams",
"Contentful Access Token": "Contentatieve Toegangstoken",
"Space": "Spatiebalk",
"Environment": "Milieu",
"Search Records": "Records zoeken",
"Get Record": "Krijg Record",
"Create Record": "Record Maken",
"Custom API Call": "Custom API Call",
"Searches for records of a given Content Model": "Zoekt naar records van een bepaald inhoudsmodel",
"Gets a Contentful record for a given Content Model": "Haalt een inhoudsbestand op voor een bepaald inhoudsmodel",
"Creates a new Contentful record for a given Content Model": "Maakt een nieuw Contentful Record voor een bepaald Content Model",
"Make a custom API call to a specific endpoint": "Maak een aangepaste API call naar een specifiek eindpunt",
"Content Model": "Inhoud model",
"Content Locale": "Lokalisatie inhoud",
"Query Formula": "Formule zoeken",
"Limit": "Limiet",
"Skip": "Overslaan",
"Relationship Include Depth": "Relatie met diepte",
"Return Fields": "velden retourneren",
"Entity ID": "Entiteit ID",
"Publish after Creating": "Publiceer na aanmaken",
"Fields": "Velden",
"Method": "Methode",
"Headers": "Kopteksten",
"Query Parameters": "Query parameters",
"Body": "Lichaam",
"Response is Binary ?": "Antwoord is binair?",
"No Error on Failure": "Geen fout bij fout",
"Timeout (in seconds)": "Time-out (in seconden)",
"The query formula to use to search for records. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters for more information": "De query formule om te zoeken naar records. Zie https://www.contentful.com/developers/docences/content-delivery-api/#/reference/search-parameters voor meer informatie",
"The maximum number of records to return": "Het maximum aantal terug te sturen records",
"The number of records to skip": "Het aantal overgeslagen records",
"Number of levels to include for entries and assets. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links": "Aantal niveaus op te nemen voor items en assets. Zie https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resourced-resourced-links",
"The fields to return for each record.": "De velden om weer te geven voor elk record.",
"The ID of the record to get.": "Het ID van het record om te krijgen.",
"Whether or not to publish this record after creating it.": "Of dit record moet worden gepubliceerd na het aanmaken ervan.",
"Fields for Content Model": "Velden voor inhoudsmodel",
"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"
}

View File

@@ -0,0 +1,47 @@
{
"Content infrastructure for digital teams": "Infraestrutura de conteúdo para equipes digitais",
"Contentful Access Token": "Token de Acesso Contentful",
"Space": "Sala",
"Environment": "Seguros",
"Search Records": "Buscar Registros",
"Get Record": "Obter Registro",
"Create Record": "Criar Registro",
"Custom API Call": "Chamada de API personalizada",
"Searches for records of a given Content Model": "Procura por registros de um determinado Modelo de Conteúdo",
"Gets a Contentful record for a given Content Model": "Obtém um registro de conteúdo para um determinado Modelo de Conteúdo",
"Creates a new Contentful record for a given Content Model": "Cria um novo registro de Conteúdo para um determinado Modelo de Conteúdo",
"Make a custom API call to a specific endpoint": "Faça uma chamada de API personalizada para um ponto de extremidade específico",
"Content Model": "Modelo de Conteúdo",
"Content Locale": "Localidade do Conteúdo",
"Query Formula": "Fórmula de consulta",
"Limit": "Limitar",
"Skip": "Ignorar",
"Relationship Include Depth": "Profundidade do Relacionamento Incluir",
"Return Fields": "Campos de Devolução",
"Entity ID": "ID da entidade",
"Publish after Creating": "Publicar depois de Criar",
"Fields": "campos",
"Method": "Método",
"Headers": "Cabeçalhos",
"Query Parameters": "Parâmetros da consulta",
"Body": "Conteúdo",
"Response is Binary ?": "A resposta é binária ?",
"No Error on Failure": "Nenhum erro no Failure",
"Timeout (in seconds)": "Tempo limite (em segundos)",
"The query formula to use to search for records. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters for more information": "A fórmula de consulta a ser usada para pesquisar registros. Consulte https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search parameters para obter mais informações",
"The maximum number of records to return": "O número máximo de registros para retornar",
"The number of records to skip": "O número de registros a ignorar",
"Number of levels to include for entries and assets. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links": "Número de níveis a incluir para entradas e ativos. Veja https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links",
"The fields to return for each record.": "Os campos a retornar para cada registro",
"The ID of the record to get.": "A ID do registro a ser obtido.",
"Whether or not to publish this record after creating it.": "Se deve ou não publicar este registro após a criação.",
"Fields for Content Model": "Campos para Modelo de Conteúdo",
"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"
}

View File

@@ -0,0 +1,46 @@
{
"Contentful": "Содержимое",
"Content infrastructure for digital teams": "Инфраструктура контента для цифровых команд",
"Contentful Access Token": "Токен контентного доступа",
"Space": "Пространство",
"Environment": "Среда",
"Search Records": "Поиск записей",
"Get Record": "Получить запись",
"Create Record": "Создать запись",
"Custom API Call": "Пользовательский вызов API",
"Searches for records of a given Content Model": "Поиск записей заданной модели содержимого",
"Gets a Contentful record for a given Content Model": "Получает содержательную запись для данной модели содержимого",
"Creates a new Contentful record for a given Content Model": "Создает новую Содержательную запись для данной модели контента",
"Make a custom API call to a specific endpoint": "Сделать пользовательский API вызов к определенной конечной точке",
"Content Model": "Модель контента",
"Content Locale": "Язык контента",
"Query Formula": "Формула запроса",
"Limit": "Лимит",
"Skip": "Пропустить",
"Relationship Include Depth": "Взаимосвязь с Глубиной",
"Return Fields": "Поля возврата",
"Entity ID": "ID сущности",
"Publish after Creating": "Опубликовать после создания",
"Fields": "Поля",
"Method": "Метод",
"Headers": "Заголовки",
"Query Parameters": "Параметры запроса",
"Body": "Тело",
"No Error on Failure": "Нет ошибок при ошибке",
"Timeout (in seconds)": "Таймаут (в секундах)",
"The query formula to use to search for records. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters for more information": "Формула запроса, используемая для поиска записей. Смотрите https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters для получения дополнительной информации",
"The maximum number of records to return": "Максимальное количество записей для возврата",
"The number of records to skip": "Количество пропущенных записей",
"Number of levels to include for entries and assets. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links": "Количество уровней для отображения записей и активов. См. https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links",
"The fields to return for each record.": "Поля для возврата к каждой записи.",
"The ID of the record to get.": "ID получаемой записи.",
"Whether or not to publish this record after creating it.": "Опубликовать ли эту запись после ее создания.",
"Fields for Content Model": "Поля для модели содержимого",
"Authorization headers are injected automatically from your connection.": "Заголовки авторизации включаются автоматически из вашего соединения.",
"GET": "ПОЛУЧИТЬ",
"POST": "ПОСТ",
"PATCH": "ПАТЧ",
"PUT": "ПОКУПИТЬ",
"DELETE": "УДАЛИТЬ",
"HEAD": "HEAD"
}

View File

@@ -0,0 +1,47 @@
{
"Content infrastructure for digital teams": "Content infrastructure for digital teams",
"Contentful Access Token": "Contentful Access Token",
"Space": "Space",
"Environment": "Environment",
"Search Records": "Search Records",
"Get Record": "Get Record",
"Create Record": "Create Record",
"Custom API Call": "Custom API Call",
"Searches for records of a given Content Model": "Searches for records of a given Content Model",
"Gets a Contentful record for a given Content Model": "Gets a Contentful record for a given Content Model",
"Creates a new Contentful record for a given Content Model": "Creates a new Contentful record for a given Content Model",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Content Model": "Content Model",
"Content Locale": "Content Locale",
"Query Formula": "Query Formula",
"Limit": "Limit",
"Skip": "Skip",
"Relationship Include Depth": "Relationship Include Depth",
"Return Fields": "Return Fields",
"Entity ID": "Entity ID",
"Publish after Creating": "Publish after Creating",
"Fields": "Fields",
"Method": "Method",
"Headers": "Headers",
"Query Parameters": "Query Parameters",
"Body": "Body",
"Response is Binary ?": "Response is Binary ?",
"No Error on Failure": "No Error on Failure",
"Timeout (in seconds)": "Timeout (in seconds)",
"The query formula to use to search for records. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters for more information": "The query formula to use to search for records. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters for more information",
"The maximum number of records to return": "The maximum number of records to return",
"The number of records to skip": "The number of records to skip",
"Number of levels to include for entries and assets. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links": "Number of levels to include for entries and assets. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links",
"The fields to return for each record.": "The fields to return for each record.",
"The ID of the record to get.": "The ID of the record to get.",
"Whether or not to publish this record after creating it.": "Whether or not to publish this record after creating it.",
"Fields for Content Model": "Fields for Content Model",
"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"
}

View File

@@ -0,0 +1,46 @@
{
"Contentful": "Contentful",
"Content infrastructure for digital teams": "Content infrastructure for digital teams",
"Contentful Access Token": "Contentful Access Token",
"Space": "Space",
"Environment": "Environment",
"Search Records": "Search Records",
"Get Record": "Get Record",
"Create Record": "Create Record",
"Custom API Call": "Custom API Call",
"Searches for records of a given Content Model": "Searches for records of a given Content Model",
"Gets a Contentful record for a given Content Model": "Gets a Contentful record for a given Content Model",
"Creates a new Contentful record for a given Content Model": "Creates a new Contentful record for a given Content Model",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Content Model": "Content Model",
"Content Locale": "Content Locale",
"Query Formula": "Query Formula",
"Limit": "Limit",
"Skip": "Skip",
"Relationship Include Depth": "Relationship Include Depth",
"Return Fields": "Return Fields",
"Entity ID": "Entity ID",
"Publish after Creating": "Publish after Creating",
"Fields": "Fields",
"Method": "Method",
"Headers": "Headers",
"Query Parameters": "Query Parameters",
"Body": "Body",
"No Error on Failure": "No Error on Failure",
"Timeout (in seconds)": "Timeout (in seconds)",
"The query formula to use to search for records. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters for more information": "The query formula to use to search for records. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters for more information",
"The maximum number of records to return": "The maximum number of records to return",
"The number of records to skip": "The number of records to skip",
"Number of levels to include for entries and assets. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links": "Number of levels to include for entries and assets. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links",
"The fields to return for each record.": "The fields to return for each record.",
"The ID of the record to get.": "The ID of the record to get.",
"Whether or not to publish this record after creating it.": "Whether or not to publish this record after creating it.",
"Fields for Content Model": "Fields for Content Model",
"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"
}

View File

@@ -0,0 +1,47 @@
{
"Content infrastructure for digital teams": "Content infrastructure for digital teams",
"Contentful Access Token": "Contentful Access Token",
"Space": "Space",
"Environment": "Environment",
"Search Records": "Search Records",
"Get Record": "Get Record",
"Create Record": "Create Record",
"Custom API Call": "自定义 API 呼叫",
"Searches for records of a given Content Model": "Searches for records of a given Content Model",
"Gets a Contentful record for a given Content Model": "Gets a Contentful record for a given Content Model",
"Creates a new Contentful record for a given Content Model": "Creates a new Contentful record for a given Content Model",
"Make a custom API call to a specific endpoint": "将一个自定义 API 调用到一个特定的终点",
"Content Model": "Content Model",
"Content Locale": "Content Locale",
"Query Formula": "Query Formula",
"Limit": "Limit",
"Skip": "Skip",
"Relationship Include Depth": "Relationship Include Depth",
"Return Fields": "Return Fields",
"Entity ID": "Entity ID",
"Publish after Creating": "Publish after Creating",
"Fields": "Fields",
"Method": "方法",
"Headers": "信头",
"Query Parameters": "查询参数",
"Body": "正文内容",
"Response is Binary ?": "Response is Binary ?",
"No Error on Failure": "失败时没有错误",
"Timeout (in seconds)": "超时(秒)",
"The query formula to use to search for records. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters for more information": "The query formula to use to search for records. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters for more information",
"The maximum number of records to return": "The maximum number of records to return",
"The number of records to skip": "The number of records to skip",
"Number of levels to include for entries and assets. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links": "Number of levels to include for entries and assets. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links",
"The fields to return for each record.": "The fields to return for each record.",
"The ID of the record to get.": "The ID of the record to get.",
"Whether or not to publish this record after creating it.": "Whether or not to publish this record after creating it.",
"Fields for Content Model": "Fields for Content Model",
"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": "黑色"
}

View File

@@ -0,0 +1,33 @@
import { createCustomApiCallAction } from '@activepieces/pieces-common';
import { createPiece } from '@activepieces/pieces-framework';
import { PieceCategory } from '@activepieces/shared';
import {
ContentfulCreateRecordAction,
ContentfulGetRecordAction,
ContentfulSearchRecordsAction,
} from './lib/actions/records';
import { ContentfulAuth } from './lib/common';
export const contentful = createPiece({
displayName: 'Contentful',
description: 'Content infrastructure for digital teams',
auth: ContentfulAuth,
minimumSupportedRelease: '0.30.0',
logoUrl: 'https://cdn.activepieces.com/pieces/contentful.png',
categories: [PieceCategory.MARKETING],
authors: ["cyrilselasi","kishanprmr","MoShizzle","abuaboud"],
actions: [
ContentfulSearchRecordsAction,
ContentfulGetRecordAction,
ContentfulCreateRecordAction,
createCustomApiCallAction({
baseUrl: () => `https://api.contentful.com`,
auth: ContentfulAuth,
authMapping: async (auth) => ({
Authorization: `Bearer ${auth.props.apiKey}`,
}),
}),
],
triggers: [],
});

View File

@@ -0,0 +1 @@
export * as RecordActions from './records';

View File

@@ -0,0 +1,73 @@
import {
DynamicPropsValue,
Property,
createAction,
} from '@activepieces/pieces-framework';
import { ContentfulAuth, PropertyKeys, makeClient } from '../../common';
import { ContentfulProperty } from '../../properties';
import { FieldProcessors } from '../../properties/processors';
function keyBy<T>(array: T[], key: keyof T): { [key: string]: T } {
return (array || []).reduce((result, item) => {
const keyValue = key ? item[key] : (item as unknown as string);
result[keyValue as unknown as string] = item;
return result;
}, {} as { [key: string]: T });
}
export const ContentfulCreateRecordAction = createAction({
name: 'contentful_record_create',
auth: ContentfulAuth,
displayName: 'Create Record',
description: 'Creates a new Contentful record for a given Content Model',
props: {
[PropertyKeys.LOCALE]: ContentfulProperty.Locale,
[PropertyKeys.CONTENT_MODEL]: ContentfulProperty.ContentModel,
[PropertyKeys.PUBLISH_ON_CREATE]: Property.Checkbox({
displayName: 'Publish after Creating',
required: true,
description: 'Whether or not to publish this record after creating it.',
defaultValue: false,
}),
[PropertyKeys.FIELDS]: ContentfulProperty.DynamicFields,
},
async run({ auth, propsValue }) {
const { client } = makeClient(auth);
const model = await client.contentType.get({
contentTypeId: propsValue[PropertyKeys.CONTENT_MODEL] as string,
});
const fields = keyBy(model.fields, 'id');
const values = propsValue[PropertyKeys.FIELDS] as DynamicPropsValue;
// Remove empty fields
for (const key in values) {
if (
values[key] === '' ||
values[key] === null ||
values[key] === undefined ||
(Array.isArray(values[key]) && values[key].length === 0)
) {
delete values[key];
continue;
}
const fieldType = fields[key].type;
const processor = FieldProcessors[fieldType] || FieldProcessors['Basic'];
values[key] = {
[propsValue[PropertyKeys.LOCALE] as string]: await processor(
fields[key],
values[key]
),
};
}
console.debug('Creating record with values', values);
const record = await client.entry.create(
{ contentTypeId: model.sys.id },
{ fields: values }
);
if (propsValue[PropertyKeys.PUBLISH_ON_CREATE]) {
await client.entry.publish({ entryId: record.sys.id }, record);
}
return record;
},
});

View File

@@ -0,0 +1,22 @@
import { Property, createAction } from '@activepieces/pieces-framework';
import { ContentfulAuth, PropertyKeys, makeClient } from '../../common';
export const ContentfulGetRecordAction = createAction({
name: 'contentful_record_get',
auth: ContentfulAuth,
displayName: 'Get Record',
description: 'Gets a Contentful record for a given Content Model',
props: {
[PropertyKeys.ENTITY_ID]: Property.ShortText({
displayName: 'Entity ID',
required: true,
description: 'The ID of the record to get.',
}),
},
async run({ auth, propsValue }) {
const { client } = makeClient(auth);
return await client.entry.get({
entryId: propsValue[PropertyKeys.ENTITY_ID] as string,
});
},
});

View File

@@ -0,0 +1,3 @@
export * from './create-record';
export * from './search-records';
export * from './get-record';

View File

@@ -0,0 +1,65 @@
import {
Property,
createAction,
} from '@activepieces/pieces-framework';
import { ContentfulAuth, PropertyKeys, makeClient } from '../../common';
import { ContentfulProperty } from '../../properties';
import { z } from 'zod';
import { propsValidation } from '@activepieces/pieces-common';
export const ContentfulSearchRecordsAction = createAction({
name: 'contentful_record_search',
auth: ContentfulAuth,
displayName: 'Search Records',
description: 'Searches for records of a given Content Model',
props: {
[PropertyKeys.CONTENT_MODEL]: ContentfulProperty.ContentModel,
[PropertyKeys.LOCALE]: ContentfulProperty.Locale,
[PropertyKeys.QUERY]: Property.Json({
required: true,
defaultValue: {},
displayName: 'Query Formula',
description:
'The query formula to use to search for records. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters for more information',
}),
[PropertyKeys.QUERY_LIMIT]: Property.Number({
displayName: 'Limit',
description: 'The maximum number of records to return',
required: false,
defaultValue: 10,
}),
[PropertyKeys.QUERY_SKIP]: Property.Number({
displayName: 'Skip',
description: 'The number of records to skip',
required: false,
defaultValue: 0,
}),
[PropertyKeys.QUERY_INCLUDE]: Property.Number({
displayName: 'Relationship Include Depth',
description:
'Number of levels to include for entries and assets. See https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links/retrieval-of-linked-resource-links',
defaultValue: 1,
required: false,
}),
[PropertyKeys.QUERY_SELECT]: ContentfulProperty.SelectFields,
},
async run({ auth, propsValue }) {
await propsValidation.validateZod(propsValue, {
[PropertyKeys.QUERY_INCLUDE]: z.number().min(1),
});
const { client } = makeClient(auth);
const select =
(propsValue[PropertyKeys.QUERY_SELECT] as string[]) || undefined;
return client.entry.getMany({
query: {
...(propsValue[PropertyKeys.QUERY] as any),
limit: (propsValue[PropertyKeys.QUERY_LIMIT] as number) || 10,
skip: (propsValue[PropertyKeys.QUERY_SKIP] as number) || 0,
content_type: propsValue[PropertyKeys.CONTENT_MODEL] as string,
include: (propsValue[PropertyKeys.QUERY_INCLUDE] as number) || 1,
select: select?.join(','),
},
});
},
});

View File

@@ -0,0 +1,25 @@
import { PieceAuth, Property } from '@activepieces/pieces-framework';
export interface ContentfulAuth {
apiKey: string;
environment: string;
space: string;
}
export const ContentfulAuth = PieceAuth.CustomAuth({
required: true,
props: {
apiKey: Property.ShortText({
displayName: 'Contentful Access Token',
required: true,
}),
space: Property.ShortText({
displayName: 'Space',
required: true,
}),
environment: Property.ShortText({
displayName: 'Environment',
required: true,
}),
},
});

View File

@@ -0,0 +1,15 @@
import { AppConnectionValueForAuthProperty } from '@activepieces/pieces-framework';
import { ContentfulAuth } from './auth';
import * as Contentful from 'contentful-management';
export const makeClient = (auth: AppConnectionValueForAuthProperty<typeof ContentfulAuth>) => {
return {
client: Contentful.createClient(
{ accessToken: auth.props.apiKey },
{
type: 'plain',
defaults: { spaceId: auth.props.space, environmentId: auth.props.environment },
}
),
};
};

View File

@@ -0,0 +1,13 @@
export const PropertyKeys = {
CONTENT_MODEL: 'contentModel',
FIELDS: 'fields',
PUBLISH_ON_CREATE: 'publishOnCreate',
LOCALE: 'locale',
ENTITY_ID: 'entityId',
SEARCH_FIELDS: 'searchFields',
QUERY: 'query',
QUERY_LIMIT: 'limit',
QUERY_SKIP: 'skip',
QUERY_INCLUDE: 'include',
QUERY_SELECT: 'select',
};

View File

@@ -0,0 +1,4 @@
export * from './auth';
export * from './client';
export * from './constants';
export * from './utils';

View File

@@ -0,0 +1,14 @@
import { camelCase, startCase } from '@activepieces/shared';
import { ContentFields } from 'contentful-management';
export const getLinkHelperText = (
validations: ContentFields['validations']
) => {
const mimes: string[] =
validations?.find((v) => v['linkMimetypeGroup'])?.['linkMimetypeGroup'] ||
[];
const entryTypes: string[] =
validations?.find((v) => v['linkContentType'])?.['linkContentType'] || [];
const parts: string[] = [...mimes, ...entryTypes];
return startCase(camelCase(parts.join(',')));
};

View File

@@ -0,0 +1,58 @@
import { DropdownOption, Property } from '@activepieces/pieces-framework';
import { ContentfulAuth, makeClient } from '../common';
import { isEmpty } from '@activepieces/shared';
const ContentModel = Property.Dropdown({
auth: ContentfulAuth,
displayName: 'Content Model',
required: true,
refreshers: [],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account',
};
}
const { client } = makeClient(auth);
try {
const models: DropdownOption<string>[] = [];
let contentModels = await client.contentType.getMany({
query: { limit: 1000 },
});
models.push(
...contentModels.items.map((model) => ({
value: model.sys.id,
label: model.name,
}))
);
while (contentModels.skip + contentModels.limit < contentModels.total) {
contentModels = await client.contentType.getMany({
query: { skip: contentModels.skip + contentModels.limit },
});
models.push(
...contentModels.items.map((model) => ({
value: model.sys.id,
label: model.name,
}))
);
}
return {
disabled: false,
options: models.sort((a, b) =>
a.label < b.label ? -1 : a.label > b.label ? 1 : 0
),
};
} catch (e) {
console.debug(e);
return {
disabled: true,
options: [],
placeholder: 'Please check your Contentful connection settings',
};
}
},
});
export default ContentModel;

View File

@@ -0,0 +1,53 @@
import { DynamicPropsValue, Property } from '@activepieces/pieces-framework';
import { ContentfulAuth, PropertyKeys, makeClient } from '../common';
import { FieldTransformers } from './transformers';
import { FieldType } from 'contentful-management';
import { isEmpty, isNil } from '@activepieces/shared';
const DynamicFields = Property.DynamicProperties({
auth: ContentfulAuth,
displayName: 'Fields',
description: 'Fields for Content Model',
required: true,
refreshers: [PropertyKeys.CONTENT_MODEL, PropertyKeys.LOCALE],
props: async ({
auth,
[PropertyKeys.CONTENT_MODEL]: model,
[PropertyKeys.LOCALE]: locale,
}) => {
if (isEmpty(auth) || !auth || isNil(model)) return {};
const dynamicFields: DynamicPropsValue = {};
const { client } = makeClient(auth);
try {
const contentModel = await client.contentType.get({
contentTypeId: model as unknown as string,
});
// Remove fields that are disabled or omitted from the API
contentModel.fields
.filter((f) => !!f.id && !f.omitted && !f.disabled && !f.deleted)
.map((f) => {
const transformer = FieldTransformers[f.type as FieldType['type']];
if (transformer) {
const property = transformer(f);
if (!property) return;
dynamicFields[f.id] = {
...property,
defaultValue: f.defaultValue?.[locale as unknown as string],
};
return;
}
dynamicFields[f.id] = Property.ShortText({
displayName: f.name,
required: f.required,
description: 'Unsupported Field Type',
defaultValue: f.defaultValue?.[locale as unknown as string],
});
});
} catch (e) {
console.debug(e);
}
return dynamicFields;
},
});
export default DynamicFields;

View File

@@ -0,0 +1,11 @@
import ContentModel from './content-model';
import DynamicFields from './dynamic-fields';
import Locale from './locale';
import SelectFields from './select-fields';
export const ContentfulProperty = {
ContentModel,
DynamicFields,
Locale,
SelectFields,
};

View File

@@ -0,0 +1,39 @@
import { DropdownOption, Property } from '@activepieces/pieces-framework';
import { ContentfulAuth, makeClient } from '../common';
import { isEmpty } from '@activepieces/shared';
const Locale = Property.Dropdown({
auth: ContentfulAuth,
displayName: 'Content Locale',
required: true,
refreshers: [],
options: async ({ auth }) => {
if (isEmpty(auth) || !auth) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account',
};
}
const { client } = makeClient(auth);
try {
const response = await client.locale.getMany({});
const options: DropdownOption<string>[] = response.items.map(
(locale) => ({ label: locale.name, value: locale.code })
);
return {
disabled: false,
options,
};
} catch (e) {
console.debug(e);
return {
disabled: true,
options: [],
placeholder: 'Please check your Contentful connection settings',
};
}
},
});
export default Locale;

View File

@@ -0,0 +1,30 @@
import { ContentFields } from 'contentful-management';
type FieldProcessor = (field: ContentFields, value: any) => any;
export const FieldProcessors: Record<string, FieldProcessor> = {
Link: (field, value) => {
return {
sys: {
type: 'Link',
linkType: field.linkType,
id: value,
},
};
},
Array: (field, value) => {
if (field.items?.type === 'Symbol') {
return value;
}
if (field.items?.type === 'Link') {
return value.map((v: string) => ({
sys: {
type: 'Link',
linkType: field.items?.linkType,
id: v,
},
}));
}
},
Basic: (field, value) => value,
};

View File

@@ -0,0 +1,39 @@
import { DropdownState, Property } from '@activepieces/pieces-framework';
import { ContentfulAuth, PropertyKeys, makeClient } from '../common';
import { isEmpty, isNil } from '@activepieces/shared';
const SelectFields = Property.MultiSelectDropdown({
displayName: 'Return Fields',
auth: ContentfulAuth,
description: 'The fields to return for each record.',
refreshers: [PropertyKeys.CONTENT_MODEL],
required: false,
options: async ({ auth, [PropertyKeys.CONTENT_MODEL]: model }) => {
const searchFields: DropdownState<string> = {
options: [],
disabled: true,
placeholder: '',
};
if (isEmpty(auth) || !auth || isNil(model)) return searchFields;
try {
const { client } = makeClient(auth);
const contentType = await client.contentType.get({
contentTypeId: model as unknown as string,
});
// Process available options
searchFields.options = contentType.fields
.filter((f) => !!f.id && !f.omitted && !f.disabled && !f.deleted)
.map((f) => ({ label: f.name as string, value: `fields.${f.id}` }));
searchFields.disabled = false;
searchFields.placeholder = 'Select fields to return';
} catch (e) {
console.debug(e);
}
return searchFields;
},
});
export default SelectFields;

View File

@@ -0,0 +1,157 @@
import {
ArrayProperty,
BasePropertySchema,
CheckboxProperty,
DateTimeProperty,
DropdownOption,
LongTextProperty,
NumberProperty,
ObjectProperty,
Property,
ShortTextProperty,
} from '@activepieces/pieces-framework';
import { ContentFields, FieldType } from 'contentful-management';
import { getLinkHelperText } from '../common';
type Properties<T> = Omit<
T,
| 'valueSchema'
| 'type'
| 'defaultValidators'
| 'defaultProcessors'
| 'required'
| 'displayName'
>;
const evalAndConvertToStaticDropDown = <T extends string | number>(
field: ContentFields
) => {
const options: DropdownOption<T>[] = [];
if (field.validations) {
field.validations.forEach((v) => {
if (v['in']) {
options.push(
...v['in'].map((o) => ({ label: o.toString(), value: o as T }))
);
}
});
}
if (options.length > 0) {
return Property.StaticDropdown<T>({
displayName: field.name,
required: field.required,
options: {
disabled: false,
placeholder: 'Select an option',
options,
},
});
}
return null;
};
const ShortTextTransformer =
(request: Properties<ShortTextProperty<true>> = {}) =>
(field: ContentFields) => {
const isDropdown = evalAndConvertToStaticDropDown<string>(field);
if (isDropdown) return isDropdown;
return Property.ShortText({
...request,
displayName: field.name,
required: field.required,
});
};
const LongTextTransformer =
(request: Properties<LongTextProperty<true>> = {}) =>
(field: ContentFields) =>
Property.LongText({
...request,
displayName: field.name,
required: field.required,
});
const NumberTransformer =
(request: Properties<NumberProperty<true>> = {}) =>
(field: ContentFields) => {
const isDrowdown = evalAndConvertToStaticDropDown<number>(field);
if (isDrowdown) return isDrowdown;
return Property.Number({
...request,
displayName: field.name,
required: field.required,
});
};
const DateTimeTransformer =
(request: Properties<DateTimeProperty<true>> = {}) =>
(field: ContentFields) => {
return Property.DateTime({
...request,
displayName: field.name,
required: field.required,
});
};
const CheckboxTransformer =
(request: Properties<CheckboxProperty<true>> = {}) =>
(field: ContentFields) =>
Property.Checkbox({
...request,
displayName: field.name,
required: field.required,
});
const ObjectTransformer =
(request: Properties<ObjectProperty<true>> = {}) =>
(field: ContentFields) =>
Property.Object({
...request,
displayName: field.name,
required: field.required,
});
const LinkTransformer =
(request: Properties<ShortTextProperty<true>> = {}) =>
(field: ContentFields) => {
const prefix = field.linkType || field.type || '';
const helperText = getLinkHelperText(field.validations);
return ShortTextTransformer({
...request,
description: `${prefix}: ${helperText || 'Any'}`,
})(field);
};
const ArrayTransformer =
(request: Properties<ArrayProperty<true>> = {}) =>
(field: ContentFields) => {
const prefix = field.items?.linkType || field.items?.type || '';
const helperText = getLinkHelperText(field.items?.validations);
return Property.Array({
...request,
displayName: field.name,
required: field.required,
description: `${prefix}: ${helperText || 'Any'}`,
});
};
type Transformer = (field: ContentFields) => BasePropertySchema | null;
export const FieldTransformers: Record<FieldType['type'], Transformer> = {
Symbol: ShortTextTransformer({}),
Text: LongTextTransformer({}),
RichText: LongTextTransformer(),
Integer: NumberTransformer({}),
Number: NumberTransformer(),
Date: DateTimeTransformer(),
Boolean: CheckboxTransformer(),
Object: ObjectTransformer(),
Location: ObjectTransformer(),
Link: LinkTransformer(),
ResourceLink: LinkTransformer(),
Array: ArrayTransformer(),
};