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

View File

@@ -0,0 +1,10 @@
{
"name": "@activepieces/piece-capsule-crm",
"version": "0.0.2",
"type": "commonjs",
"main": "./src/index.js",
"types": "./src/index.d.ts",
"dependencies": {
"tslib": "^2.3.0"
}
}

View File

@@ -0,0 +1,65 @@
{
"name": "pieces-capsule-crm",
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/pieces/community/capsule-crm/src",
"projectType": "library",
"release": {
"version": {
"manifestRootsToUpdate": [
"dist/{projectRoot}"
],
"currentVersionResolver": "git-tag",
"fallbackCurrentVersionResolver": "disk"
}
},
"tags": [],
"targets": {
"build": {
"executor": "@nx/js:tsc",
"outputs": [
"{options.outputPath}"
],
"options": {
"outputPath": "dist/packages/pieces/community/capsule-crm",
"tsConfig": "packages/pieces/community/capsule-crm/tsconfig.lib.json",
"packageJson": "packages/pieces/community/capsule-crm/package.json",
"main": "packages/pieces/community/capsule-crm/src/index.ts",
"assets": [
"packages/pieces/community/capsule-crm/*.md",
{
"input": "packages/pieces/community/capsule-crm/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/capsule-crm",
"command": "bun install --no-save --silent"
},
"dependsOn": [
"^build"
]
}
}
}

View File

@@ -0,0 +1,118 @@
{
"\n To authenticate with Capsule CRM:\n 1. Go to your Capsule CRM user settings.\n 2. Navigate to \"My Preferences\" > \"API Authentication Tokens\".\n 3. Register a new application to get a Client ID and Client Secret.\n 4. Add https://cloud.activepieces.com/redirect to the authorized redirect URIs.\n 5. Use the OAuth2 flow below.": "\n Zur Authentifizierung mit Capsule CRM:\n 1. Gehen Sie zu Ihren Capsule CRM Benutzereinstellungen.\n 2. Navigieren Sie zu \"Meine Einstellungen\" > \"API-Authentifizierungs-Tokens\".\n 3. Registrieren Sie eine neue Anwendung, um eine Client ID und Client Secret zu erhalten.\n 4. Fügen Sie https://cloud hinzu. ctivepieces.com/redirect zu den autorisierten Weiterleitungs-URIs.\n 5. Verwenden Sie den OAuth2-Fluss unten.",
"Create Contact": "Kontakt erstellen",
"Update Contact": "Kontakt aktualisieren",
"Create Opportunity": "Verkaufschance erstellen",
"Create Project": "Projekt erstellen",
"Create Task": "Aufgabe erstellen",
"Update Opportunity": "Update-Verkaufschance",
"Add Note to Entity": "Notiz zu Entität hinzufügen",
"Find Contact": "Kontakt finden",
"Find Project": "Projekt finden",
"Find Opportunity": "Verkaufschance suchen",
"Create a new Person or Organisation in Capsule CRM.": "Erstellen Sie eine neue Person oder Organisation in Capsule CRM.",
"Update fields on an existing Person or Organisation.": "Felder einer bestehenden Person oder Organisation aktualisieren.",
"Create a new Opportunity in Capsule CRM.": "Erstellen Sie eine neue Verkaufschance in Capsule CRM.",
"Create a new Project in Capsule CRM.": "Erstellen Sie ein neues Projekt in Capsule CRM.",
"Create a new Task in Capsule CRM.": "Erstellen Sie eine neue Aufgabe in Capsule CRM.",
"Update an existing Opportunity in Capsule CRM.": "Aktualisieren Sie eine vorhandene Verkaufschance in Capsule CRM.",
"Add a comment/note to an entity (e.g., contact, opportunity, project).": "Kommentar/Notiz zu einer Entität hinzufügen (z. B. Kontakt, Chance, Projekt).",
"Find a Person by search criteria.": "Finden Sie eine Person nach Suchkriterien.",
"Find a Project by search criteria.": "Suchen Sie ein Projekt nach Suchkriterien.",
"Find an Opportunity by search criteria.": "Finden Sie eine Verkaufschance anhand von Suchkriterien.",
"Contact Type": "Kontakttyp",
"Details": "Details",
"About": "Über",
"Owner": "Besitzer",
"Team": "Team",
"Tags": "Tags",
"Custom Fields": "Eigene Felder",
"Email Addresses": "E-Mail-Adressen",
"Phone Numbers": "Telefonnummern",
"Addresses": "Adressen",
"Websites": "Webseiten",
"Contact": "Kontakt",
"Party": "Gruppe",
"Name": "Name",
"Description": "Beschreibung",
"Milestone": "Meilenstein",
"Currency": "Währung",
"Amount": "Betrag",
"Expected Close Date": "Erwartetes Enddatum",
"Probability": "Wahrscheinlichkeit",
"Duration Basis": "Dauer",
"Duration": "Dauer",
"Opportunity": "Verkaufschance",
"Stage": "Teil",
"Status": "Status",
"Due Date": "Fälligkeitsdatum",
"Due Time": "Fällige Zeit",
"Link To": "Link zu",
"Linked Entity": "Verknüpfte Entität",
"Category": "Kategorie",
"Note Content": "Notiz Inhalt",
"Entity Type": "Entitätstyp",
"Entity": "Entität",
"Activity Type": "Aktivitätstyp",
"Search Term": "Suchbegriff",
"Filter": "Filtern",
"The type of contact to create.": "Die Art des zu erstellenden Kontakts.",
"The contact (Person or Organisation) to select.": "Der zu wählende Kontakt (Person oder Organisation).",
"The user to assign the task to.": "Der Benutzer, dem die Aufgabe zugewiesen wird.",
"The team to assign the contact to.": "Das Team, dem der Kontakt zugewiesen werden soll.",
"Update the biography or description for the contact.": "Aktualisieren Sie die Biographie oder Beschreibung für den Kontakt.",
"A short description of the opportunity.": "Eine kurze Beschreibung der Möglichkeit.",
"More details about the opportunity.": "Mehr Details zur Chance.",
"The currency for the opportunity value (e.g., USD, GBP).": "Die Währung für den Opportunity-Wert (z.B. USD, GBP).",
"The numerical value of the opportunity.": "Der numerische Wert der Chance.",
"The expected closing date for the opportunity.": "Das erwartete Enddatum für die Chance.",
"The probability of winning the opportunity.": "Die Wahrscheinlichkeit, die Chance zu gewinnen.",
"The basis of the duration of the opportunity.": "Die Grundlage für die Dauer der Möglichkeit.",
"The duration of the opportunity.": "Die Dauer der Möglichkeit.",
"The user the opportunity is assigned to.": "Der Benutzer, dem die Chance zugewiesen wurde.",
"The team the opportunity is assigned to.": "Das Team, dem die Gelegenheit zugewiesen ist.",
"The main contact for this project.": "Der Hauptkontakt für dieses Projekt.",
"The name of this project.": "Der Name dieses Projekts.",
"The description of this project.": "Die Beschreibung dieses Projekts.",
"An optional link to the opportunity that this project was created to support.": "Ein optionaler Link zu der Möglichkeit, die dieses Projekt zur Unterstützung erstellt hat.",
"The stage that this project is on.": "Die Phase, in der sich dieses Projekt befindet.",
"The status of the project.": "Der Status des Projekts.",
"The expected close date of this project.": "Das erwartete Enddatum dieses Projekts.",
"The user this project is assigned to.": "Der Benutzer, dem dieses Projekt zugewiesen ist.",
"The team this project is assigned to.": "Das Team, dem dieses Projekt zugewiesen ist.",
"An array of tags that are added to this project.": "Ein Array von Tags, die diesem Projekt hinzugefügt werden.",
"An array of custom fields that are defined for this project.": "Ein Array von benutzerdefinierten Feldern, die für dieses Projekt definiert sind.",
"A short description of the task.": "Eine kurze Beschreibung der Aufgabe.",
"The date when this task is due.": "Das Datum, an dem diese Aufgabe fällig ist.",
"More details about the task.": "Mehr Details zur Aufgabe.",
"The time when this task is due (e.g., 18:00:00). Note: The time is in the user's timezone.": "Die Zeit, zu der diese Aufgabe fällig ist (z.B. 18:00:00). Hinweis: Die Zeit ist in der Zeitzone des Benutzers.",
"The entity this task is linked to. Only one can be selected.": "Die Entität, mit der diese Aufgabe verknüpft ist. Nur eine kann ausgewählt werden.",
"The category of this task.": "Die Kategorie dieser Aufgabe.",
"The user this task is assigned to.": "Der Benutzer, dem diese Aufgabe zugewiesen ist.",
"The body of the note.": "Der Text der Notiz.",
"The type of entity to add the note to.": "Der Typ der Entität, der die Notiz hinzugefügt werden soll.",
"The activity type for this entry. Defaults to \"Note\".": "Der Aktivitätstyp für diesen Eintrag. Standard ist \"Notiz\".",
"The value to search for (e.g., a name or email).": "Der zu suchende Wert (z.B. Name oder E-Mail).",
"The structured filter query. See the [documentation](https://capsulecrm.com/developer/api-v2/filters/) for examples.": "Die strukturierte Filterabfrage. Siehe die [documentation](https://capsulecrm.com/developer/api-v2/filters/) für Beispiele.",
"Person": "Person",
"Organisation": "Organisation",
"Fixed": "Feste",
"Hour": "Stunde",
"Day": "Tag",
"Week": "Woche",
"Month": "Monat",
"Quarter": "Quartal",
"Year": "Jahr",
"Open": "Öffnen",
"Closed": "Geschlossen",
"Party (Contact)": "Gruppe (Kontakt)",
"Project": "Projekt",
"New Case": "Neuer Fall",
"New Opportunity": "Neue Verkaufschance",
"New Task": "Neue Aufgabe",
"New Project": "Neues Projekt",
"Fires when a new case (project) is created in Capsule CRM.": "Feuert ab, wenn ein neuer Fall (Projekt) in Capsule CRM erstellt wird.",
"Fires when a new opportunity is created.": "Feuert ab, wenn eine neue Chance geschaffen wird.",
"Fires when a new task is created.": "Feuert ab, wenn eine neue Aufgabe erstellt wird.",
"Fires when a project is created.": "Feuert ab, wenn ein Projekt erstellt wird."
}

View File

@@ -0,0 +1,118 @@
{
"\n To authenticate with Capsule CRM:\n 1. Go to your Capsule CRM user settings.\n 2. Navigate to \"My Preferences\" > \"API Authentication Tokens\".\n 3. Register a new application to get a Client ID and Client Secret.\n 4. Add https://cloud.activepieces.com/redirect to the authorized redirect URIs.\n 5. Use the OAuth2 flow below.": "\n To authenticate with Capsule CRM:\n 1. Go to your Capsule CRM user settings.\n 2. Navigate to \"My Preferences\" > \"API Authentication Tokens\".\n 3. Register a new application to get a Client ID and Client Secret.\n 4. Add https://cloud.activepieces.com/redirect to the authorized redirect URIs.\n 5. Use the OAuth2 flow below.",
"Create Contact": "Crear contacto",
"Update Contact": "Actualizar contacto",
"Create Opportunity": "Crear Oportunidad",
"Create Project": "Crear proyecto",
"Create Task": "Crear tarea",
"Update Opportunity": "Actualizar Oportunidad",
"Add Note to Entity": "Añadir Nota a Entidad",
"Find Contact": "Encontrar contacto",
"Find Project": "Buscar proyecto",
"Find Opportunity": "Buscar Oportunidad",
"Create a new Person or Organisation in Capsule CRM.": "Crear una nueva persona u organización en Capsule CRM.",
"Update fields on an existing Person or Organisation.": "Actualizar campos en una persona u organización existente.",
"Create a new Opportunity in Capsule CRM.": "Crear una nueva oportunidad en Cápsula CRM.",
"Create a new Project in Capsule CRM.": "Crear un nuevo proyecto en Cápsula CRM.",
"Create a new Task in Capsule CRM.": "Crear una nueva tarea en Cápsula CRM.",
"Update an existing Opportunity in Capsule CRM.": "Actualizar una Oportunidad existente en Cápsula CRM.",
"Add a comment/note to an entity (e.g., contact, opportunity, project).": "Añadir un comentario/nota a una entidad (por ejemplo, contacto, oportunidad, proyecto).",
"Find a Person by search criteria.": "Encuentre una Persona por criterios de búsqueda.",
"Find a Project by search criteria.": "Buscar un proyecto por criterios de búsqueda.",
"Find an Opportunity by search criteria.": "Encuentre una Oportunidad por criterios de búsqueda.",
"Contact Type": "Tipo de contacto",
"Details": "Detalles",
"About": "Acerca de",
"Owner": "Propietario",
"Team": "Equipo",
"Tags": "Etiquetas",
"Custom Fields": "Campos personalizados",
"Email Addresses": "Direcciones de email",
"Phone Numbers": "Números de teléfono",
"Addresses": "Direcciones",
"Websites": "Sitios web",
"Contact": "Contacto",
"Party": "Fiesta",
"Name": "Nombre",
"Description": "Descripción",
"Milestone": "Hito",
"Currency": "Moneda",
"Amount": "Cantidad",
"Expected Close Date": "Fecha de cierre esperada",
"Probability": "Probabilidad",
"Duration Basis": "Duración base",
"Duration": "Duración",
"Opportunity": "Oportunidad",
"Stage": "Etapa",
"Status": "Estado",
"Due Date": "Fecha de fin",
"Due Time": "Hora límite",
"Link To": "Enlace a",
"Linked Entity": "Entidad vinculada",
"Category": "Categoría",
"Note Content": "Contenido de Nota",
"Entity Type": "Tipo de entidad",
"Entity": "Entidad",
"Activity Type": "Tipo de actividad",
"Search Term": "Buscar término",
"Filter": "Filtro",
"The type of contact to create.": "El tipo de contacto a crear.",
"The contact (Person or Organisation) to select.": "El contacto (Persona u Organización) para seleccionar.",
"The user to assign the task to.": "El usuario al que asignar la tarea.",
"The team to assign the contact to.": "El equipo al que asignar el contacto.",
"Update the biography or description for the contact.": "Actualizar la biografía o descripción del contacto.",
"A short description of the opportunity.": "Una breve descripción de la oportunidad.",
"More details about the opportunity.": "Más detalles sobre la oportunidad.",
"The currency for the opportunity value (e.g., USD, GBP).": "La moneda para el valor de oportunidad (por ejemplo, USD, GBP).",
"The numerical value of the opportunity.": "El valor numérico de la oportunidad.",
"The expected closing date for the opportunity.": "La fecha de cierre prevista para la oportunidad.",
"The probability of winning the opportunity.": "La probabilidad de ganar la oportunidad.",
"The basis of the duration of the opportunity.": "La base de la duración de la oportunidad.",
"The duration of the opportunity.": "La duración de la oportunidad.",
"The user the opportunity is assigned to.": "El usuario al que se ha asignado la oportunidad.",
"The team the opportunity is assigned to.": "El equipo al que se ha asignado la oportunidad.",
"The main contact for this project.": "El contacto principal para este proyecto.",
"The name of this project.": "El nombre de este proyecto.",
"The description of this project.": "La descripción de este proyecto.",
"An optional link to the opportunity that this project was created to support.": "Un enlace opcional a la oportunidad que este proyecto fue creado para apoyar.",
"The stage that this project is on.": "La fase en la que se encuentra este proyecto.",
"The status of the project.": "El estado del proyecto.",
"The expected close date of this project.": "La fecha prevista de cierre de este proyecto.",
"The user this project is assigned to.": "El usuario al que este proyecto está asignado.",
"The team this project is assigned to.": "El equipo al que este proyecto está asignado.",
"An array of tags that are added to this project.": "Un array de etiquetas que se añaden a este proyecto.",
"An array of custom fields that are defined for this project.": "Un array de campos personalizados que están definidos para este proyecto.",
"A short description of the task.": "Una breve descripción de la tarea.",
"The date when this task is due.": "La fecha en que esta tarea es vencida.",
"More details about the task.": "Más detalles sobre la tarea.",
"The time when this task is due (e.g., 18:00:00). Note: The time is in the user's timezone.": "El tiempo en que esta tarea es debido (por ejemplo, 18:00:00). Nota: La hora está en la zona horaria del usuario.",
"The entity this task is linked to. Only one can be selected.": "La entidad a la que esta tarea está vinculada. Sólo una puede ser seleccionada.",
"The category of this task.": "La categoría de esta tarea.",
"The user this task is assigned to.": "El usuario al que esta tarea está asignada.",
"The body of the note.": "El cuerpo de la nota.",
"The type of entity to add the note to.": "El tipo de entidad a la que agregar la nota.",
"The activity type for this entry. Defaults to \"Note\".": "El tipo de actividad para esta entrada. Por defecto es \"Nota\".",
"The value to search for (e.g., a name or email).": "El valor a buscar (por ejemplo, un nombre o correo electrónico).",
"The structured filter query. See the [documentation](https://capsulecrm.com/developer/api-v2/filters/) for examples.": "La consulta de filtro estructurado. Vea la [documentation](https://capsulecrm.com/developer/api-v2/filters/) para ver ejemplos.",
"Person": "Persona",
"Organisation": "Organisation",
"Fixed": "Fijado",
"Hour": "Hora",
"Day": "Día",
"Week": "Semana",
"Month": "Mes",
"Quarter": "Triturador",
"Year": "Año",
"Open": "Abrir",
"Closed": "Cerrado",
"Party (Contact)": "Fiesta (Contacto)",
"Project": "Projekt",
"New Case": "Nuevo Caso",
"New Opportunity": "Nueva oportunidad",
"New Task": "Nueva tarea",
"New Project": "Nuevo proyecto",
"Fires when a new case (project) is created in Capsule CRM.": "Dispara cuando se crea un nuevo caso (proyecto) en Cápsula CRM.",
"Fires when a new opportunity is created.": "Dispara cuando se crea una nueva oportunidad.",
"Fires when a new task is created.": "Dispara cuando se crea una nueva tarea.",
"Fires when a project is created.": "Dispara cuando se crea un proyecto."
}

View File

@@ -0,0 +1,118 @@
{
"\n To authenticate with Capsule CRM:\n 1. Go to your Capsule CRM user settings.\n 2. Navigate to \"My Preferences\" > \"API Authentication Tokens\".\n 3. Register a new application to get a Client ID and Client Secret.\n 4. Add https://cloud.activepieces.com/redirect to the authorized redirect URIs.\n 5. Use the OAuth2 flow below.": "\n To authenticate with Capsule CRM:\n 1. Go to your Capsule CRM user settings.\n 2. Navigate to \"My Preferences\" > \"API Authentication Tokens\".\n 3. Register a new application to get a Client ID and Client Secret.\n 4. Add https://cloud.activepieces.com/redirect to the authorized redirect URIs.\n 5. Use the OAuth2 flow below.",
"Create Contact": "Créer un contact",
"Update Contact": "Mettre à jour le contact",
"Create Opportunity": "Créer une Affaire",
"Create Project": "Créer un projet",
"Create Task": "Créer une tâche",
"Update Opportunity": "Mettre à jour l'Affaire",
"Add Note to Entity": "Ajouter une note à l'entité",
"Find Contact": "Trouver un contact",
"Find Project": "Trouver un projet",
"Find Opportunity": "Trouver une opportunité",
"Create a new Person or Organisation in Capsule CRM.": "Créer une nouvelle Personne ou Organisation dans Capsule CRM.",
"Update fields on an existing Person or Organisation.": "Mettre à jour les champs sur une personne ou une organisation existante.",
"Create a new Opportunity in Capsule CRM.": "Créer une nouvelle opportunité dans Capsule CRM.",
"Create a new Project in Capsule CRM.": "Créer un nouveau projet dans Capsule CRM.",
"Create a new Task in Capsule CRM.": "Créer une nouvelle tâche dans Capsule CRM.",
"Update an existing Opportunity in Capsule CRM.": "Mettre à jour une opportunité existante dans Capsule CRM.",
"Add a comment/note to an entity (e.g., contact, opportunity, project).": "Ajouter un commentaire/note à une entité (par exemple, contact, opportunité, projet).",
"Find a Person by search criteria.": "Trouver une personne par critère de recherche.",
"Find a Project by search criteria.": "Trouver un projet par critères de recherche.",
"Find an Opportunity by search criteria.": "Trouver une Opportunité par critères de recherche.",
"Contact Type": "Type de contact",
"Details": "Détails",
"About": "À propos de",
"Owner": "Propriétaire",
"Team": "Équipe",
"Tags": "Tags",
"Custom Fields": "Champs personnalisés",
"Email Addresses": "Adresses e-mail",
"Phone Numbers": "Numéros de téléphone",
"Addresses": "Adresses",
"Websites": "Sites web",
"Contact": "Contacter",
"Party": "Soirée",
"Name": "Nom",
"Description": "Libellé",
"Milestone": "Jalon",
"Currency": "Devise",
"Amount": "Montant",
"Expected Close Date": "Date de clôture prévue",
"Probability": "Probabilité",
"Duration Basis": "Durée de la base",
"Duration": "Durée",
"Opportunity": "Opportunité",
"Stage": "Étape",
"Status": "Statut",
"Due Date": "Date de fin",
"Due Time": "Heure d'échéance",
"Link To": "Lien vers",
"Linked Entity": "Entité liée",
"Category": "Catégorie",
"Note Content": "Contenu de la note",
"Entity Type": "Type d'entité",
"Entity": "Entité",
"Activity Type": "Type d'activité",
"Search Term": "Terme de recherche",
"Filter": "Filtre",
"The type of contact to create.": "Le type de contact à créer.",
"The contact (Person or Organisation) to select.": "Le contact (Personne ou Organisation) à sélectionner.",
"The user to assign the task to.": "L'utilisateur à assigner la tâche.",
"The team to assign the contact to.": "L'équipe à laquelle il faut assigner le contact.",
"Update the biography or description for the contact.": "Mettre à jour la biographie ou la description du contact.",
"A short description of the opportunity.": "Une courte description de l'opportunité.",
"More details about the opportunity.": "Plus de détails sur l'opportunité.",
"The currency for the opportunity value (e.g., USD, GBP).": "La devise de la valeur de l'opportunité (par exemple, USD, GBP).",
"The numerical value of the opportunity.": "La valeur numérique de l'opportunité.",
"The expected closing date for the opportunity.": "La date de clôture prévue pour l'occasion.",
"The probability of winning the opportunity.": "La probabilité de gagner l'occasion.",
"The basis of the duration of the opportunity.": "La base de la durée de l'opportunité.",
"The duration of the opportunity.": "La durée de l'opportunité.",
"The user the opportunity is assigned to.": "L'utilisateur auquel cette opportunité est assignée.",
"The team the opportunity is assigned to.": "Léquipe à laquelle cette opportunité est assignée.",
"The main contact for this project.": "Le contact principal pour ce projet.",
"The name of this project.": "Le nom de ce projet.",
"The description of this project.": "La description de ce projet.",
"An optional link to the opportunity that this project was created to support.": "Un lien facultatif vers l'opportunité que ce projet a été créé pour soutenir.",
"The stage that this project is on.": "Le stade où ce projet est en cours.",
"The status of the project.": "Le statut du projet.",
"The expected close date of this project.": "La date de clôture prévue de ce projet.",
"The user this project is assigned to.": "L'utilisateur auquel ce projet est assigné.",
"The team this project is assigned to.": "L'équipe à laquelle ce projet est assigné.",
"An array of tags that are added to this project.": "Un tableau de balises qui sont ajoutées à ce projet.",
"An array of custom fields that are defined for this project.": "Un tableau de champs personnalisés qui sont définis pour ce projet.",
"A short description of the task.": "Une courte description de la tâche.",
"The date when this task is due.": "La date à laquelle cette tâche est due.",
"More details about the task.": "Plus de détails sur la tâche.",
"The time when this task is due (e.g., 18:00:00). Note: The time is in the user's timezone.": "L'heure à laquelle cette tâche est due (par exemple, 18:00:00). Note: L'heure est dans le fuseau horaire de l'utilisateur.",
"The entity this task is linked to. Only one can be selected.": "L'entité à laquelle cette tâche est liée. Une seule peut être sélectionnée.",
"The category of this task.": "La catégorie de cette tâche.",
"The user this task is assigned to.": "L'utilisateur auquel cette tâche est assignée.",
"The body of the note.": "Le corps de la note.",
"The type of entity to add the note to.": "Le type d'entité auquel ajouter la note.",
"The activity type for this entry. Defaults to \"Note\".": "Le type d'activité pour cette entrée. Par défaut, \"Note\".",
"The value to search for (e.g., a name or email).": "La valeur à rechercher (par exemple, un nom ou un e-mail).",
"The structured filter query. See the [documentation](https://capsulecrm.com/developer/api-v2/filters/) for examples.": "La requête de filtre structuré. Voir la [documentation](https://capsulecrm.com/developer/api-v2/filters/) pour des exemples.",
"Person": "Personne",
"Organisation": "Organisation",
"Fixed": "Fixe",
"Hour": "Heure",
"Day": "Jour",
"Week": "Semaine",
"Month": "Mois",
"Quarter": "Trimestre",
"Year": "Année",
"Open": "Ouvert",
"Closed": "Fermé",
"Party (Contact)": "Groupe (Contact)",
"Project": "Votre compte",
"New Case": "Nouveau Cas",
"New Opportunity": "Nouvelle opportunité",
"New Task": "Nouvelle tâche",
"New Project": "Nouveau projet",
"Fires when a new case (project) is created in Capsule CRM.": "Se déclenche lorsqu'un nouveau cas (projet) est créé dans Capsule CRM.",
"Fires when a new opportunity is created.": "Tire quand une nouvelle opportunité est créée.",
"Fires when a new task is created.": "Tire quand une nouvelle tâche est créée.",
"Fires when a project is created.": "Se déclenche lorsqu'un projet est créé."
}

View File

@@ -0,0 +1,118 @@
{
"\n To authenticate with Capsule CRM:\n 1. Go to your Capsule CRM user settings.\n 2. Navigate to \"My Preferences\" > \"API Authentication Tokens\".\n 3. Register a new application to get a Client ID and Client Secret.\n 4. Add https://cloud.activepieces.com/redirect to the authorized redirect URIs.\n 5. Use the OAuth2 flow below.": "\n To authenticate with Capsule CRM:\n 1. Go to your Capsule CRM user settings.\n 2. Navigate to \"My Preferences\" > \"API Authentication Tokens\".\n 3. Register a new application to get a Client ID and Client Secret.\n 4. Add https://cloud.activepieces.com/redirect to the authorized redirect URIs.\n 5. Use the OAuth2 flow below.",
"Create Contact": "連絡先を作成",
"Update Contact": "連絡先を更新",
"Create Opportunity": "案件を作成",
"Create Project": "プロジェクトを作成",
"Create Task": "タスクを作成",
"Update Opportunity": "商談を更新",
"Add Note to Entity": "エンティティにメモを追加",
"Find Contact": "連絡先を探す",
"Find Project": "プロジェクトを検索",
"Find Opportunity": "商談を探す",
"Create a new Person or Organisation in Capsule CRM.": "Capsule CRM に新しい人または組織を作成します。",
"Update fields on an existing Person or Organisation.": "既存の個人または組織のフィールドを更新します。",
"Create a new Opportunity in Capsule CRM.": "Capsule CRM に新しい機会を作成します。",
"Create a new Project in Capsule CRM.": "Capsule CRM に新しいプロジェクトを作成します。",
"Create a new Task in Capsule CRM.": "Capsule CRM に新しいタスクを作成します。",
"Update an existing Opportunity in Capsule CRM.": "Capsule CRM 内の既存の機会を更新します。",
"Add a comment/note to an entity (e.g., contact, opportunity, project).": "エンティティにコメント/メモを追加 (取引先責任者、商談、プロジェクトなど)。",
"Find a Person by search criteria.": "検索条件で人を検索します。",
"Find a Project by search criteria.": "検索条件でプロジェクトを検索します。",
"Find an Opportunity by search criteria.": "検索条件で商談を検索します。",
"Contact Type": "連絡先の種類",
"Details": "詳細",
"About": "About",
"Owner": "所有者",
"Team": "Team",
"Tags": "タグ",
"Custom Fields": "カスタムフィールド",
"Email Addresses": "メールアドレス",
"Phone Numbers": "電話番号",
"Addresses": "アドレス",
"Websites": "ウェブサイト",
"Contact": "お問い合わせ",
"Party": "パーティー",
"Name": "Name",
"Description": "説明",
"Milestone": "マイルストーン",
"Currency": "通貨",
"Amount": "金額",
"Expected Close Date": "終了予定日",
"Probability": "可能性",
"Duration Basis": "Duration Basis",
"Duration": "期間",
"Opportunity": "機会",
"Stage": "ステージ",
"Status": "Status",
"Due Date": "締切日",
"Due Time": "締切日時",
"Link To": "リンク先",
"Linked Entity": "リンクされたエンティティ",
"Category": "カテゴリ",
"Note Content": "ノートコンテンツ",
"Entity Type": "エンティティタイプ",
"Entity": "エンティティ",
"Activity Type": "活動タイプ",
"Search Term": "検索用語",
"Filter": "フィルター",
"The type of contact to create.": "作成する連絡先の種類",
"The contact (Person or Organisation) to select.": "選択する連絡先 (個人または組織) 。",
"The user to assign the task to.": "タスクを割り当てるユーザー",
"The team to assign the contact to.": "連絡先を割り当てるチーム。",
"Update the biography or description for the contact.": "連絡先の伝記または説明を更新します。",
"A short description of the opportunity.": "機会の簡単な説明。",
"More details about the opportunity.": "機会についての詳細。",
"The currency for the opportunity value (e.g., USD, GBP).": "商談値の通貨USD、GBP。",
"The numerical value of the opportunity.": "機会の数値。",
"The expected closing date for the opportunity.": "案件の終了予定日。",
"The probability of winning the opportunity.": "チャンスを勝ち取る確率。",
"The basis of the duration of the opportunity.": "機会の持続時間の基礎。",
"The duration of the opportunity.": "機会の持続時間。",
"The user the opportunity is assigned to.": "商談が割り当てられているユーザー。",
"The team the opportunity is assigned to.": "商談が割り当てられているチーム。",
"The main contact for this project.": "このプロジェクトの主な連絡先。",
"The name of this project.": "このプロジェクトの名前",
"The description of this project.": "このプロジェクトの説明",
"An optional link to the opportunity that this project was created to support.": "このプロジェクトをサポートするために作成された商談へのオプションのリンク。",
"The stage that this project is on.": "このプロジェクトが進行中の段階。",
"The status of the project.": "プロジェクトのステータス。",
"The expected close date of this project.": "このプロジェクトの終了予定日。",
"The user this project is assigned to.": "このプロジェクトに割り当てられているユーザー。",
"The team this project is assigned to.": "このプロジェクトに割り当てられているチーム",
"An array of tags that are added to this project.": "このプロジェクトに追加されたタグの配列。",
"An array of custom fields that are defined for this project.": "このプロジェクトで定義されているカスタムフィールドの配列。",
"A short description of the task.": "タスクの簡単な説明。",
"The date when this task is due.": "このタスクの期日です。",
"More details about the task.": "タスクの詳細。",
"The time when this task is due (e.g., 18:00:00). Note: The time is in the user's timezone.": "このタスクが期限切れの時刻(例:18:00)。注:時刻はユーザのタイムゾーンにあります。",
"The entity this task is linked to. Only one can be selected.": "このタスクがリンクされているエンティティ。1つだけ選択できます。",
"The category of this task.": "このタスクのカテゴリ",
"The user this task is assigned to.": "このタスクに割り当てられているユーザー。",
"The body of the note.": "メモの本文。",
"The type of entity to add the note to.": "メモを追加するエンティティの種類",
"The activity type for this entry. Defaults to \"Note\".": "このエントリのアクティビティタイプ。デフォルトは\"Note\"です。",
"The value to search for (e.g., a name or email).": "検索する値 (名前やメールなど)。",
"The structured filter query. See the [documentation](https://capsulecrm.com/developer/api-v2/filters/) for examples.": "構造化されたフィルタクエリ。例については、 [documentation](https://capsulecrm.com/developer/api-v2/filters/) を参照してください。",
"Person": "人",
"Organisation": "Organisation",
"Fixed": "固定",
"Hour": "時間",
"Day": "日",
"Week": "週",
"Month": "月",
"Quarter": "四半期ごと",
"Year": "年",
"Open": "開く",
"Closed": "クローズ済み",
"Party (Contact)": "パーティー (連絡先)",
"Project": "プロジェクト",
"New Case": "新規ケース",
"New Opportunity": "新しい機会",
"New Task": "新しいタスク",
"New Project": "新規プロジェクト",
"Fires when a new case (project) is created in Capsule CRM.": "Capsule CRM に新しいケース (プロジェクト) が作成されたときに発生します。",
"Fires when a new opportunity is created.": "新しい商談が作成されたときに発火します。",
"Fires when a new task is created.": "新しいタスクが作成されたときに発生します。",
"Fires when a project is created.": "プロジェクトが作成されたときに発生します。"
}

View File

@@ -0,0 +1,118 @@
{
"\n To authenticate with Capsule CRM:\n 1. Go to your Capsule CRM user settings.\n 2. Navigate to \"My Preferences\" > \"API Authentication Tokens\".\n 3. Register a new application to get a Client ID and Client Secret.\n 4. Add https://cloud.activepieces.com/redirect to the authorized redirect URIs.\n 5. Use the OAuth2 flow below.": "\n Om te verifiëren met Capsule CRM:\n 1. Ga naar uw Capsule CRM-instellingen.\n 2. Navigeer naar \"Mijn Voorkeuren\" > \"API Authenticatie Token\".\n 3. Een nieuwe applicatie registreren om een client-ID en client-geheim te krijgen.\n 4. Voeg https://cloud. ctivepieces.com/redirect naar de toegestane redirect URIs.\n 5. Gebruik de OAuth2 flow hieronder.",
"Create Contact": "Contactpersoon aanmaken",
"Update Contact": "Contactpersoon bijwerken",
"Create Opportunity": "Verkoopkans creëren",
"Create Project": "Project aanmaken",
"Create Task": "Taak maken",
"Update Opportunity": "Update Verkoopkans",
"Add Note to Entity": "Notitie toevoegen aan entiteit",
"Find Contact": "Contactpersoon zoeken",
"Find Project": "Project zoeken",
"Find Opportunity": "Zoek Opportunity",
"Create a new Person or Organisation in Capsule CRM.": "Maak een nieuwe persoon of organisatie aan in Capsule CRM.",
"Update fields on an existing Person or Organisation.": "Werk velden bij op een bestaande persoon of organisatie.",
"Create a new Opportunity in Capsule CRM.": "Maak een nieuwe kans in Capsule CRM.",
"Create a new Project in Capsule CRM.": "Maak een nieuw project aan in Capsule CRM.",
"Create a new Task in Capsule CRM.": "Maak een nieuwe taak in Capsule CRM.",
"Update an existing Opportunity in Capsule CRM.": "Update een bestaande Kans in Capsule CRM.",
"Add a comment/note to an entity (e.g., contact, opportunity, project).": "Voeg een reactie/opmerking toe aan een entiteit (bijv. contact, opportunity, project).",
"Find a Person by search criteria.": "Zoek een persoon op zoek criteria.",
"Find a Project by search criteria.": "Zoek een project op zoek criteria.",
"Find an Opportunity by search criteria.": "Vind een Mogelijkheid door zoekcriteria.",
"Contact Type": "Type contactpersoon",
"Details": "Beschrijving",
"About": "Informatie",
"Owner": "Eigenaar",
"Team": "Team",
"Tags": "Labels",
"Custom Fields": "Aangepaste velden",
"Email Addresses": "E-mail adressen",
"Phone Numbers": "Telefoon nummers",
"Addresses": "Adres",
"Websites": "Websites",
"Contact": "Contactpersoon",
"Party": "Feest",
"Name": "Naam",
"Description": "Beschrijving",
"Milestone": "Mijlpaal",
"Currency": "valuta",
"Amount": "Hoeveelheid",
"Expected Close Date": "Verwachte afsluitdatum",
"Probability": "Waarschijnlijkheid",
"Duration Basis": "Duur Basis",
"Duration": "Tijdsduur",
"Opportunity": "Kans",
"Stage": "Speelveld",
"Status": "status",
"Due Date": "Inleverdatum",
"Due Time": "Achterstallige tijd",
"Link To": "Link naar",
"Linked Entity": "Verbonden entiteit",
"Category": "categorie",
"Note Content": "Notitie inhoud",
"Entity Type": "Entiteit type",
"Entity": "Entiteit",
"Activity Type": "Type activiteit",
"Search Term": "Zoek term",
"Filter": "Filteren",
"The type of contact to create.": "Het type contact dat moet worden gemaakt.",
"The contact (Person or Organisation) to select.": "Het contact (Person of Organisatie) om te selecteren.",
"The user to assign the task to.": "De gebruiker waaraan de taak moet worden toegewezen.",
"The team to assign the contact to.": "Het team waaraan de contactpersoon wordt toegewezen.",
"Update the biography or description for the contact.": "Werk de biografie of beschrijving van de contactpersoon bij.",
"A short description of the opportunity.": "Een korte beschrijving van de kans.",
"More details about the opportunity.": "Meer details over deze mogelijkheid.",
"The currency for the opportunity value (e.g., USD, GBP).": "De valuta voor de kanswaarde (bijv. USD, GBP).",
"The numerical value of the opportunity.": "De numerieke waarde van de kans.",
"The expected closing date for the opportunity.": "De verwachte sluitingsdatum voor deze mogelijkheid.",
"The probability of winning the opportunity.": "De kans is groot dat we deze kans zullen krijgen.",
"The basis of the duration of the opportunity.": "De basis voor de duur van de mogelijkheid.",
"The duration of the opportunity.": "De duur van de mogelijkheid.",
"The user the opportunity is assigned to.": "De gebruiker waaraan de kans is toegewezen.",
"The team the opportunity is assigned to.": "Het team waaraan de kans is toegewezen.",
"The main contact for this project.": "Het hoofdcontact voor dit project.",
"The name of this project.": "De naam van dit project.",
"The description of this project.": "De beschrijving van dit project.",
"An optional link to the opportunity that this project was created to support.": "Een facultatieve link naar de mogelijkheid die dit project werd gecreëerd om te ondersteunen.",
"The stage that this project is on.": "De fase waarin dit project zich bevindt.",
"The status of the project.": "De status van het project.",
"The expected close date of this project.": "De verwachte sluitingsdatum van dit project.",
"The user this project is assigned to.": "De gebruiker aan dit project is toegewezen.",
"The team this project is assigned to.": "Het team waaraan dit project is toegewezen.",
"An array of tags that are added to this project.": "Een reeks tags die worden toegevoegd aan dit project.",
"An array of custom fields that are defined for this project.": "Een reeks aangepaste velden die zijn gedefinieerd voor dit project.",
"A short description of the task.": "Een korte beschrijving van de taak.",
"The date when this task is due.": "De datum waarop deze taak afgelopen is.",
"More details about the task.": "Meer details over de taak.",
"The time when this task is due (e.g., 18:00:00). Note: The time is in the user's timezone.": "De tijd waarin deze taak afgerond moet zijn (bijv. 18:00:00). Opmerking: De tijd ligt in de tijdzone van de gebruiker.",
"The entity this task is linked to. Only one can be selected.": "De entiteit waaraan deze taak is gekoppeld. Er kan maar één geselecteerd worden.",
"The category of this task.": "De categorie van deze taak.",
"The user this task is assigned to.": "De gebruiker waaraan deze taak is toegewezen.",
"The body of the note.": "De body van de notitie.",
"The type of entity to add the note to.": "Het type entiteit waaraan de notitie toe te voegen",
"The activity type for this entry. Defaults to \"Note\".": "Het activiteitstype voor deze invoer. Standaard ingesteld op \"Opmerking\".",
"The value to search for (e.g., a name or email).": "De waarde waarnaar gezocht moet worden (bijv. een naam of e-mail).",
"The structured filter query. See the [documentation](https://capsulecrm.com/developer/api-v2/filters/) for examples.": "De gestructureerde filter query. Zie de [documentation](https://capsulecrm.com/developer/api-v2/filters/) voor voorbeelden.",
"Person": "Persoon",
"Organisation": "Organisation",
"Fixed": "Opgelost",
"Hour": "Uur",
"Day": "dag",
"Week": "week",
"Month": "maand",
"Quarter": "Kwartaal",
"Year": "jaar",
"Open": "Open",
"Closed": "gesloten",
"Party (Contact)": "Partij (contact)",
"Project": "Project",
"New Case": "Nieuwe Geval",
"New Opportunity": "Nieuwe kans",
"New Task": "Nieuwe taak",
"New Project": "Nieuw project",
"Fires when a new case (project) is created in Capsule CRM.": "Vuurt wanneer een nieuw geval (project) is gemaakt in Capsule CRM.",
"Fires when a new opportunity is created.": "Vuurt af wanneer een nieuwe kans wordt gecreëerd.",
"Fires when a new task is created.": "Vuurt af wanneer een nieuwe taak is aangemaakt.",
"Fires when a project is created.": "Vuurt wanneer een project wordt aangemaakt."
}

View File

@@ -0,0 +1,118 @@
{
"\n To authenticate with Capsule CRM:\n 1. Go to your Capsule CRM user settings.\n 2. Navigate to \"My Preferences\" > \"API Authentication Tokens\".\n 3. Register a new application to get a Client ID and Client Secret.\n 4. Add https://cloud.activepieces.com/redirect to the authorized redirect URIs.\n 5. Use the OAuth2 flow below.": "\n Para autenticar com CRM em Capsula:\n 1. Vá para suas configurações de usuário em Capsula CRM.\n 2. Navegue até \"Minhas preferências\" > \"Tokens de Autenticação API\".\n 3. Registre um novo aplicativo para obter um Client ID e Client Secret.\n 4. Adicione https://cloud. ctivepieces.com/redirect para os URIs de redirecionamento autorizados.\n 5. Use o fluxo OAuth2 abaixo.",
"Create Contact": "Criar contato",
"Update Contact": "Atualizar contato",
"Create Opportunity": "Criar Oportunidade",
"Create Project": "Criar Projeto",
"Create Task": "Criar tarefa",
"Update Opportunity": "Atualizar Oportunidade",
"Add Note to Entity": "Adicionar Nota à Entidade",
"Find Contact": "Localizar contato",
"Find Project": "Localizar projeto",
"Find Opportunity": "Encontrar Oportunidade",
"Create a new Person or Organisation in Capsule CRM.": "Criar uma nova Pessoa ou Organização em Capsule CRM.",
"Update fields on an existing Person or Organisation.": "Atualizar campos para uma Pessoa ou Organização existente.",
"Create a new Opportunity in Capsule CRM.": "Criar uma nova Oportunidade em Capsule CRM.",
"Create a new Project in Capsule CRM.": "Criar um novo projeto no CRM de Cápsula.",
"Create a new Task in Capsule CRM.": "Criar uma nova Tarefa em Capsule CRM.",
"Update an existing Opportunity in Capsule CRM.": "Atualizar uma Oportunidade existente em Capsule CRM.",
"Add a comment/note to an entity (e.g., contact, opportunity, project).": "Adicionar um comentário/nota a uma entidade (por exemplo, contato, oportunidade, projeto).",
"Find a Person by search criteria.": "Encontre uma pessoa usando critérios de pesquisa.",
"Find a Project by search criteria.": "Encontre um projeto com critérios de pesquisa.",
"Find an Opportunity by search criteria.": "Encontrar uma oportunidade por critérios de busca.",
"Contact Type": "Tipo de contato",
"Details": "detalhes",
"About": "SOBRE",
"Owner": "Proprietário",
"Team": "Equipe",
"Tags": "Etiquetas",
"Custom Fields": "Campos Personalizados",
"Email Addresses": "Endereços de e-mail",
"Phone Numbers": "Números de telefone",
"Addresses": "Endereços",
"Websites": "Sites",
"Contact": "contato",
"Party": "Festa",
"Name": "Nome",
"Description": "Descrição",
"Milestone": "Marco",
"Currency": "moeda",
"Amount": "Quantidade",
"Expected Close Date": "Data de fechamento esperada",
"Probability": "Probabilidade",
"Duration Basis": "Duração da Base",
"Duration": "Duração",
"Opportunity": "Oportunidade",
"Stage": "Etapa",
"Status": "Estado",
"Due Date": "Data de vencimento",
"Due Time": "Hora-Limite",
"Link To": "Link para",
"Linked Entity": "Entidade vinculada",
"Category": "categoria",
"Note Content": "Conteúdo da Nota",
"Entity Type": "Tipo de entidade",
"Entity": "Entidade",
"Activity Type": "Tipo de Atividade",
"Search Term": "Termo para pesquisa",
"Filter": "filtro",
"The type of contact to create.": "O tipo de contato para criar.",
"The contact (Person or Organisation) to select.": "O contato (Pessoa ou Organização) para selecionar.",
"The user to assign the task to.": "O usuário para atribuir a tarefa.",
"The team to assign the contact to.": "A equipe para atribuir o contato.",
"Update the biography or description for the contact.": "Atualize a biografia ou a descrição do contato.",
"A short description of the opportunity.": "Uma breve descrição da oportunidade.",
"More details about the opportunity.": "Mais detalhes sobre a oportunidade.",
"The currency for the opportunity value (e.g., USD, GBP).": "A moeda para o valor de oportunidade (por exemplo, USD, GBP).",
"The numerical value of the opportunity.": "O valor numérico da oportunidade.",
"The expected closing date for the opportunity.": "A data esperada de encerramento da oportunidade.",
"The probability of winning the opportunity.": "A probabilidade de ganhar a oportunidade.",
"The basis of the duration of the opportunity.": "A base da duração da oportunidade.",
"The duration of the opportunity.": "A duração da oportunidade.",
"The user the opportunity is assigned to.": "O usuário à qual a oportunidade é atribuída.",
"The team the opportunity is assigned to.": "A equipe à qual a oportunidade foi atribuída.",
"The main contact for this project.": "O contato principal para este projeto.",
"The name of this project.": "O nome deste projeto.",
"The description of this project.": "A descrição deste projeto.",
"An optional link to the opportunity that this project was created to support.": "Um link opcional para a oportunidade que este projeto foi criado para apoiar.",
"The stage that this project is on.": "O estádio em que se encontra este projecto.",
"The status of the project.": "O status do projeto.",
"The expected close date of this project.": "A data esperada de fechamento deste projeto.",
"The user this project is assigned to.": "O usuário a quem este projeto está atribuído.",
"The team this project is assigned to.": "A equipe a qual este projeto está atribuído.",
"An array of tags that are added to this project.": "Uma matriz de tags que são adicionadas a este projeto.",
"An array of custom fields that are defined for this project.": "Um array de campos personalizados que são definidos para este projeto.",
"A short description of the task.": "Uma breve descrição da tarefa.",
"The date when this task is due.": "A data de término desta tarefa.",
"More details about the task.": "Mais detalhes sobre a tarefa.",
"The time when this task is due (e.g., 18:00:00). Note: The time is in the user's timezone.": "O horário em que esta tarefa é encerrada (por exemplo, 18:00:00). Nota: A hora está no fuso horário do usuário.",
"The entity this task is linked to. Only one can be selected.": "A entidade em que esta tarefa está vinculada. Apenas uma pode ser selecionada.",
"The category of this task.": "A categoria desta tarefa.",
"The user this task is assigned to.": "O usuário esta tarefa está atribuída.",
"The body of the note.": "O corpo da nota.",
"The type of entity to add the note to.": "O tipo de entidade a que adicionar a nota.",
"The activity type for this entry. Defaults to \"Note\".": "O tipo de atividade para esta entrada. O padrão é \"Nota\".",
"The value to search for (e.g., a name or email).": "O valor a pesquisar (por exemplo, um nome ou email)",
"The structured filter query. See the [documentation](https://capsulecrm.com/developer/api-v2/filters/) for examples.": "A consulta de filtro estruturada. Veja o [documentation](https://capsulecrm.com/developer/api-v2/filters/) para exemplos.",
"Person": "Pessoa",
"Organisation": "Organisation",
"Fixed": "Corrigido",
"Hour": "hora",
"Day": "dia",
"Week": "semana",
"Month": "Mês",
"Quarter": "Trimestre",
"Year": "ano",
"Open": "Abertas",
"Closed": "Fechado",
"Party (Contact)": "Grupo (Contato)",
"Project": "Projecto",
"New Case": "Nova Ocorrência",
"New Opportunity": "Nova Oportunidade",
"New Task": "Nova tarefa",
"New Project": "Novo Projeto",
"Fires when a new case (project) is created in Capsule CRM.": "Atira quando um novo caso (projeto) é criado no Capsule CRM.",
"Fires when a new opportunity is created.": "Atira quando uma nova oportunidade é criada.",
"Fires when a new task is created.": "Atira quando uma nova tarefa é criada.",
"Fires when a project is created.": "aciona quando um projeto é criado."
}

View File

@@ -0,0 +1,118 @@
{
"\n To authenticate with Capsule CRM:\n 1. Go to your Capsule CRM user settings.\n 2. Navigate to \"My Preferences\" > \"API Authentication Tokens\".\n 3. Register a new application to get a Client ID and Client Secret.\n 4. Add https://cloud.activepieces.com/redirect to the authorized redirect URIs.\n 5. Use the OAuth2 flow below.": "\n To authenticate with Capsule CRM:\n 1. Go to your Capsule CRM user settings.\n 2. Navigate to \"My Preferences\" > \"API Authentication Tokens\".\n 3. Register a new application to get a Client ID and Client Secret.\n 4. Add https://cloud.activepieces.com/redirect to the authorized redirect URIs.\n 5. Use the OAuth2 flow below.",
"Create Contact": "Create Contact",
"Update Contact": "Update Contact",
"Create Opportunity": "Create Opportunity",
"Create Project": "Create Project",
"Create Task": "Create Task",
"Update Opportunity": "Update Opportunity",
"Add Note to Entity": "Add Note to Entity",
"Find Contact": "Find Contact",
"Find Project": "Find Project",
"Find Opportunity": "Find Opportunity",
"Create a new Person or Organisation in Capsule CRM.": "Create a new Person or Organisation in Capsule CRM.",
"Update fields on an existing Person or Organisation.": "Update fields on an existing Person or Organisation.",
"Create a new Opportunity in Capsule CRM.": "Create a new Opportunity in Capsule CRM.",
"Create a new Project in Capsule CRM.": "Create a new Project in Capsule CRM.",
"Create a new Task in Capsule CRM.": "Create a new Task in Capsule CRM.",
"Update an existing Opportunity in Capsule CRM.": "Update an existing Opportunity in Capsule CRM.",
"Add a comment/note to an entity (e.g., contact, opportunity, project).": "Add a comment/note to an entity (e.g., contact, opportunity, project).",
"Find a Person by search criteria.": "Find a Person by search criteria.",
"Find a Project by search criteria.": "Find a Project by search criteria.",
"Find an Opportunity by search criteria.": "Find an Opportunity by search criteria.",
"Contact Type": "Contact Type",
"Details": "Details",
"About": "About",
"Owner": "Owner",
"Team": "Team",
"Tags": "Tags",
"Custom Fields": "Custom Fields",
"Email Addresses": "Email Addresses",
"Phone Numbers": "Phone Numbers",
"Addresses": "Addresses",
"Websites": "Websites",
"Contact": "Contact",
"Party": "Party",
"Name": "Name",
"Description": "Description",
"Milestone": "Milestone",
"Currency": "Currency",
"Amount": "Amount",
"Expected Close Date": "Expected Close Date",
"Probability": "Probability",
"Duration Basis": "Duration Basis",
"Duration": "Duration",
"Opportunity": "Opportunity",
"Stage": "Stage",
"Status": "Status",
"Due Date": "Due Date",
"Due Time": "Due Time",
"Link To": "Link To",
"Linked Entity": "Linked Entity",
"Category": "Category",
"Note Content": "Note Content",
"Entity Type": "Entity Type",
"Entity": "Entity",
"Activity Type": "Activity Type",
"Search Term": "Search Term",
"Filter": "Filter",
"The type of contact to create.": "The type of contact to create.",
"The contact (Person or Organisation) to select.": "The contact (Person or Organisation) to select.",
"The user to assign the task to.": "The user to assign the task to.",
"The team to assign the contact to.": "The team to assign the contact to.",
"Update the biography or description for the contact.": "Update the biography or description for the contact.",
"A short description of the opportunity.": "A short description of the opportunity.",
"More details about the opportunity.": "More details about the opportunity.",
"The currency for the opportunity value (e.g., USD, GBP).": "The currency for the opportunity value (e.g., USD, GBP).",
"The numerical value of the opportunity.": "The numerical value of the opportunity.",
"The expected closing date for the opportunity.": "The expected closing date for the opportunity.",
"The probability of winning the opportunity.": "The probability of winning the opportunity.",
"The basis of the duration of the opportunity.": "The basis of the duration of the opportunity.",
"The duration of the opportunity.": "The duration of the opportunity.",
"The user the opportunity is assigned to.": "The user the opportunity is assigned to.",
"The team the opportunity is assigned to.": "The team the opportunity is assigned to.",
"The main contact for this project.": "The main contact for this project.",
"The name of this project.": "The name of this project.",
"The description of this project.": "The description of this project.",
"An optional link to the opportunity that this project was created to support.": "An optional link to the opportunity that this project was created to support.",
"The stage that this project is on.": "The stage that this project is on.",
"The status of the project.": "The status of the project.",
"The expected close date of this project.": "The expected close date of this project.",
"The user this project is assigned to.": "The user this project is assigned to.",
"The team this project is assigned to.": "The team this project is assigned to.",
"An array of tags that are added to this project.": "An array of tags that are added to this project.",
"An array of custom fields that are defined for this project.": "An array of custom fields that are defined for this project.",
"A short description of the task.": "A short description of the task.",
"The date when this task is due.": "The date when this task is due.",
"More details about the task.": "More details about the task.",
"The time when this task is due (e.g., 18:00:00). Note: The time is in the user's timezone.": "The time when this task is due (e.g., 18:00:00). Note: The time is in the user's timezone.",
"The entity this task is linked to. Only one can be selected.": "The entity this task is linked to. Only one can be selected.",
"The category of this task.": "The category of this task.",
"The user this task is assigned to.": "The user this task is assigned to.",
"The body of the note.": "The body of the note.",
"The type of entity to add the note to.": "The type of entity to add the note to.",
"The activity type for this entry. Defaults to \"Note\".": "The activity type for this entry. Defaults to \"Note\".",
"The value to search for (e.g., a name or email).": "The value to search for (e.g., a name or email).",
"The structured filter query. See the [documentation](https://capsulecrm.com/developer/api-v2/filters/) for examples.": "The structured filter query. See the [documentation](https://capsulecrm.com/developer/api-v2/filters/) for examples.",
"Person": "Person",
"Organisation": "Organisation",
"Fixed": "Fixed",
"Hour": "Hour",
"Day": "Day",
"Week": "Week",
"Month": "Month",
"Quarter": "Quarter",
"Year": "Year",
"Open": "Open",
"Closed": "Closed",
"Party (Contact)": "Party (Contact)",
"Project": "Project",
"New Case": "New Case",
"New Opportunity": "New Opportunity",
"New Task": "New Task",
"New Project": "New Project",
"Fires when a new case (project) is created in Capsule CRM.": "Fires when a new case (project) is created in Capsule CRM.",
"Fires when a new opportunity is created.": "Fires when a new opportunity is created.",
"Fires when a new task is created.": "Fires when a new task is created.",
"Fires when a project is created.": "Fires when a project is created."
}

View File

@@ -0,0 +1,118 @@
{
"\n To authenticate with Capsule CRM:\n 1. Go to your Capsule CRM user settings.\n 2. Navigate to \"My Preferences\" > \"API Authentication Tokens\".\n 3. Register a new application to get a Client ID and Client Secret.\n 4. Add https://cloud.activepieces.com/redirect to the authorized redirect URIs.\n 5. Use the OAuth2 flow below.": "\n To authenticate with Capsule CRM:\n 1. Go to your Capsule CRM user settings.\n 2. Navigate to \"My Preferences\" > \"API Authentication Tokens\".\n 3. Register a new application to get a Client ID and Client Secret.\n 4. Add https://cloud.activepieces.com/redirect to the authorized redirect URIs.\n 5. Use the OAuth2 flow below.",
"Create Contact": "Create Contact",
"Update Contact": "Update Contact",
"Create Opportunity": "Create Opportunity",
"Create Project": "Create Project",
"Create Task": "Create Task",
"Update Opportunity": "Update Opportunity",
"Add Note to Entity": "Add Note to Entity",
"Find Contact": "Find Contact",
"Find Project": "Find Project",
"Find Opportunity": "Find Opportunity",
"Create a new Person or Organisation in Capsule CRM.": "Create a new Person or Organisation in Capsule CRM.",
"Update fields on an existing Person or Organisation.": "Update fields on an existing Person or Organisation.",
"Create a new Opportunity in Capsule CRM.": "Create a new Opportunity in Capsule CRM.",
"Create a new Project in Capsule CRM.": "Create a new Project in Capsule CRM.",
"Create a new Task in Capsule CRM.": "Create a new Task in Capsule CRM.",
"Update an existing Opportunity in Capsule CRM.": "Update an existing Opportunity in Capsule CRM.",
"Add a comment/note to an entity (e.g., contact, opportunity, project).": "Add a comment/note to an entity (e.g., contact, opportunity, project).",
"Find a Person by search criteria.": "Find a Person by search criteria.",
"Find a Project by search criteria.": "Find a Project by search criteria.",
"Find an Opportunity by search criteria.": "Find an Opportunity by search criteria.",
"Contact Type": "Contact Type",
"Details": "详细信息",
"About": "About",
"Owner": "所有者",
"Team": "Team",
"Tags": "标签",
"Custom Fields": "Custom Fields",
"Email Addresses": "Email Addresses",
"Phone Numbers": "Phone Numbers",
"Addresses": "Addresses",
"Websites": "Websites",
"Contact": "Contact",
"Party": "Party",
"Name": "名称",
"Description": "描述",
"Milestone": "Milestone",
"Currency": "Currency",
"Amount": "Amount",
"Expected Close Date": "Expected Close Date",
"Probability": "Probability",
"Duration Basis": "Duration Basis",
"Duration": "期限",
"Opportunity": "Opportunity",
"Stage": "Stage",
"Status": "状态",
"Due Date": "Due Date",
"Due Time": "Due Time",
"Link To": "Link To",
"Linked Entity": "Linked Entity",
"Category": "Category",
"Note Content": "Note Content",
"Entity Type": "Entity Type",
"Entity": "Entity",
"Activity Type": "Activity Type",
"Search Term": "Search Term",
"Filter": "Filter",
"The type of contact to create.": "The type of contact to create.",
"The contact (Person or Organisation) to select.": "The contact (Person or Organisation) to select.",
"The user to assign the task to.": "The user to assign the task to.",
"The team to assign the contact to.": "The team to assign the contact to.",
"Update the biography or description for the contact.": "Update the biography or description for the contact.",
"A short description of the opportunity.": "A short description of the opportunity.",
"More details about the opportunity.": "More details about the opportunity.",
"The currency for the opportunity value (e.g., USD, GBP).": "The currency for the opportunity value (e.g., USD, GBP).",
"The numerical value of the opportunity.": "The numerical value of the opportunity.",
"The expected closing date for the opportunity.": "The expected closing date for the opportunity.",
"The probability of winning the opportunity.": "The probability of winning the opportunity.",
"The basis of the duration of the opportunity.": "The basis of the duration of the opportunity.",
"The duration of the opportunity.": "The duration of the opportunity.",
"The user the opportunity is assigned to.": "The user the opportunity is assigned to.",
"The team the opportunity is assigned to.": "The team the opportunity is assigned to.",
"The main contact for this project.": "The main contact for this project.",
"The name of this project.": "The name of this project.",
"The description of this project.": "The description of this project.",
"An optional link to the opportunity that this project was created to support.": "An optional link to the opportunity that this project was created to support.",
"The stage that this project is on.": "The stage that this project is on.",
"The status of the project.": "The status of the project.",
"The expected close date of this project.": "The expected close date of this project.",
"The user this project is assigned to.": "The user this project is assigned to.",
"The team this project is assigned to.": "The team this project is assigned to.",
"An array of tags that are added to this project.": "An array of tags that are added to this project.",
"An array of custom fields that are defined for this project.": "An array of custom fields that are defined for this project.",
"A short description of the task.": "A short description of the task.",
"The date when this task is due.": "The date when this task is due.",
"More details about the task.": "More details about the task.",
"The time when this task is due (e.g., 18:00:00). Note: The time is in the user's timezone.": "The time when this task is due (e.g., 18:00:00). Note: The time is in the user's timezone.",
"The entity this task is linked to. Only one can be selected.": "The entity this task is linked to. Only one can be selected.",
"The category of this task.": "The category of this task.",
"The user this task is assigned to.": "The user this task is assigned to.",
"The body of the note.": "The body of the note.",
"The type of entity to add the note to.": "The type of entity to add the note to.",
"The activity type for this entry. Defaults to \"Note\".": "The activity type for this entry. Defaults to \"Note\".",
"The value to search for (e.g., a name or email).": "The value to search for (e.g., a name or email).",
"The structured filter query. See the [documentation](https://capsulecrm.com/developer/api-v2/filters/) for examples.": "The structured filter query. See the [documentation](https://capsulecrm.com/developer/api-v2/filters/) for examples.",
"Person": "Person",
"Organisation": "Organisation",
"Fixed": "Fixed",
"Hour": "Hour",
"Day": "Day",
"Week": "Week",
"Month": "Month",
"Quarter": "Quarter",
"Year": "Year",
"Open": "Open",
"Closed": "Closed",
"Party (Contact)": "Party (Contact)",
"Project": "项目",
"New Case": "New Case",
"New Opportunity": "New Opportunity",
"New Task": "New Task",
"New Project": "新建项目",
"Fires when a new case (project) is created in Capsule CRM.": "Fires when a new case (project) is created in Capsule CRM.",
"Fires when a new opportunity is created.": "Fires when a new opportunity is created.",
"Fires when a new task is created.": "Fires when a new task is created.",
"Fires when a project is created.": "Fires when a project is created."
}

View File

@@ -0,0 +1,44 @@
import { createPiece } from "@activepieces/pieces-framework";
import { capsuleCrmAuth } from "../src/lib/common/auth";
import { createContactAction } from "../src/lib/actions/create-contact";
import { updateContactAction } from "../src/lib/actions/update-contact";
import { createOpportunityAction } from "../src/lib/actions/create-opportunity";
import { createProjectAction } from "../src/lib/actions/create-project";
import { createTaskAction } from "../src/lib/actions/create-task";
import { updateOpportunityAction } from "../src/lib/actions/update-opportunity";
import { addNoteToEntityAction } from "../src/lib/actions/add-note-to-entity";
import { findContactAction } from "../src/lib/actions/find-contact";
import { findProjectAction } from "../src/lib/actions/find-project";
import { findOpportunityAction } from "../src/lib/actions/find-opportunity";
import { newCaseTrigger } from "../src/lib/triggers/new-case";
import { newOpportunityTrigger } from "../src/lib/triggers/new-opportunity";
import { newTaskTrigger } from "../src/lib/triggers/new-task";
import { newProjectTrigger } from "../src/lib/triggers/new-project";
export const capsuleCrm = createPiece({
displayName: 'Capsule CRM',
auth: capsuleCrmAuth,
minimumSupportedRelease: '0.36.1',
logoUrl: 'https://cdn.activepieces.com/pieces/capsule-crm.png',
authors: ['Prabhukiran161', 'onyedikachi-david'],
actions: [
createContactAction,
updateContactAction,
createOpportunityAction,
createProjectAction,
createTaskAction,
updateOpportunityAction,
addNoteToEntityAction,
findContactAction,
findProjectAction,
findOpportunityAction,
],
triggers: [
newCaseTrigger,
newOpportunityTrigger,
newTaskTrigger,
newProjectTrigger,
],
});

View File

@@ -0,0 +1,142 @@
import {
createAction,
Property,
DynamicPropsValue,
} from '@activepieces/pieces-framework';
import { capsuleCrmAuth, CapsuleCrmAuthType } from '../common/auth';
import { capsuleCrmClient } from '../common/client';
import { CreateEntryParams } from '../common/types';
export const addNoteToEntityAction = createAction({
auth: capsuleCrmAuth,
name: 'add_note_to_entity',
displayName: 'Add Note to Entity',
description:
'Add a comment/note to an entity (e.g., contact, opportunity, project).',
props: {
content: Property.LongText({
displayName: 'Note Content',
description: 'The body of the note.',
required: true,
}),
entityType: Property.StaticDropdown({
displayName: 'Entity Type',
description: 'The type of entity to add the note to.',
required: true,
options: {
options: [
{ label: 'Party (Contact)', value: 'party' },
{ label: 'Opportunity', value: 'opportunity' },
{ label: 'Project', value: 'project' },
],
},
}),
entityId: Property.DynamicProperties({
auth: capsuleCrmAuth,
displayName: 'Entity',
required: true,
refreshers: ['entityType'],
props: async ({ auth, entityType }) => {
const fields: DynamicPropsValue = {};
const entityTypeStr = entityType as unknown as string;
if (!auth || !entityTypeStr) return fields;
if (entityTypeStr === 'party') {
const contacts = await capsuleCrmClient.searchContacts(
auth,
''
);
fields['partyId'] = Property.StaticDropdown({
displayName: 'Party',
required: true,
options:{
options: contacts.map((contact) => ({
label:
contact.type === 'person'
? `${contact.firstName} ${contact.lastName}`
: contact.name || `Unnamed ${contact.type}`,
value: contact.id,
})),
}})
} else if (entityTypeStr === 'opportunity') {
const opportunities =
await capsuleCrmClient.searchOpportunities(
auth
);
fields['opportunityId'] = Property.StaticDropdown({
displayName: 'Opportunity',
required: true,
options: {
options: opportunities.map((opportunity) => ({
label: opportunity.name,
value: opportunity.id,
})),
}})
} else if (entityTypeStr === 'project') {
const projects = await capsuleCrmClient.searchProjects(
auth
);
fields['projectId'] = Property.StaticDropdown({
displayName: 'Project',
required: true,
options:{
options: projects.map((project) => ({
label: project.name,
value: project.id,
})),
}})
}
return fields;
},
}),
activityTypeId: Property.Dropdown({
displayName: 'Activity Type',
description: 'The activity type for this entry. Defaults to "Note".',
required: false,
refreshers: [],
auth: capsuleCrmAuth,
options: async ({ auth }) => {
if (!auth)
return {
options: [],
disabled: true,
placeholder: 'Please connect your Capsule CRM account first',
};
const activityTypes = await capsuleCrmClient.listActivityTypes(
auth
);
return {
options: activityTypes.map((activityType) => ({
label: activityType.name,
value: activityType.id,
})),
};
},
}),
},
async run(context) {
const { auth, propsValue } = context;
const entryData: CreateEntryParams = {
type: 'note',
content: propsValue.content,
};
if (propsValue.activityTypeId) {
entryData.activityType = { id: propsValue.activityTypeId };
}
const entityId = propsValue.entityId as DynamicPropsValue;
if (entityId) {
if (entityId['partyId']) {
entryData.party = { id: entityId['partyId'] as number };
} else if (entityId['opportunityId']) {
entryData.opportunity = { id: entityId['opportunityId'] as number };
} else if (entityId['projectId']) {
entryData.kase = { id: entityId['projectId'] as number };
}
}
return await capsuleCrmClient.createEntry(auth, entryData);
},
});

View File

@@ -0,0 +1,378 @@
import {
createAction,
Property,
DynamicPropsValue,
OAuth2PropertyValue,
} from '@activepieces/pieces-framework';
import { capsuleCrmAuth, CapsuleCrmAuthType } from '../common/auth';
import { capsuleCrmClient } from '../common/client';
import { CreatePartyParams } from '../common/types';
export const createContactAction = createAction({
auth: capsuleCrmAuth,
name: 'create_contact',
displayName: 'Create Contact',
description: 'Create a new Person or Organisation in Capsule CRM.',
props: {
type: Property.StaticDropdown({
displayName: 'Contact Type',
description: 'The type of contact to create.',
required: true,
options: {
options: [
{ label: 'Person', value: 'person' },
{ label: 'Organisation', value: 'organisation' },
],
},
}),
contactFields: Property.DynamicProperties({
auth: capsuleCrmAuth,
displayName: 'Details',
required: true,
refreshers: ['type'],
props: async ({ auth, type }) => {
const contactType = type as unknown as string;
const fields: DynamicPropsValue = {};
if (contactType === 'person') {
// Fetch organisations data ONCE at the outer level
let organisationOptions: { label: string; value: number }[] = [];
if (auth) {
try {
const organisations = await capsuleCrmClient.searchContacts(
auth,
''
);
organisationOptions = organisations
.filter((party) => party.type === 'organisation')
.map((org) => ({
label: org.name || 'Unnamed Organisation',
value: org.id,
}));
} catch (error) {
console.error('Failed to load organisations:', error);
}
}
fields['firstName'] = Property.ShortText({
displayName: 'First Name',
required: true,
});
fields['lastName'] = Property.ShortText({
displayName: 'Last Name',
required: true,
});
fields['title'] = Property.ShortText({
displayName: 'Title',
required: false,
});
fields['jobTitle'] = Property.ShortText({
displayName: 'Job Title',
required: false,
});
fields['organisationId'] = Property.StaticDropdown({
displayName: 'Organisation',
required: false,
options: {
options: organisationOptions,
},
});
} else if (contactType === 'organisation') {
fields['organisationName'] = Property.ShortText({
displayName: 'Organisation Name',
required: true,
});
}
return fields;
},
}),
about: Property.LongText({
displayName: 'About',
required: false,
}),
ownerId: Property.Dropdown({
auth: capsuleCrmAuth,
displayName: 'Owner',
required: false,
refreshers: [],
options: async ({ auth }) => {
if (!auth) return { options: [] };
const users = await capsuleCrmClient.listUsers(
auth
);
return {
options: users.map((user) => ({
label: user.name,
value: user.id,
})),
};
},
}),
teamId: Property.Dropdown({
auth: capsuleCrmAuth,
displayName: 'Team',
required: false,
refreshers: [],
options: async ({ auth }) => {
if (!auth) return { options: [] };
const teams = await capsuleCrmClient.listTeams(
auth
);
return {
options: teams.map((team) => ({
label: team.name,
value: team.id,
})),
};
},
}),
tags: Property.MultiSelectDropdown({
auth: capsuleCrmAuth,
displayName: 'Tags',
required: false,
refreshers: [],
options: async ({ auth }) => {
if (!auth) return { options: [] };
const tags = await capsuleCrmClient.listTags(auth);
return {
options: tags.map((tag) => ({
label: tag.name,
value: tag.name,
})),
};
},
}),
customFields: Property.DynamicProperties({
auth: capsuleCrmAuth,
displayName: 'Custom Fields',
required: true,
refreshers: [],
props: async ({ auth }) => {
const fields: DynamicPropsValue = {};
if (!auth) return fields;
const customFields = await capsuleCrmClient.listCustomFields(
auth
);
for (const field of customFields) {
switch (field.type) {
case 'list':
fields[field.id] = Property.StaticDropdown({
displayName: field.name,
required: false,
options: {
options:
field.options?.map((option) => ({
label: option,
value: option,
})) || [],
},
});
break;
case 'boolean':
fields[field.id] = Property.Checkbox({
displayName: field.name,
required: false,
});
break;
case 'date':
fields[field.id] = Property.DateTime({
displayName: field.name,
required: false,
});
break;
default:
fields[field.id] = Property.ShortText({
displayName: field.name,
required: false,
});
}
}
return fields;
},
}),
emailAddresses: Property.Array({
displayName: 'Email Addresses',
required: false,
properties: {
type: Property.StaticDropdown({
displayName: 'Type',
required: false,
options: {
options: [
{ label: 'Home', value: 'Home' },
{ label: 'Work', value: 'Work' },
],
},
}),
address: Property.ShortText({
displayName: 'Address',
required: true,
}),
},
}),
phoneNumbers: Property.Array({
displayName: 'Phone Numbers',
required: false,
properties: {
type: Property.StaticDropdown({
displayName: 'Type',
required: false,
options: {
options: [
{ label: 'Home', value: 'Home' },
{ label: 'Work', value: 'Work' },
{ label: 'Mobile', value: 'Mobile' },
{ label: 'Fax', value: 'Fax' },
{ label: 'Direct', value: 'Direct' },
],
},
}),
number: Property.ShortText({
displayName: 'Number',
required: true,
}),
},
}),
addresses: Property.Array({
displayName: 'Addresses',
required: false,
properties: {
type: Property.StaticDropdown({
displayName: 'Type',
required: false,
options: {
options: [
{ label: 'Home', value: 'Home' },
{ label: 'Postal', value: 'Postal' },
{ label: 'Office', value: 'Office' },
{ label: 'Billing', value: 'Billing' },
{ label: 'Shipping', value: 'Shipping' },
],
},
}),
street: Property.ShortText({
displayName: 'Street',
required: false,
}),
city: Property.ShortText({
displayName: 'City',
required: false,
}),
state: Property.ShortText({
displayName: 'State',
required: false,
}),
country: Property.ShortText({
displayName: 'Country',
required: false,
}),
zip: Property.ShortText({
displayName: 'Zip',
required: false,
}),
},
}),
websites: Property.Array({
displayName: 'Websites',
required: false,
properties: {
type: Property.StaticDropdown({
displayName: 'Type',
required: false,
options: {
options: [
{ label: 'Home', value: 'Home' },
{ label: 'Work', value: 'Work' },
],
},
}),
service: Property.StaticDropdown({
displayName: 'Service',
required: true,
options: {
options: [
{ label: 'URL', value: 'URL' },
{ label: 'Skype', value: 'SKYPE' },
{ label: 'Twitter', value: 'TWITTER' },
{ label: 'LinkedIn', value: 'LINKED_IN' },
{ label: 'Facebook', value: 'FACEBOOK' },
{ label: 'Xing', value: 'XING' },
{ label: 'Feed', value: 'FEED' },
{ label: 'Google+', value: 'GOOGLE_PLUS' },
{ label: 'Flickr', value: 'FLICKR' },
{ label: 'GitHub', value: 'GITHUB' },
{ label: 'YouTube', value: 'YOUTUBE' },
{ label: 'Instagram', value: 'INSTAGRAM' },
{ label: 'Pinterest', value: 'PINTEREST' },
],
},
}),
address: Property.ShortText({
displayName: 'Address',
required: true,
}),
},
}),
},
async run(context) {
const { auth, propsValue } = context;
const type = propsValue.type as 'person' | 'organisation';
const contactFields = propsValue.contactFields as DynamicPropsValue;
const contactData: Partial<CreatePartyParams> = {
type: type,
title: contactFields['title'] as string | undefined,
jobTitle: contactFields['jobTitle'] as string | undefined,
about: propsValue.about,
organisationId: contactFields['organisationId'] as number | undefined,
ownerId: propsValue.ownerId,
teamId: propsValue.teamId,
tags: propsValue.tags,
emailAddresses: propsValue.emailAddresses as {
type?: string;
address: string;
}[],
phoneNumbers: propsValue.phoneNumbers as {
type?: string;
number: string;
}[],
addresses: propsValue.addresses as {
type?: string;
street?: string;
city?: string;
state?: string;
country?: string;
zip?: string;
}[],
websites: propsValue.websites as {
type?: string;
service: string;
address: string;
}[],
};
if (type === 'person') {
contactData.firstName = contactFields['firstName'] as string;
contactData.lastName = contactFields['lastName'] as string;
} else if (type === 'organisation') {
contactData.name = contactFields['organisationName'] as string;
}
const customFields = propsValue.customFields as DynamicPropsValue;
if (customFields) {
contactData.fields = Object.entries(customFields)
.filter(([, value]) => value !== undefined && value !== null)
.map(([id, value]) => ({
definition: { id: Number(id) },
value: value,
}));
}
return await capsuleCrmClient.createContact(
auth,
contactData as CreatePartyParams
);
},
});

View File

@@ -0,0 +1,263 @@
import {
createAction,
Property,
DynamicPropsValue,
} from '@activepieces/pieces-framework';
import { capsuleCrmAuth, CapsuleCrmAuthType } from '../common/auth';
import { capsuleCrmClient } from '../common/client';
import {
CreateOpportunityParams,
OpportunityCustomField,
OpportunityTag,
} from '../common/types';
export const createOpportunityAction = createAction({
auth: capsuleCrmAuth,
name: 'create_opportunity',
displayName: 'Create Opportunity',
description: 'Create a new Opportunity in Capsule CRM.',
props: {
partyId: Property.Dropdown({
displayName: 'Party',
required: true,
refreshers: [],
auth: capsuleCrmAuth,
options: async ({ auth }) => {
if (!auth) return { options: [], disabled: true, placeholder: "Please connect your Capsule CRM account first" };
const contacts = await capsuleCrmClient.searchContacts(
auth,
''
);
return {
options: contacts.map((contact) => ({
label:
contact.type === 'person'
? `${contact.firstName} ${contact.lastName}`
: contact.name || `Unnamed ${contact.type}`,
value: contact.id,
})),
};
},
}),
name: Property.ShortText({
displayName: 'Name',
description: 'A short description of the opportunity.',
required: true,
}),
description: Property.LongText({
displayName: 'Description',
description: 'More details about the opportunity.',
required: false,
}),
milestoneId: Property.Dropdown({
auth: capsuleCrmAuth,
displayName: 'Milestone',
required: true,
refreshers: [],
options: async ({ auth }) => {
if (!auth) return { options: [], disabled: true, placeholder: "Please connect your Capsule CRM account first" };
const milestones = await capsuleCrmClient.listMilestones(
auth
);
return {
options: milestones.map((milestone) => ({
label: milestone.name,
value: milestone.id,
})),
};
},
}),
currency: Property.ShortText({
displayName: 'Currency',
description: 'The currency for the opportunity value (e.g., USD, GBP).',
required: false,
}),
amount: Property.Number({
displayName: 'Amount',
description: 'The numerical value of the opportunity.',
required: false,
}),
expectedCloseOn: Property.DateTime({
displayName: 'Expected Close Date',
description: 'The expected closing date for the opportunity.',
required: false,
}),
probability: Property.Number({
displayName: 'Probability',
description: 'The probability of winning the opportunity.',
required: false,
}),
durationBasis: Property.StaticDropdown({
displayName: 'Duration Basis',
required: false,
description: 'The basis of the duration of the opportunity.',
options: {
options: [
{ label: 'Fixed', value: 'FIXED' },
{ label: 'Hour', value: 'HOUR' },
{ label: 'Day', value: 'DAY' },
{ label: 'Week', value: 'WEEK' },
{ label: 'Month', value: 'MONTH' },
{ label: 'Quarter', value: 'QUARTER' },
{ label: 'Year', value: 'YEAR' },
],
},
}),
duration: Property.Number({
displayName: 'Duration',
required: false,
description: 'The duration of the opportunity.',
}),
ownerId: Property.Dropdown({
auth: capsuleCrmAuth,
displayName: 'Owner',
required: false,
description: 'The user the opportunity is assigned to.',
refreshers: [],
options: async ({ auth }) => {
if (!auth) return { options: [], disabled: true, placeholder: "Please connect your Capsule CRM account first" };
const users = await capsuleCrmClient.listUsers(
auth
);
return {
options: users.map((user) => ({
label: user.name,
value: user.id,
})),
};
},
}),
teamId: Property.Dropdown({
auth: capsuleCrmAuth,
displayName: 'Team',
required: false,
description: 'The team the opportunity is assigned to.',
refreshers: [],
options: async ({ auth }) => {
if (!auth) return { options: [], disabled: true, placeholder: "Please connect your Capsule CRM account first" };
const teams = await capsuleCrmClient.listTeams(
auth
);
return {
options: teams.map((team) => ({
label: team.name,
value: team.id,
})),
};
},
}),
tags: Property.MultiSelectDropdown({
auth: capsuleCrmAuth,
displayName: 'Tags',
required: false,
refreshers: [],
options: async ({ auth }) => {
if (!auth) return { options: [], disabled: true, placeholder: "Please connect your Capsule CRM account first" };
const tags = await capsuleCrmClient.listTags(auth);
return {
options: tags.map((tag) => ({
label: tag.name,
value: tag.name,
})),
};
},
}),
customFields: Property.DynamicProperties({
auth: capsuleCrmAuth,
displayName: 'Custom Fields',
required: true,
refreshers: [],
props: async ({ auth }) => {
const fields: DynamicPropsValue = {};
if (!auth) return { options: [], disabled: true, placeholder: "Please connect your Capsule CRM account first" };
const customFields = await capsuleCrmClient.listCustomFields(
auth
);
for (const field of customFields) {
switch (field.type) {
case 'list':
fields[field.id] = Property.StaticDropdown({
displayName: field.name,
required: false,
options: {
options:
field.options?.map((option) => ({
label: option,
value: option,
})) || [],
},
});
break;
case 'boolean':
fields[field.id] = Property.Checkbox({
displayName: field.name,
required: false,
});
break;
case 'date':
fields[field.id] = Property.DateTime({
displayName: field.name,
required: false,
});
break;
default:
fields[field.id] = Property.ShortText({
displayName: field.name,
required: false,
});
}
}
return fields;
},
}),
},
async run(context) {
const { auth, propsValue } = context;
const opportunityData: CreateOpportunityParams = {
party: { id: propsValue.partyId },
name: propsValue.name,
milestone: { id: propsValue.milestoneId },
description: propsValue.description,
expectedCloseOn: propsValue.expectedCloseOn,
probability: propsValue.probability,
durationBasis: propsValue.durationBasis,
duration: propsValue.duration,
};
if (propsValue.ownerId) {
opportunityData.owner = { id: propsValue.ownerId };
}
if (propsValue.teamId) {
opportunityData.team = { id: propsValue.teamId };
}
if (propsValue.currency && propsValue.amount) {
opportunityData.value = {
currency: propsValue.currency,
amount: propsValue.amount,
};
}
if (propsValue.tags) {
opportunityData.tags = propsValue.tags.map(
(tag) => ({ name: tag } as OpportunityTag)
);
}
const customFields = propsValue.customFields as DynamicPropsValue;
if (customFields) {
opportunityData.fields = Object.entries(customFields)
.filter(([, value]) => value !== undefined && value !== null)
.map(
([id, value]) =>
({
definition: { id: Number(id) },
value: value,
} as OpportunityCustomField)
);
}
return await capsuleCrmClient.createOpportunity(auth, opportunityData);
},
});

View File

@@ -0,0 +1,288 @@
import {
createAction,
Property,
DynamicPropsValue,
} from '@activepieces/pieces-framework';
import { capsuleCrmAuth, CapsuleCrmAuthType } from '../common/auth';
import { capsuleCrmClient } from '../common/client';
import {
CreateProjectParams,
OpportunityCustomField,
OpportunityTag,
} from '../common/types';
export const createProjectAction = createAction({
auth: capsuleCrmAuth,
name: 'create_project',
displayName: 'Create Project',
description: 'Create a new Project in Capsule CRM.',
props: {
partyId: Property.Dropdown({
auth: capsuleCrmAuth,
displayName: 'Party',
description: 'The main contact for this project.',
required: true,
refreshers: [],
options: async ({ auth }) => {
if (!auth)
return {
options: [],
disabled: true,
placeholder: 'Please connect your Capsule CRM account first',
};
const contacts = await capsuleCrmClient.searchContacts(
auth,
''
);
return {
options: contacts.map((contact) => ({
label:
contact.type === 'person'
? `${contact.firstName} ${contact.lastName}`
: contact.name || `Unnamed ${contact.type}`,
value: contact.id,
})),
};
},
}),
name: Property.ShortText({
displayName: 'Name',
description: 'The name of this project.',
required: true,
}),
description: Property.LongText({
displayName: 'Description',
description: 'The description of this project.',
required: false,
}),
opportunityId: Property.Dropdown({
displayName: 'Opportunity',
description:
'An optional link to the opportunity that this project was created to support.',
required: false,
refreshers: [],
auth: capsuleCrmAuth,
options: async ({ auth }) => {
if (!auth)
return {
options: [],
disabled: true,
placeholder: 'Please connect your Capsule CRM account first',
};
const opportunities = await capsuleCrmClient.searchOpportunities(
auth
);
return {
options: opportunities.map((opportunity) => ({
label: opportunity.name,
value: opportunity.id,
})),
};
},
}),
stageId: Property.Dropdown({
displayName: 'Stage',
description: 'The stage that this project is on.',
required: false,
refreshers: [],
auth: capsuleCrmAuth,
options: async ({ auth }) => {
if (!auth)
return {
options: [],
disabled: true,
placeholder: 'Please connect your Capsule CRM account first',
};
const stages = await capsuleCrmClient.listStages(
auth
);
return {
options: stages.map((stage) => ({
label: stage.name,
value: stage.id,
})),
};
},
}),
status: Property.StaticDropdown({
displayName: 'Status',
description: 'The status of the project.',
required: false,
options: {
options: [
{ label: 'Open', value: 'OPEN' },
{ label: 'Closed', value: 'CLOSED' },
],
},
}),
expectedCloseOn: Property.DateTime({
displayName: 'Expected Close Date',
description: 'The expected close date of this project.',
required: false,
}),
ownerId: Property.Dropdown({
auth: capsuleCrmAuth,
displayName: 'Owner',
description: 'The user this project is assigned to.',
required: false,
refreshers: [],
options: async ({ auth }) => {
if (!auth)
return {
options: [],
disabled: true,
placeholder: 'Please connect your Capsule CRM account first',
};
const users = await capsuleCrmClient.listUsers(
auth
);
return {
options: users.map((user) => ({
label: user.name,
value: user.id,
})),
};
},
}),
teamId: Property.Dropdown({
auth: capsuleCrmAuth,
displayName: 'Team',
description: 'The team this project is assigned to.',
required: false,
refreshers: [],
options: async ({ auth }) => {
if (!auth)
return {
options: [],
disabled: true,
placeholder: 'Please connect your Capsule CRM account first',
};
const teams = await capsuleCrmClient.listTeams(
auth
);
return {
options: teams.map((team) => ({
label: team.name,
value: team.id,
})),
};
},
}),
tags: Property.MultiSelectDropdown({
auth: capsuleCrmAuth,
displayName: 'Tags',
description: 'An array of tags that are added to this project.',
required: false,
refreshers: [],
options: async ({ auth }) => {
if (!auth)
return {
options: [],
disabled: true,
placeholder: 'Please connect your Capsule CRM account first',
};
const tags = await capsuleCrmClient.listTags(auth);
return {
options: tags.map((tag) => ({
label: tag.name,
value: tag.name,
})),
};
},
}),
customFields: Property.DynamicProperties({
auth: capsuleCrmAuth,
displayName: 'Custom Fields',
description: 'An array of custom fields that are defined for this project.',
required: false,
refreshers: [],
props: async ({ auth }) => {
const fields: DynamicPropsValue = {};
if (!auth) return fields;
const customFields = await capsuleCrmClient.listCustomFields(
auth
);
for (const field of customFields) {
switch (field.type) {
case 'list':
fields[field.id] = Property.StaticDropdown({
displayName: field.name,
required: false,
options: {
options:
field.options?.map((option) => ({
label: option,
value: option,
})) || [],
},
});
break;
case 'boolean':
fields[field.id] = Property.Checkbox({
displayName: field.name,
required: false,
});
break;
case 'date':
fields[field.id] = Property.DateTime({
displayName: field.name,
required: false,
});
break;
default:
fields[field.id] = Property.ShortText({
displayName: field.name,
required: false,
});
}
}
return fields;
},
}),
},
async run(context) {
const { auth, propsValue } = context;
const projectData: CreateProjectParams = {
party: { id: propsValue.partyId },
name: propsValue.name,
description: propsValue.description,
status: propsValue.status as 'OPEN' | 'CLOSED' | undefined,
expectedCloseOn: propsValue.expectedCloseOn,
};
if (propsValue.opportunityId) {
projectData.opportunity = { id: propsValue.opportunityId };
}
if (propsValue.stageId) {
projectData.stage = { id: propsValue.stageId };
}
if (propsValue.ownerId) {
projectData.owner = { id: propsValue.ownerId };
}
if (propsValue.teamId) {
projectData.team = { id: propsValue.teamId };
}
if (propsValue.tags) {
projectData.tags = propsValue.tags.map(
(tag) => ({ name: tag } as OpportunityTag)
);
}
const customFields = propsValue.customFields as DynamicPropsValue;
if (customFields) {
projectData.fields = Object.entries(customFields)
.filter(([, value]) => value !== undefined && value !== null)
.map(
([id, value]) =>
({
definition: { id: Number(id) },
value: value,
} as OpportunityCustomField)
);
}
return await capsuleCrmClient.createProject(auth, projectData);
},
});

View File

@@ -0,0 +1,192 @@
import {
createAction,
Property,
DynamicPropsValue,
} from '@activepieces/pieces-framework';
import { capsuleCrmAuth, CapsuleCrmAuthType } from '../common/auth';
import { capsuleCrmClient } from '../common/client';
import { CreateTaskParams } from '../common/types';
export const createTaskAction = createAction({
auth: capsuleCrmAuth,
name: 'create_task',
displayName: 'Create Task',
description: 'Create a new Task in Capsule CRM.',
props: {
description: Property.ShortText({
displayName: 'Description',
description: 'A short description of the task.',
required: true,
}),
dueOn: Property.DateTime({
displayName: 'Due Date',
description: 'The date when this task is due.',
required: true,
}),
detail: Property.LongText({
displayName: 'Details',
description: 'More details about the task.',
required: false,
}),
dueTime: Property.ShortText({
displayName: 'Due Time',
description:
"The time when this task is due (e.g., 18:00:00). Note: The time is in the user's timezone.",
required: false,
}),
linkTo: Property.StaticDropdown({
displayName: 'Link To',
description:
'The entity this task is linked to. Only one can be selected.',
required: false,
options: {
options: [
{ label: 'Party (Contact)', value: 'party' },
{ label: 'Opportunity', value: 'opportunity' },
{ label: 'Project', value: 'project' },
],
},
}),
linkedEntityId: Property.DynamicProperties({
displayName: 'Linked Entity',
required: false,
refreshers: ['linkTo'],
auth: capsuleCrmAuth,
props: async ({ auth, linkTo }) => {
const fields: DynamicPropsValue = {};
const linkToType = linkTo as unknown as string;
if (!auth || !linkToType) return fields;
if (linkToType === 'party') {
const contacts = await capsuleCrmClient.searchContacts(
auth,
''
);
const contactOptions = contacts.map((contact) => ({
label:
contact.type === 'person'
? `${contact.firstName} ${contact.lastName}`
: contact.name || `Unnamed ${contact.type}`,
value: contact.id,
}));
fields['partyId'] = Property.StaticDropdown({
displayName: 'Party',
required: true,
options: {
options: contactOptions,
},
});
} else if (linkToType === 'opportunity') {
const opportunities = await capsuleCrmClient.searchOpportunities(
auth
);
const opportunityOptions = opportunities.map((opportunity) => ({
label: opportunity.name,
value: opportunity.id,
}));
fields['opportunityId'] = Property.StaticDropdown({
displayName: 'Opportunity',
required: true,
options: {
options: opportunityOptions,
},
});
} else if (linkToType === 'project') {
const projects = await capsuleCrmClient.searchProjects(
auth
);
const projectOptions = projects.map((project) => ({
label: project.name,
value: project.id,
}));
fields['projectId'] = Property.StaticDropdown({
displayName: 'Project',
required: true,
options: {
options: projectOptions,
},
});
}
return fields;
},
}),
categoryId: Property.Dropdown({
displayName: 'Category',
description: 'The category of this task.',
required: false,
refreshers: [],
auth: capsuleCrmAuth,
options: async ({ auth }) => {
if (!auth)
return {
options: [],
disabled: true,
placeholder: 'Please connect your Capsule CRM account first',
};
const categories = await capsuleCrmClient.listCategories(
auth
);
return {
options: categories.map((category) => ({
label: category.name,
value: category.id,
})),
};
},
}),
ownerId: Property.Dropdown({
displayName: 'Owner',
description: 'The user this task is assigned to.',
required: false,
refreshers: [],
auth: capsuleCrmAuth,
options: async ({ auth }) => {
if (!auth)
return {
options: [],
disabled: true,
placeholder: 'Please connect your Capsule CRM account first',
};
const users = await capsuleCrmClient.listUsers(
auth
);
return {
options: users.map((user) => ({
label: user.name,
value: user.id,
})),
};
},
}),
},
async run(context) {
const { auth, propsValue } = context;
const taskData: CreateTaskParams = {
description: propsValue.description,
dueOn: propsValue.dueOn,
detail: propsValue.detail,
dueTime: propsValue.dueTime,
};
if (propsValue.categoryId) {
taskData.category = { id: propsValue.categoryId };
}
if (propsValue.ownerId) {
taskData.owner = { id: propsValue.ownerId };
}
const linkedEntity = propsValue.linkedEntityId as DynamicPropsValue;
if (linkedEntity) {
if (linkedEntity['partyId']) {
taskData.party = { id: linkedEntity['partyId'] as number };
} else if (linkedEntity['opportunityId']) {
taskData.opportunity = { id: linkedEntity['opportunityId'] as number };
} else if (linkedEntity['projectId']) {
taskData.kase = { id: linkedEntity['projectId'] as number };
}
}
return await capsuleCrmClient.createTask(auth, taskData);
},
});

View File

@@ -0,0 +1,22 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { capsuleCrmAuth } from '../common/auth';
import { capsuleCrmClient } from '../common/client';
export const findContactAction = createAction({
auth: capsuleCrmAuth,
name: 'find_contact',
displayName: 'Find Contact',
description: 'Find a Person by search criteria.',
props: {
term: Property.ShortText({
displayName: 'Search Term',
description: 'The value to search for (e.g., a name or email).',
required: true,
}),
},
async run(context) {
const { auth, propsValue } = context;
const parties = await capsuleCrmClient.findContact(auth, propsValue.term);
return parties.filter((party) => party.type === 'person');
},
});

View File

@@ -0,0 +1,35 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { capsuleCrmAuth } from '../common/auth';
import { capsuleCrmClient } from '../common/client';
import { Filter } from '../common/types';
export const findOpportunityAction = createAction({
auth: capsuleCrmAuth,
name: 'find_opportunity',
displayName: 'Find Opportunity',
description: 'Find an Opportunity by search criteria.',
props: {
filter: Property.Json({
displayName: 'Filter',
description:
'The structured filter query. See the [documentation](https://capsulecrm.com/developer/api-v2/filters/) for examples.',
required: true,
defaultValue: {
conditions: [
{
field: 'name',
operator: 'is',
value: 'example',
},
],
},
}),
},
async run(context) {
const { auth, propsValue } = context;
return await capsuleCrmClient.filterOpportunities(
auth,
propsValue.filter as unknown as Filter
);
},
});

View File

@@ -0,0 +1,35 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { capsuleCrmAuth } from '../common/auth';
import { capsuleCrmClient } from '../common/client';
import { Filter } from '../common/types';
export const findProjectAction = createAction({
auth: capsuleCrmAuth,
name: 'find_project',
displayName: 'Find Project',
description: 'Find a Project by search criteria.',
props: {
filter: Property.Json({
displayName: 'Filter',
description:
'The structured filter query. See the [documentation](https://capsulecrm.com/developer/api-v2/filters/) for examples.',
required: true,
defaultValue: {
conditions: [
{
field: 'name',
operator: 'is',
value: 'example',
},
],
},
}),
},
async run(context) {
const { auth, propsValue } = context;
return await capsuleCrmClient.filterProjects(
auth,
propsValue.filter as unknown as Filter
);
},
});

View File

@@ -0,0 +1,368 @@
import {
createAction,
Property,
DynamicPropsValue,
OAuth2PropertyValue,
} from '@activepieces/pieces-framework';
import { capsuleCrmAuth, CapsuleCrmAuthType } from '../common/auth';
import { capsuleCrmClient } from '../common/client';
import { capsuleCrmProps } from '../common/props';
export const updateContactAction = createAction({
auth: capsuleCrmAuth,
name: 'update_contact',
displayName: 'Update Contact',
description: 'Update fields on an existing Person or Organisation.',
props: {
contact_id: capsuleCrmProps.contact_id(),
contactFields: Property.DynamicProperties({
auth: capsuleCrmAuth,
displayName: 'Details',
required: true,
refreshers: ['contact_id'],
props: async ({ auth, contact_id }) => {
const fields: DynamicPropsValue = {};
if (!auth || !contact_id) return fields;
const contact = await capsuleCrmClient.getContact(
auth,
contact_id as unknown as number
);
if (contact?.type === 'person') {
fields['firstName'] = Property.ShortText({
displayName: 'First Name',
description: "Update the person's first name.",
required: false,
});
fields['lastName'] = Property.ShortText({
displayName: 'Last Name',
description: "Update the person's last name.",
required: false,
});
fields['title'] = Property.ShortText({
displayName: 'Title',
description: "Update the person's job title.",
required: false,
});
} else if (contact?.type === 'organisation') {
fields['organisationName'] = Property.ShortText({
displayName: 'Organisation Name',
description: "Update the organisation's name.",
required: false,
});
}
return fields;
},
}),
ownerId: capsuleCrmProps.owner_id(false),
teamId: capsuleCrmProps.team_id(false),
about: Property.LongText({
displayName: 'About',
description: 'Update the biography or description for the contact.',
required: false,
}),
addresses: Property.DynamicProperties({
auth: capsuleCrmAuth,
displayName: 'Addresses',
required: false,
refreshers: ['contact_id'],
props: async ({ auth, contact_id }) => {
const fields: DynamicPropsValue = {};
if (!auth || !contact_id) return fields;
const contact = await capsuleCrmClient.getContact(
auth,
contact_id as unknown as number
);
const addressOptions =
contact?.addresses?.map((address) => ({
label: `${address.street}, ${address.city}`,
value: address.id,
})) ?? [];
fields['addresses'] = Property.Array({
displayName: 'Addresses',
required: false,
properties: {
id: Property.StaticDropdown({
displayName: 'Address',
required: false,
options: {
options: addressOptions,
},
}),
type: Property.StaticDropdown({
displayName: 'Type',
required: false,
options: {
options: [
{ label: 'Home', value: 'Home' },
{ label: 'Postal', value: 'Postal' },
{ label: 'Office', value: 'Office' },
{ label: 'Billing', value: 'Billing' },
{ label: 'Shipping', value: 'Shipping' },
],
},
}),
street: Property.ShortText({
displayName: 'Street',
required: false,
}),
city: Property.ShortText({
displayName: 'City',
required: false,
}),
state: Property.ShortText({
displayName: 'State',
required: false,
}),
country: Property.ShortText({
displayName: 'Country',
required: false,
}),
zip: Property.ShortText({
displayName: 'Zip',
required: false,
}),
delete: Property.Checkbox({
displayName: 'Delete',
description: 'Check this to delete the address.',
required: false,
}),
},
});
return fields;
},
}),
websites: Property.DynamicProperties({
auth: capsuleCrmAuth,
displayName: 'Websites',
required: false,
refreshers: ['contact_id'],
props: async ({ auth, contact_id }) => {
const fields: DynamicPropsValue = {};
if (!auth || !contact_id) return fields;
const contact = await capsuleCrmClient.getContact(
auth,
contact_id as unknown as number
);
const websiteOptions =
contact?.websites?.map((website) => ({
label: website.address,
value: website.id,
})) ?? [];
fields['websites'] = Property.Array({
displayName: 'Websites',
required: false,
properties: {
id: Property.StaticDropdown({
displayName: 'Website',
required: false,
options: {
options: websiteOptions,
},
}),
type: Property.StaticDropdown({
displayName: 'Type',
required: false,
options: {
options: [
{ label: 'Home', value: 'Home' },
{ label: 'Work', value: 'Work' },
],
},
}),
service: Property.StaticDropdown({
displayName: 'Service',
required: false,
options: {
options: [
{ label: 'URL', value: 'URL' },
{ label: 'Skype', value: 'SKYPE' },
{ label: 'Twitter', value: 'TWITTER' },
{ label: 'LinkedIn', value: 'LINKED_IN' },
{ label: 'Facebook', value: 'FACEBOOK' },
{ label: 'Xing', value: 'XING' },
{ label: 'Feed', value: 'FEED' },
{ label: 'Google+', value: 'GOOGLE_PLUS' },
{ label: 'Flickr', value: 'FLICKR' },
{ label: 'GitHub', value: 'GITHUB' },
{ label: 'YouTube', value: 'YOUTUBE' },
{ label: 'Instagram', value: 'INSTAGRAM' },
{ label: 'Pinterest', value: 'PINTEREST' },
],
},
}),
address: Property.ShortText({
displayName: 'Address',
required: false,
}),
delete: Property.Checkbox({
displayName: 'Delete',
description: 'Check this to delete the website.',
required: false,
}),
},
});
return fields;
},
}),
emailAddresses: Property.DynamicProperties({
auth: capsuleCrmAuth,
displayName: 'Email Addresses',
required: false,
refreshers: ['contact_id'],
props: async ({ auth, contact_id }) => {
const fields: DynamicPropsValue = {};
if (!auth || !contact_id) return fields;
const contact = await capsuleCrmClient.getContact(
auth,
contact_id as unknown as number
);
const emailOptions =
contact?.emailAddresses?.map((email) => ({
label: email.address,
value: email.id,
})) ?? [];
fields['emailAddresses'] = Property.Array({
displayName: 'Email Addresses',
required: false,
properties: {
id: Property.StaticDropdown({
displayName: 'Email Address',
required: false,
options: {
options: emailOptions,
},
}),
type: Property.StaticDropdown({
displayName: 'Type',
required: false,
options: {
options: [
{ label: 'Home', value: 'Home' },
{ label: 'Work', value: 'Work' },
],
},
}),
address: Property.ShortText({
displayName: 'Address',
required: false,
}),
delete: Property.Checkbox({
displayName: 'Delete',
description: 'Check this to delete the email.',
required: false,
}),
},
});
return fields;
},
}),
phoneNumbers: Property.DynamicProperties({
auth: capsuleCrmAuth,
displayName: 'Phone Numbers',
required: false,
refreshers: ['contact_id'],
props: async ({ auth, contact_id }) => {
const fields: DynamicPropsValue = {};
if (!auth || !contact_id) return fields;
const contact = await capsuleCrmClient.getContact(
auth,
contact_id as unknown as number
);
const phoneOptions =
contact?.phoneNumbers?.map((phone) => ({
label: phone.number,
value: phone.id,
})) ?? [];
fields['phoneNumbers'] = Property.Array({
displayName: 'Phone Numbers',
required: false,
properties: {
id: Property.StaticDropdown({
displayName: 'Phone Number',
required: false,
options: {
options: phoneOptions,
},
}),
type: Property.StaticDropdown({
displayName: 'Type',
required: false,
options: {
options: [
{ label: 'Home', value: 'Home' },
{ label: 'Work', value: 'Work' },
{ label: 'Mobile', value: 'Mobile' },
{ label: 'Fax', value: 'Fax' },
{ label: 'Direct', value: 'Direct' },
],
},
}),
number: Property.ShortText({
displayName: 'Number',
required: false,
}),
delete: Property.Checkbox({
displayName: 'Delete',
description: 'Check this to delete the phone number.',
required: false,
}),
},
});
return fields;
},
}),
},
async run(context) {
const { auth, propsValue } = context;
const contactId = propsValue.contact_id as number;
const contactFields = propsValue.contactFields as DynamicPropsValue;
return await capsuleCrmClient.updateContact(auth, contactId, {
firstName: contactFields['firstName'] as string | undefined,
lastName: contactFields['lastName'] as string | undefined,
name: contactFields['organisationName'] as string | undefined,
title: contactFields['title'] as string | undefined,
about: propsValue.about,
ownerId: propsValue.ownerId,
teamId: propsValue.teamId,
addresses: (
(propsValue.addresses as DynamicPropsValue)?.['addresses'] as any[]
)?.map((address) => ({
...address,
_delete: address.delete,
})),
websites: (
(propsValue.websites as DynamicPropsValue)?.['websites'] as any[]
)?.map((website) => ({
...website,
_delete: website.delete,
})),
emailAddresses: (
(propsValue.emailAddresses as DynamicPropsValue)?.[
'emailAddresses'
] as any[]
)?.map((email) => ({
...email,
_delete: email.delete,
})),
phoneNumbers: (
(propsValue.phoneNumbers as DynamicPropsValue)?.[
'phoneNumbers'
] as any[]
)?.map((phone) => ({
...phone,
_delete: phone.delete,
})),
});
},
});

View File

@@ -0,0 +1,286 @@
import {
createAction,
Property,
DynamicPropsValue,
} from '@activepieces/pieces-framework';
import { capsuleCrmAuth, CapsuleCrmAuthType } from '../common/auth';
import { capsuleCrmClient } from '../common/client';
import {
UpdateOpportunityParams,
OpportunityCustomField,
OpportunityTag,
} from '../common/types';
export const updateOpportunityAction = createAction({
auth: capsuleCrmAuth,
name: 'update_opportunity',
displayName: 'Update Opportunity',
description: 'Update an existing Opportunity in Capsule CRM.',
props: {
opportunityId: Property.Dropdown({
auth: capsuleCrmAuth,
displayName: 'Opportunity',
required: true,
refreshers: [],
options: async ({ auth }) => {
if (!auth) return { options: [], disabled: true, placeholder: "Please connect your Capsule CRM account first" };
const opportunities = await capsuleCrmClient.searchOpportunities(
auth
);
return {
options: opportunities.map((opportunity) => ({
label: opportunity.name,
value: opportunity.id,
})),
};
},
}),
name: Property.ShortText({
displayName: 'Name',
required: false,
}),
description: Property.LongText({
displayName: 'Description',
required: false,
}),
milestoneId: Property.Dropdown({
auth: capsuleCrmAuth,
displayName: 'Milestone',
required: false,
refreshers: [],
options: async ({ auth }) => {
if (!auth) return { options: [], disabled: true, placeholder: "Please connect your Capsule CRM account first" };
const milestones = await capsuleCrmClient.listMilestones(
auth
);
return {
options: milestones.map((milestone) => ({
label: milestone.name,
value: milestone.id,
})),
};
},
}),
currency: Property.ShortText({
displayName: 'Currency',
required: false,
}),
amount: Property.Number({
displayName: 'Amount',
required: false,
}),
expectedCloseOn: Property.DateTime({
displayName: 'Expected Close Date',
required: false,
}),
probability: Property.Number({
displayName: 'Probability',
required: false,
}),
durationBasis: Property.StaticDropdown({
displayName: 'Duration Basis',
required: false,
options: {
options: [
{ label: 'Fixed', value: 'FIXED' },
{ label: 'Hour', value: 'HOUR' },
{ label: 'Day', value: 'DAY' },
{ label: 'Week', value: 'WEEK' },
{ label: 'Month', value: 'MONTH' },
{ label: 'Quarter', value: 'QUARTER' },
{ label: 'Year', value: 'YEAR' },
],
},
}),
duration: Property.Number({
displayName: 'Duration',
required: false,
}),
ownerId: Property.Dropdown({
auth: capsuleCrmAuth,
displayName: 'Owner',
required: false,
refreshers: [],
options: async ({ auth }) => {
if (!auth) return { options: [], disabled: true, placeholder: "Please connect your Capsule CRM account first" };
const users = await capsuleCrmClient.listUsers(
auth
);
return {
options: users.map((user) => ({
label: user.name,
value: user.id,
})),
};
},
}),
teamId: Property.Dropdown({
auth: capsuleCrmAuth,
displayName: 'Team',
required: false,
refreshers: [],
options: async ({ auth }) => {
if (!auth) return { options: [], disabled: true, placeholder: "Please connect your Capsule CRM account first" };
const teams = await capsuleCrmClient.listTeams(
auth
);
return {
options: teams.map((team) => ({
label: team.name,
value: team.id,
})),
};
},
}),
tags: Property.DynamicProperties({
auth: capsuleCrmAuth,
displayName: 'Tags',
required: false,
refreshers: ['opportunityId'],
props: async ({ auth, opportunityId }) => {
const fields: DynamicPropsValue = {};
if (!auth || !opportunityId) return { options: [], disabled: true, placeholder: "Please connect your Capsule CRM account first or select an opportunity" };
const opportunity = await capsuleCrmClient.getOpportunity(
auth,
opportunityId as unknown as number
);
const tagOptions =
opportunity.tags?.map((tag) => ({
label: tag.name,
value: tag.id,
})) ?? [];
fields['tags'] = Property.Array({
displayName: 'Tags',
required: false,
properties: {
id: Property.StaticDropdown({
displayName: 'Tag',
required: false,
options: {
options: tagOptions,
},
}),
name: Property.ShortText({
displayName: 'New Tag Name',
description: 'Enter a name to create a new tag.',
required: false,
}),
delete: Property.Checkbox({
displayName: 'Delete',
description: 'Check this to delete the tag.',
required: false,
}),
},
});
return fields;
},
}),
customFields: Property.DynamicProperties({
auth: capsuleCrmAuth,
displayName: 'Custom Fields',
required: false,
refreshers: ['opportunityId'],
props: async ({ auth, opportunityId }) => {
const fields: DynamicPropsValue = {};
if (!auth || !opportunityId) return { options: [], disabled: true, placeholder: "Please connect your Capsule CRM account first or select an opportunity" };
await capsuleCrmClient.getOpportunity(
auth,
opportunityId as unknown as number
);
const allCustomFields = await capsuleCrmClient.listCustomFields(
auth
);
const customFieldOptions =
allCustomFields?.map((field) => ({
label: field.name,
value: field.id,
})) ?? [];
fields['customFields'] = Property.Array({
displayName: 'Custom Fields',
required: false,
properties: {
definitionId: Property.StaticDropdown({
displayName: 'Field',
required: true,
options: {
options: customFieldOptions,
},
}),
value: Property.ShortText({
displayName: 'Value',
required: true,
}),
delete: Property.Checkbox({
displayName: 'Delete',
description: 'Check this to delete the custom field value.',
required: false,
}),
},
});
return fields;
},
}),
},
async run(context) {
const { auth, propsValue } = context;
const { opportunityId } = propsValue;
const opportunityData: UpdateOpportunityParams = {
name: propsValue.name,
description: propsValue.description,
expectedCloseOn: propsValue.expectedCloseOn,
probability: propsValue.probability,
durationBasis: propsValue.durationBasis,
duration: propsValue.duration,
};
if (propsValue.ownerId) {
opportunityData.owner = { id: propsValue.ownerId };
}
if (propsValue.teamId) {
opportunityData.team = { id: propsValue.teamId };
}
if (propsValue.milestoneId) {
opportunityData.milestone = { id: propsValue.milestoneId };
}
if (propsValue.currency && propsValue.amount) {
opportunityData.value = {
currency: propsValue.currency,
amount: propsValue.amount,
};
}
const tags = (propsValue.tags as { tags: OpportunityTag[] })?.tags;
if (tags) {
opportunityData.tags = tags.map((tag) => ({
id: tag.id,
name: tag.name,
_delete: tag._delete,
}));
}
const customFields = (
propsValue.customFields as {
customFields: { definitionId: number; value: unknown; delete: boolean }[];
}
)?.customFields;
if (customFields) {
opportunityData.fields = customFields.map((field) => ({
definition: { id: field.definitionId },
value: field.value,
_delete: field.delete,
}));
}
return await capsuleCrmClient.updateOpportunity(
auth,
opportunityId,
opportunityData
);
},
});

View File

@@ -0,0 +1,42 @@
import { OAuth2PropertyValue, PieceAuth } from '@activepieces/pieces-framework';
import {
httpClient,
HttpMethod,
AuthenticationType,
} from '@activepieces/pieces-common';
export const capsuleCrmAuth = PieceAuth.OAuth2({
description: `
To authenticate with Capsule CRM:
1. Go to your Capsule CRM user settings.
2. Navigate to "My Preferences" > "API Authentication Tokens".
3. Register a new application to get a Client ID and Client Secret.
4. Add https://cloud.activepieces.com/redirect to the authorized redirect URIs.
5. Use the OAuth2 flow below.`,
authUrl: 'https://api.capsulecrm.com/oauth/authorise',
tokenUrl: 'https://api.capsulecrm.com/oauth/token',
required: true,
scope: ['read', 'write'],
validate: async ({ auth }) => {
try {
await httpClient.sendRequest({
method: HttpMethod.GET,
url: 'https://api.capsulecrm.com/api/v2/site',
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
});
return {
valid: true,
};
} catch (e) {
return {
valid: false,
error: 'Invalid credentials',
};
}
},
});
export type CapsuleCrmAuthType = OAuth2PropertyValue;

View File

@@ -0,0 +1,778 @@
import {
AuthenticationType,
httpClient,
HttpMethod,
HttpRequest,
} from '@activepieces/pieces-common';
import {
CreateOpportunityParams,
CreatePartyParams,
CreateProjectParams,
Milestone,
Opportunity,
Party,
Project,
UpdateOpportunityParams,
UpdatePartyParams,
Case,
CreateTaskParams,
Task,
User,
Team,
Tag,
CustomField,
CreateNoteParams,
Note,
FindProjectParams,
FindOpportunityParams,
Webhook,
Stage,
Category,
ActivityType,
CreateEntryParams,
Entry,
Filter,
CreateRestHookParams,
RestHook,
} from './types';
import { CapsuleCrmAuthType } from './auth';
export const capsuleCrmClient = {
async createContact(
auth: CapsuleCrmAuthType,
params: CreatePartyParams
): Promise<Party> {
const partyData: { [key: string]: unknown } = {
type: params.type,
};
if (params.type === 'person') {
partyData['firstName'] = params.firstName;
partyData['lastName'] = params.lastName;
} else {
partyData['name'] = params.name;
}
if (params.title) partyData['title'] = params.title;
if (params.jobTitle) partyData['jobTitle'] = params.jobTitle;
if (params.about) partyData['about'] = params.about;
if (params.organisationId) {
partyData['organisation'] = { id: params.organisationId };
}
if (params.ownerId) {
partyData['owner'] = { id: params.ownerId };
}
if (params.teamId) {
partyData['team'] = { id: params.teamId };
}
if (params.tags) {
partyData['tags'] = params.tags.map((tag) => ({ name: tag }));
}
if (params.fields) {
partyData['fields'] = params.fields;
}
if (params.emailAddresses) {
partyData['emailAddresses'] = params.emailAddresses;
}
if (params.phoneNumbers) {
partyData['phoneNumbers'] = params.phoneNumbers;
}
if (params.addresses) {
partyData['addresses'] = params.addresses;
}
if (params.websites) {
partyData['websites'] = params.websites;
}
const request: HttpRequest = {
method: HttpMethod.POST,
url: 'https://api.capsulecrm.com/api/v2/parties',
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
body: {
party: partyData,
},
};
const response = await httpClient.sendRequest<Party>(request);
return response.body;
},
async searchContacts(
auth: CapsuleCrmAuthType,
searchTerm: string
): Promise<Party[]> {
const isSearch = searchTerm && searchTerm.length > 0;
const url = isSearch
? `https://api.capsulecrm.com/api/v2/parties/search`
: `https://api.capsulecrm.com/api/v2/parties`;
const queryParams: Record<string, string> = {};
if (isSearch) {
queryParams['q'] = searchTerm;
}
const request: HttpRequest = {
method: HttpMethod.GET,
url: url,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
queryParams: queryParams,
};
const response = await httpClient.sendRequest<{ parties: Party[] }>(
request
);
return response.body.parties;
},
async searchOrganisations(
auth: CapsuleCrmAuthType,
searchTerm?: string
): Promise<Party[]> {
try {
const url = searchTerm
? `https://api.capsulecrm.com/api/v2/parties/search`
: `https://api.capsulecrm.com/api/v2/parties`;
const queryParams: Record<string, string> = {
perPage: '100',
};
if (searchTerm) {
queryParams['q'] = searchTerm;
}
const request: HttpRequest = {
method: HttpMethod.GET,
url: url,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
queryParams: queryParams,
};
const response = await httpClient.sendRequest<{ parties: Party[] }>(
request
);
if (!response.body || !response.body.parties) {
return [];
}
// Temporarily return all parties to debug
console.log('Parties response:', response.body.parties);
const organisations = response.body.parties.filter(
(party) => party.type === 'organisation'
);
console.log('Filtered organisations:', organisations);
return organisations;
} catch (error) {
console.error('searchOrganisations error:', error);
return [];
}
},
async listTeams(auth: CapsuleCrmAuthType): Promise<Team[]> {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/teams`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
};
const response = await httpClient.sendRequest<{ teams: Team[] }>(request);
return response.body.teams;
},
async listTags(auth: CapsuleCrmAuthType): Promise<Tag[]> {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/parties/tags`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
};
const response = await httpClient.sendRequest<{ tags: Tag[] }>(request);
return response.body.tags;
},
async listCustomFields(auth: CapsuleCrmAuthType): Promise<CustomField[]> {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/parties/fields/definitions`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
};
const response = await httpClient.sendRequest<{
definitions: CustomField[];
}>(request);
return response.body.definitions;
},
async updateContact(
auth: CapsuleCrmAuthType,
partyId: number,
params: UpdatePartyParams
): Promise<Party> {
const partyData: { [key: string]: unknown } = {};
if (params.firstName) partyData['firstName'] = params.firstName;
if (params.lastName) partyData['lastName'] = params.lastName;
if (params.name) partyData['name'] = params.name;
if (params.title) partyData['title'] = params.title;
if (params.about) partyData['about'] = params.about;
if (params.ownerId) partyData['owner'] = { id: params.ownerId };
if (params.teamId) partyData['team'] = { id: params.teamId };
if (params.addresses) partyData['addresses'] = params.addresses;
if (params.websites) partyData['websites'] = params.websites;
if (params.emailAddresses)
partyData['emailAddresses'] = params.emailAddresses;
if (params.phoneNumbers) partyData['phoneNumbers'] = params.phoneNumbers;
const request: HttpRequest = {
method: HttpMethod.PUT,
url: `https://api.capsulecrm.com/api/v2/parties/${partyId}`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
body: {
party: partyData,
},
};
const response = await httpClient.sendRequest<Party>(request);
return response.body;
},
async listMilestones(auth: CapsuleCrmAuthType): Promise<Milestone[]> {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/milestones`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
};
const response = await httpClient.sendRequest<{ milestones: Milestone[] }>(
request
);
return response.body.milestones;
},
async searchOpportunities(
auth: CapsuleCrmAuthType
): Promise<Opportunity[]> {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/opportunities`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
};
const response = await httpClient.sendRequest<{
opportunities: Opportunity[];
}>(request);
return response.body.opportunities;
},
async getOpportunity(
auth: CapsuleCrmAuthType,
opportunityId: number
): Promise<Opportunity> {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/opportunities/${opportunityId}`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
queryParams: {
embed: 'tags,fields',
},
};
const response = await httpClient.sendRequest<{ opportunity: Opportunity }>(
request
);
return response.body.opportunity;
},
async createOpportunity(
auth: CapsuleCrmAuthType,
params: CreateOpportunityParams
): Promise<Opportunity> {
const request: HttpRequest = {
method: HttpMethod.POST,
url: `https://api.capsulecrm.com/api/v2/opportunities`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
body: {
opportunity: params,
},
};
const response = await httpClient.sendRequest<{ opportunity: Opportunity }>(
request
);
return response.body.opportunity;
},
async listOpportunities(auth: CapsuleCrmAuthType): Promise<Opportunity[]> {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/opportunities`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
};
const response = await httpClient.sendRequest<{
opportunities: Opportunity[];
}>(request);
return response.body.opportunities;
},
async updateOpportunity(
auth: CapsuleCrmAuthType,
opportunityId: number,
params: UpdateOpportunityParams
): Promise<Opportunity> {
const request: HttpRequest = {
method: HttpMethod.PUT,
url: `https://api.capsulecrm.com/api/v2/opportunities/${opportunityId}`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
body: {
opportunity: params,
},
};
const response = await httpClient.sendRequest<{ opportunity: Opportunity }>(
request
);
return response.body.opportunity;
},
async listCategories(auth: CapsuleCrmAuthType): Promise<Category[]> {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/categories`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
};
const response = await httpClient.sendRequest<{ categories: Category[] }>(
request
);
return response.body.categories;
},
async searchProjects(auth: CapsuleCrmAuthType): Promise<Project[]> {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/kases`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
};
const response = await httpClient.sendRequest<{ kases: Project[] }>(request);
return response.body.kases;
},
async subscribeRestHook(
auth: CapsuleCrmAuthType,
params: CreateRestHookParams
): Promise<RestHook> {
const request: HttpRequest = {
method: HttpMethod.POST,
url: `https://api.capsulecrm.com/api/v2/resthooks`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
body: {
restHook: params,
},
};
const response = await httpClient.sendRequest<{ restHook: RestHook }>(
request
);
return response.body.restHook;
},
async unsubscribeRestHook(
auth: CapsuleCrmAuthType,
hookId: number
): Promise<void> {
const request: HttpRequest = {
method: HttpMethod.DELETE,
url: `https://api.capsulecrm.com/api/v2/resthooks/${hookId}`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
};
await httpClient.sendRequest(request);
},
async listActivityTypes(auth: CapsuleCrmAuthType): Promise<ActivityType[]> {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/activitytypes`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
};
const response = await httpClient.sendRequest<{
activityTypes: ActivityType[];
}>(request);
return response.body.activityTypes;
},
async findContact(
auth: CapsuleCrmAuthType,
term: string
): Promise<Party[]> {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/parties/search`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
queryParams: {
q: term,
},
};
const response = await httpClient.sendRequest<{ parties: Party[] }>(
request
);
return response.body.parties;
},
async filterOpportunities(
auth: CapsuleCrmAuthType,
filter: Filter
): Promise<Opportunity[]> {
const request: HttpRequest = {
method: HttpMethod.POST,
url: `https://api.capsulecrm.com/api/v2/opportunities/filters/results`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
body: {
filter: filter,
},
};
const response = await httpClient.sendRequest<{
opportunities: Opportunity[];
}>(request);
return response.body.opportunities;
},
async filterProjects(
auth: CapsuleCrmAuthType,
filter: Filter
): Promise<Project[]> {
const request: HttpRequest = {
method: HttpMethod.POST,
url: `https://api.capsulecrm.com/api/v2/kases/filters/results`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
body: {
filter: filter,
},
};
const response = await httpClient.sendRequest<{ kases: Project[] }>(
request
);
return response.body.kases;
},
async listStages(auth: CapsuleCrmAuthType): Promise<Stage[]> {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/stages`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
};
const response = await httpClient.sendRequest<{ stages: Stage[] }>(request);
return response.body.stages;
},
async createProject(
auth: CapsuleCrmAuthType,
params: CreateProjectParams
): Promise<Project> {
const request: HttpRequest = {
method: HttpMethod.POST,
url: `https://api.capsulecrm.com/api/v2/kases`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
body: {
kase: params,
},
};
const response = await httpClient.sendRequest<{ kase: Project }>(request);
return response.body.kase;
},
async listProjects(auth: CapsuleCrmAuthType): Promise<Project[]> {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/kases`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
};
const response = await httpClient.sendRequest<{ kases: Project[] }>(
request
);
return response.body.kases;
},
async listCases(auth: CapsuleCrmAuthType): Promise<Case[]> {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/kases`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
};
const response = await httpClient.sendRequest<{ kases: Case[] }>(request);
return response.body.kases;
},
async listUsers(auth: CapsuleCrmAuthType): Promise<User[]> {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/users`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
};
const response = await httpClient.sendRequest<{ users: User[] }>(request);
return response.body.users;
},
async createEntry(
auth: CapsuleCrmAuthType,
params: CreateEntryParams
): Promise<Entry> {
const request: HttpRequest = {
method: HttpMethod.POST,
url: `https://api.capsulecrm.com/api/v2/entries`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
body: {
entry: params,
},
};
const response = await httpClient.sendRequest<{ entry: Entry }>(request);
return response.body.entry;
},
async createTask(
auth: CapsuleCrmAuthType,
params: CreateTaskParams
): Promise<Task> {
const request: HttpRequest = {
method: HttpMethod.POST,
url: `https://api.capsulecrm.com/api/v2/tasks`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
body: {
task: params,
},
};
const response = await httpClient.sendRequest<{ task: Task }>(request);
return response.body.task;
},
async createNote(
auth: CapsuleCrmAuthType,
params: CreateNoteParams
): Promise<Note> {
const entryData: { [key: string]: unknown } = {
type: 'Note',
content: params.content,
};
if (params.partyId) entryData['party'] = { id: params.partyId };
if (params.opportunityId)
entryData['opportunity'] = { id: params.opportunityId };
if (params.caseId) entryData['case'] = { id: params.caseId };
if (params.projectId) entryData['project'] = { id: params.projectId };
const request: HttpRequest = {
method: HttpMethod.POST,
url: 'https://api.capsulecrm.com/api/v2/entries',
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
body: {
entry: entryData,
},
};
const response = await httpClient.sendRequest<Note>(request);
return response.body;
},
async getContact(
auth: CapsuleCrmAuthType,
contactId: number
): Promise<Party | null> {
try {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/parties/${contactId}`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
queryParams: {
embed: 'addresses,phoneNumbers,websites,emailAddresses',
},
};
const response = await httpClient.sendRequest<{ party: Party }>(request);
return response.body.party;
} catch (e) {
return null;
}
},
async findProject(
auth: CapsuleCrmAuthType,
params: FindProjectParams
): Promise<Project[]> {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/kases`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
queryParams: {
q: params.searchTerm,
},
};
const response = await httpClient.sendRequest<{ kases: Project[] }>(
request
);
return response.body.kases;
},
async getProject(
auth: CapsuleCrmAuthType,
projectId: number
): Promise<Project | null> {
try {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/kases/${projectId}`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
};
const response = await httpClient.sendRequest<{ kase: Project }>(request);
return response.body.kase;
} catch (e) {
return null;
}
},
async findOpportunity(
auth: CapsuleCrmAuthType,
params: FindOpportunityParams
): Promise<Opportunity[]> {
const request: HttpRequest = {
method: HttpMethod.GET,
url: `https://api.capsulecrm.com/api/v2/opportunities/search`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
queryParams: {
q: params.searchTerm,
},
};
const response = await httpClient.sendRequest<{
opportunities: Opportunity[];
}>(request);
return response.body.opportunities;
},
async subscribeWebhook(
auth: CapsuleCrmAuthType,
url: string,
event: string
): Promise<Webhook> {
const request: HttpRequest = {
method: HttpMethod.POST,
url: `https://api.capsulecrm.com/api/v2/webhooks`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
body: {
webhook: {
url: url,
event: event,
},
},
};
const response = await httpClient.sendRequest<{ webhook: Webhook }>(
request
);
return response.body.webhook;
},
async unsubscribeWebhook(
auth: CapsuleCrmAuthType,
webhookId: number
): Promise<void> {
const request: HttpRequest = {
method: HttpMethod.DELETE,
url: `https://api.capsulecrm.com/api/v2/webhooks/${webhookId}`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth.access_token,
},
};
await httpClient.sendRequest(request);
},
};

View File

@@ -0,0 +1,215 @@
import { Property } from '@activepieces/pieces-framework';
import { capsuleCrmAuth, CapsuleCrmAuthType } from './auth';
import { capsuleCrmClient } from './client';
export const capsuleCrmProps = {
contact_id: (required = true) =>
Property.Dropdown({
displayName: 'Contact',
description: 'The contact (Person or Organisation) to select.',
required: required,
refreshers: [],
auth: capsuleCrmAuth,
options: async (props) => {
const { auth } = props;
if (!auth) {
return {
disabled: true,
placeholder: 'Please connect your account first.',
options: [],
};
}
const searchTerm = (props['searchValue'] as string) ?? '';
const contacts = await capsuleCrmClient.searchContacts(
auth,
searchTerm
);
const options = contacts.map((contact) => {
const label =
contact.type === 'person'
? `${contact.firstName} ${contact.lastName}`
: contact.name;
return {
label: label || 'Unnamed Contact',
value: contact.id,
};
});
return {
disabled: false,
options: options,
};
},
}),
milestone_id: (required = true) =>
Property.Dropdown({
displayName: 'Milestone',
description: 'The milestone to assign the opportunity to.',
required: required,
refreshers: [],
auth: capsuleCrmAuth,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Please connect your account first.',
options: [],
};
}
const milestones = await capsuleCrmClient.listMilestones(
auth
);
const options = milestones.map((milestone) => {
return {
label: milestone.name,
value: milestone.id,
};
});
return {
disabled: false,
options: options,
};
},
}),
opportunity_id: (required = true) =>
Property.Dropdown({
displayName: 'Opportunity',
description: 'The opportunity to associate with this item.',
required: required,
refreshers: [],
auth: capsuleCrmAuth,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Please connect your account first.',
options: [],
};
}
const opportunities = await capsuleCrmClient.listOpportunities(
auth
);
return {
disabled: false,
options: opportunities.map((opportunity) => ({
label: opportunity.name,
value: opportunity.id,
})),
};
},
}),
project_id: (required = false) =>
Property.Dropdown({
displayName: 'Project',
description: 'The project to associate this item with.',
required: required,
refreshers: [],
auth: capsuleCrmAuth,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Please connect your account first.',
options: [],
};
}
const projects = await capsuleCrmClient.listProjects(
auth
);
return {
disabled: false,
options: projects.map((project) => ({
label: project.name,
value: project.id,
})),
};
},
}),
case_id: (required = false) =>
Property.Dropdown({
displayName: 'Case',
description: 'The case to associate this item with.',
required: required,
refreshers: [],
auth: capsuleCrmAuth,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Please connect your account first.',
options: [],
};
}
const cases = await capsuleCrmClient.listCases(
auth
);
return {
disabled: false,
options: cases.map((kase) => ({ label: kase.name, value: kase.id })),
};
},
}),
owner_id: (required = false) =>
Property.Dropdown({
auth: capsuleCrmAuth,
displayName: 'Owner',
description: 'The user to assign the task to.',
required: required,
refreshers: [],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Please connect your account first.',
options: [],
};
}
const users = await capsuleCrmClient.listUsers(
auth
);
return {
disabled: false,
options: users.map((user) => ({
label: user.username,
value: user.id,
})),
};
},
}),
team_id: (required = false) =>
Property.Dropdown({
displayName: 'Team',
description: 'The team to assign the contact to.',
required: required,
refreshers: [],
auth: capsuleCrmAuth,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Please connect your account first.',
options: [],
};
}
const teams = await capsuleCrmClient.listTeams(
auth
);
return {
disabled: false,
options: teams.map((team) => ({
label: team.name,
value: team.id,
})),
};
},
}),
};

View File

@@ -0,0 +1,56 @@
import {
createTrigger,
TriggerStrategy,
} from '@activepieces/pieces-framework';
import { capsuleCrmAuth } from './auth';
import { capsuleCrmClient } from './client';
type TriggerParams = {
name: string;
displayName: string;
description: string;
event: string;
sampleData: unknown;
};
export const capsuleCrmCreateTrigger = ({
name,
displayName,
description,
event,
sampleData,
}: TriggerParams) => {
return createTrigger({
auth: capsuleCrmAuth,
name: name,
displayName: displayName,
description: description,
props: {},
type: TriggerStrategy.WEBHOOK,
sampleData: sampleData,
async onEnable(context) {
const hook = await capsuleCrmClient.subscribeRestHook(context.auth, {
targetUrl: context.webhookUrl,
event: event,
description: `Activepieces - ${displayName}`,
});
await context.store.put(`capsule_crm_trigger_${name}`, {
hookId: hook.id,
});
},
async onDisable(context) {
const storedData = await context.store.get<{ hookId: number }>(
`capsule_crm_trigger_${name}`
);
if (storedData) {
await capsuleCrmClient.unsubscribeRestHook(context.auth, storedData.hookId);
}
},
async run(context) {
const body = context.payload.body as { payload: unknown[] };
return body.payload;
},
});
};

View File

@@ -0,0 +1,337 @@
export interface Party {
id: number;
type: 'person' | 'organisation';
firstName?: string;
lastName?: string;
name?: string;
addresses?: {
id: number;
street: string;
city: string;
}[];
websites?: {
id: number;
address: string;
}[];
emailAddresses?: {
id: number;
address: string;
}[];
phoneNumbers?: {
id: number;
number: string;
}[];
}
export interface CreatePartyParams {
type: 'person' | 'organisation';
firstName?: string;
lastName?: string;
name?: string;
emailAddresses?: {
type?: string;
address: string;
}[];
phoneNumbers?: {
type?: string;
number: string;
}[];
title?: string;
jobTitle?: string;
about?: string;
organisationId?: number;
ownerId?: number;
teamId?: number;
tags?: string[];
fields?: { definition: { id: number }; value: unknown }[];
addresses?: {
type?: string;
street?: string;
city?: string;
state?: string;
country?: string;
zip?: string;
}[];
websites?: {
type?: string;
service: string;
address: string;
}[];
}
export interface UpdatePartyParams {
firstName?: string;
lastName?: string;
name?: string;
title?: string;
about?: string;
ownerId?: number;
teamId?: number;
addresses?: {
id?: number;
type?: string;
street?: string;
city?: string;
state?: string;
country?: string;
zip?: string;
_delete?: boolean;
}[];
websites?: {
id?: number;
type?: string;
service?: string;
address?: string;
_delete?: boolean;
}[];
emailAddresses?: {
id?: number;
type?: string;
address?: string;
_delete?: boolean;
}[];
phoneNumbers?: {
id?: number;
type?: string;
number?: string;
_delete?: boolean;
}[];
}
export interface Milestone {
id: number;
name: string;
description?: string;
probability: number;
complete: boolean;
daysUntilStale: number;
}
export interface OpportunityValue {
amount: number;
currency: string;
}
export interface OpportunityCustomField {
id?: number;
definition: {
id: number;
};
value: unknown;
_delete?: boolean;
}
export interface OpportunityTag {
id?: number;
name: string;
_delete?: boolean;
}
export interface Opportunity extends CreateOpportunityParams {
id: number;
createdAt: string;
updatedAt: string;
tags?: OpportunityTag[];
fields?: OpportunityCustomField[];
}
export interface Stage {
id: number;
name: string;
}
export interface CreateProjectParams {
party: { id: number };
name: string;
description?: string;
owner?: { id: number };
team?: { id: number };
status?: 'OPEN' | 'CLOSED';
opportunity?: { id: number };
stage?: { id: number };
expectedCloseOn?: string;
tags?: OpportunityTag[];
fields?: OpportunityCustomField[];
}
export interface Project extends CreateProjectParams {
id: number;
createdAt: string;
updatedAt: string;
closedOn?: string;
}
export interface CreateOpportunityParams {
name: string;
party: {
id: number;
};
milestone: {
id: number;
};
description?: string;
owner?: { id: number };
team?: { id: number };
value?: OpportunityValue;
expectedCloseOn?: string;
probability?: number;
durationBasis?: string;
duration?: number;
tags?: OpportunityTag[];
fields?: OpportunityCustomField[];
}
export interface UpdateOpportunityParams {
name?: string;
description?: string;
owner?: { id: number };
team?: { id: number };
milestone?: { id: number };
value?: OpportunityValue;
expectedCloseOn?: string;
probability?: number;
durationBasis?: string;
duration?: number;
tags?: OpportunityTag[];
fields?: OpportunityCustomField[];
}
export interface Project {
id: number;
name: string;
}
export interface Case {
id: number;
name: string;
}
export interface User {
id: number;
username: string;
name: string;
}
export interface Team {
id: number;
name: string;
}
export interface Tag {
id: number;
name: string;
dataTag: boolean;
}
export interface CustomField {
id: number;
name: string;
type: string;
options?: string[];
}
export interface Task {
id: number;
type: 'Task';
description: string;
}
export interface CreateTaskParams {
description: string;
dueOn: string;
detail?: string;
category?: { id: number };
owner?: { id: number };
party?: { id: number };
opportunity?: { id: number };
kase?: { id: number };
dueTime?: string;
}
export interface Task extends CreateTaskParams {
id: number;
createdAt: string;
updatedAt: string;
status: 'OPEN' | 'COMPLETED' | 'PENDING';
}
export interface ActivityType {
id: number;
name: string;
}
export interface CreateEntryParams {
type: 'note';
content: string;
activityType?: { id: number };
party?: { id: number };
opportunity?: { id: number };
kase?: { id: number };
}
export interface Entry extends CreateEntryParams {
id: number;
createdAt: string;
updatedAt: string;
}
export interface Note {
id: number;
type: 'Note';
content: string;
}
export interface CreateNoteParams {
content: string;
partyId?: number;
opportunityId?: number;
caseId?: number;
projectId?: number;
}
export interface FindContactParams {
email?: string;
searchTerm?: string;
}
export interface FindProjectParams {
searchTerm: string;
}
export interface FindOpportunityParams {
searchTerm: string;
}
export interface Webhook {
id: number;
url: string;
event: string;
}
export interface Category {
id: number;
name: string;
colour: string;
}
export interface FilterCondition {
field: string;
operator: string;
value: string | number | boolean;
}
export interface Filter {
conditions: FilterCondition[];
}
export interface RestHook {
id: number;
event: string;
targetUrl: string;
}
export interface CreateRestHookParams {
event: string;
targetUrl: string;
description: string;
}

View File

@@ -0,0 +1,38 @@
import { capsuleCrmCreateTrigger } from '../common/trigger';
export const newCaseTrigger = capsuleCrmCreateTrigger({
name: 'new_case',
displayName: 'New Case',
description: 'Fires when a new case (project) is created in Capsule CRM.',
event: 'kase/created',
sampleData: {
event: 'kase/created',
payload: [
{
id: 12,
party: {
id: 892,
type: 'organisation',
name: 'Zestia',
pictureURL:
'https://capsulecrm.com/theme/default/images/org_avatar_70.png',
},
owner: {
id: 61,
username: 'ted',
name: 'Ted Danson',
},
status: 'OPEN',
stage: {
name: 'Project Brief',
id: 149,
},
createdAt: '2015-12-07T16:54:27Z',
updatedAt: '2015-12-07T16:54:27Z',
expectedCloseOn: '2015-12-09',
description: 'Scope and design web site shopping cart',
name: 'Consulting',
},
],
},
});

View File

@@ -0,0 +1,46 @@
import { capsuleCrmCreateTrigger } from '../common/trigger';
export const newOpportunityTrigger = capsuleCrmCreateTrigger({
name: 'new_opportunity',
displayName: 'New Opportunity',
description: 'Fires when a new opportunity is created.',
event: 'opportunity/created',
sampleData: {
event: 'opportunity/created',
payload: [
{
id: 83948362,
updatedAt: '2015-10-29T12:55:12Z',
description: 'Scope and design web site shopping cart',
owner: {
id: 6,
username: 'scottspacey',
name: 'Scott Spacey',
},
party: {
id: 581,
pictureURL:
'https://capsulecrm.com/theme/default/images/person_avatar_70.png',
type: 'organisation',
name: 'Capsule',
},
lostReason: null,
milestone: {
id: 14,
name: 'Bid',
},
value: {
amount: 500,
currency: 'GBP',
},
expectedCloseOn: '2015-10-31',
probability: 50,
durationBasis: 'FIXED',
duration: null,
closedOn: null,
createdAt: '2015-10-29T12:55:12Z',
name: 'Consulting',
},
],
},
});

View File

@@ -0,0 +1,38 @@
import { capsuleCrmCreateTrigger } from '../common/trigger';
export const newProjectTrigger = capsuleCrmCreateTrigger({
name: 'new_project',
displayName: 'New Project',
description: 'Fires when a project is created.',
event: 'kase/created',
sampleData: {
event: 'kase/created',
payload: [
{
id: 12,
party: {
id: 892,
type: 'organisation',
name: 'Zestia',
pictureURL:
'https://capsulecrm.com/theme/default/images/org_avatar_70.png',
},
owner: {
id: 61,
username: 'ted',
name: 'Ted Danson',
},
status: 'OPEN',
stage: {
name: 'Project Brief',
id: 149,
},
createdAt: '2015-12-07T16:54:27Z',
updatedAt: '2015-12-07T16:54:27Z',
expectedCloseOn: '2015-12-09',
description: 'Scope and design web site shopping cart',
name: 'Consulting',
},
],
},
});

View File

@@ -0,0 +1,36 @@
import { capsuleCrmCreateTrigger } from '../common/trigger';
export const newTaskTrigger = capsuleCrmCreateTrigger({
name: 'new_task',
displayName: 'New Task',
description: 'Fires when a new task is created.',
event: 'task/created',
sampleData: {
event: 'task/created',
payload: [
{
id: 530,
description: 'Email product details',
dueTime: '18:00:00',
status: 'OPEN',
party: {
id: 11587,
type: 'person',
firstName: 'Scott',
lastName: 'Spacey',
pictureURL:
'https://capsulecrm.com/theme/default/images/person_avatar_70.png',
},
owner: {
id: 1,
username: 'john',
name: 'John Spacey',
},
createdAt: '2015-12-21T13:51:38Z',
updatedAt: '2015-12-21T13:51:38Z',
dueOn: '2014-05-20',
hasTrack: false,
},
],
},
});

View File

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

View File

@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../../dist/out-tsc",
"declaration": true,
"types": ["node"]
},
"include": ["src/**/*.ts"]
}