From 550cd630a66c05ef2c0011e8776bcaa76e2fc85c Mon Sep 17 00:00:00 2001 From: Michelle Bergeron Date: Mon, 6 Jul 2026 12:15:07 -0400 Subject: [PATCH 1/5] feat(pipedrive): add Projects, Tasks, and related list actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds action coverage for Pipedrive Projects (surfaced in the Pipedrive UI as a project-management add-on) so AI agents can create, update, delete, list, and inspect projects and their tasks — the direct ask in #20984 from the Viktor-in-Slack user. Also expands read coverage on other entities that AI agents commonly need to reach when following project/task flows (persons, organizations, filters), each modeled after the existing `list-deals` shape. New actions: Projects - pipedrive-create-project - pipedrive-get-project - pipedrive-update-project - pipedrive-delete-project - pipedrive-list-projects - pipedrive-list-project-boards - pipedrive-list-project-phases Tasks - pipedrive-create-task - pipedrive-get-task - pipedrive-update-task - pipedrive-delete-task - pipedrive-list-tasks Adjacent lists (used constantly by AI agents while working with projects and tasks) - pipedrive-list-persons - pipedrive-list-organizations - pipedrive-list-filters App-level changes (pipedrive.app.mjs, +82 lines): - New methods wrapping the SDK's ProjectsApi, TasksApi, and the v2 Persons / Organizations endpoints (getPersons and getOrganizations are already used by other options() pickers; the new list actions reuse them). - New propDefinitions where the existing set didn't cover the fields the project/task endpoints need. Constants (common/constants.mjs): - PROJECT_STATUS_OPTIONS, PERSON_SORT_BY_OPTIONS, PERSON_INCLUDE_FIELDS_OPTIONS, ORGANIZATION_SORT_BY_OPTIONS, ORGANIZATION_INCLUDE_FIELDS_OPTIONS, FILTER_TYPE_OPTIONS — enum values pulled directly from Pipedrive's v1 and v2 OpenAPI specs so the option lists don't drift from what the API actually accepts. Closes #20984 --- .../actions/create-project/create-project.mjs | 108 +++++++++++++ .../actions/create-task/create-task.mjs | 96 +++++++++++ .../actions/delete-project/delete-project.mjs | 27 ++++ .../actions/delete-task/delete-task.mjs | 27 ++++ .../actions/get-project/get-project.mjs | 27 ++++ .../pipedrive/actions/get-task/get-task.mjs | 27 ++++ .../actions/list-filters/list-filters.mjs | 32 ++++ .../list-organizations/list-organizations.mjs | 135 ++++++++++++++++ .../actions/list-persons/list-persons.mjs | 151 ++++++++++++++++++ .../list-project-boards.mjs | 24 +++ .../list-project-phases.mjs | 30 ++++ .../actions/list-projects/list-projects.mjs | 84 ++++++++++ .../actions/list-tasks/list-tasks.mjs | 74 +++++++++ .../actions/update-project/update-project.mjs | 87 ++++++++++ .../actions/update-task/update-task.mjs | 90 +++++++++++ components/pipedrive/common/constants.mjs | 84 ++++++++++ components/pipedrive/package.json | 2 +- components/pipedrive/pipedrive.app.mjs | 84 ++++++++++ 18 files changed, 1188 insertions(+), 1 deletion(-) create mode 100644 components/pipedrive/actions/create-project/create-project.mjs create mode 100644 components/pipedrive/actions/create-task/create-task.mjs create mode 100644 components/pipedrive/actions/delete-project/delete-project.mjs create mode 100644 components/pipedrive/actions/delete-task/delete-task.mjs create mode 100644 components/pipedrive/actions/get-project/get-project.mjs create mode 100644 components/pipedrive/actions/get-task/get-task.mjs create mode 100644 components/pipedrive/actions/list-filters/list-filters.mjs create mode 100644 components/pipedrive/actions/list-organizations/list-organizations.mjs create mode 100644 components/pipedrive/actions/list-persons/list-persons.mjs create mode 100644 components/pipedrive/actions/list-project-boards/list-project-boards.mjs create mode 100644 components/pipedrive/actions/list-project-phases/list-project-phases.mjs create mode 100644 components/pipedrive/actions/list-projects/list-projects.mjs create mode 100644 components/pipedrive/actions/list-tasks/list-tasks.mjs create mode 100644 components/pipedrive/actions/update-project/update-project.mjs create mode 100644 components/pipedrive/actions/update-task/update-task.mjs diff --git a/components/pipedrive/actions/create-project/create-project.mjs b/components/pipedrive/actions/create-project/create-project.mjs new file mode 100644 index 0000000000000..304dc6cb5c86d --- /dev/null +++ b/components/pipedrive/actions/create-project/create-project.mjs @@ -0,0 +1,108 @@ +import pipedriveApp from "../../pipedrive.app.mjs"; +import constants from "../../common/constants.mjs"; + +export default { + key: "pipedrive-create-project", + name: "Create Project", + description: "Creates a new project in Pipedrive. Use **List Project Boards** to obtain a valid Board ID and **List Project Phases** to obtain a valid Phase ID before running this action. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Projects#addProject)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + props: { + pipedriveApp, + title: { + type: "string", + label: "Title", + description: "The title of the project.", + }, + description: { + type: "string", + label: "Description", + description: "The description of the project.", + optional: true, + }, + status: { + type: "string", + label: "Status", + description: "The status of the project. One of: open, completed, canceled, deleted.", + options: constants.PROJECT_STATUS_OPTIONS, + optional: true, + }, + boardId: { + type: "string", + label: "Board ID", + description: "The ID of the board this project belongs to. Run **List Project Boards** first to obtain a valid board ID.", + optional: true, + }, + phaseId: { + type: "string", + label: "Phase ID", + description: "The ID of the phase this project belongs to. Run **List Project Phases** (with the chosen board ID) first to obtain a valid phase ID.", + optional: true, + }, + ownerId: { + type: "string", + label: "Owner ID", + description: "The user ID of the project owner. Run **List User ID Options** to obtain a valid user ID.", + optional: true, + }, + startDate: { + type: "string", + label: "Start Date", + description: "The start date of the project. Format: YYYY-MM-DD (e.g. 2026-07-31).", + optional: true, + }, + endDate: { + type: "string", + label: "End Date", + description: "The end date of the project. Format: YYYY-MM-DD (e.g. 2026-08-31).", + optional: true, + }, + dealIds: { + type: "string[]", + label: "Deal IDs", + description: "Array of deal IDs to associate with the project. Use **List Deals** to obtain a valid deal ID.", + optional: true, + }, + personIds: { + type: "string[]", + label: "Person IDs", + description: "Array of person IDs to associate with the project. Use **List Persons** to obtain a valid person ID.", + optional: true, + }, + orgIds: { + type: "string[]", + label: "Organization IDs", + description: "Array of organization IDs to associate with the project. Use **List Organizations** to obtain a valid organization ID.", + optional: true, + }, + labelIds: { + type: "string[]", + label: "Label IDs", + description: "Array of label IDs to associate with the project.", + optional: true, + }, + }, + async run({ $ }) { + const response = await this.pipedriveApp.addProject({ + title: this.title, + description: this.description, + status: this.status, + board_id: this.boardId, + phase_id: this.phaseId, + owner_id: this.ownerId, + start_date: this.startDate, + end_date: this.endDate, + deal_ids: this.dealIds, + person_ids: this.personIds, + org_ids: this.orgIds, + label_ids: this.labelIds, + }); + $.export("$summary", `Successfully created project ${response.data?.id}: ${this.title}`); + return response; + }, +}; diff --git a/components/pipedrive/actions/create-task/create-task.mjs b/components/pipedrive/actions/create-task/create-task.mjs new file mode 100644 index 0000000000000..338a76f7e29bf --- /dev/null +++ b/components/pipedrive/actions/create-task/create-task.mjs @@ -0,0 +1,96 @@ +import pipedriveApp from "../../pipedrive.app.mjs"; + +export default { + key: "pipedrive-create-task", + name: "Create Task", + description: "Creates a new task under a project (BETA). Run **List Projects** first to obtain a valid project ID. Use **List User ID Options** for the assignee ID. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Tasks#addTask)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + props: { + pipedriveApp, + title: { + type: "string", + label: "Title", + description: "The title of the task.", + }, + projectId: { + type: "string", + label: "Project ID", + description: "The ID of the project this task belongs to. Run **List Projects** first to obtain a valid project ID.", + }, + parentTaskId: { + type: "string", + label: "Parent Task ID", + description: "The ID of the parent task, if this is a subtask. Use **List Tasks** to obtain a valid task ID.", + optional: true, + }, + description: { + type: "string", + label: "Description", + description: "The description of the task.", + optional: true, + }, + done: { + type: "integer", + label: "Done", + description: "Whether the task is done. Integer: 0 (not done) or 1 (done).", + min: 0, + max: 1, + optional: true, + }, + milestone: { + type: "integer", + label: "Milestone", + description: "Whether the task is a milestone. Integer: 0 (no) or 1 (yes).", + min: 0, + max: 1, + optional: true, + }, + dueDate: { + type: "string", + label: "Due Date", + description: "The due date of the task. Format: YYYY-MM-DD (e.g. 2026-07-31).", + optional: true, + }, + startDate: { + type: "string", + label: "Start Date", + description: "The start date of the task. Format: YYYY-MM-DD.", + optional: true, + }, + assigneeId: { + type: "string", + label: "Assignee ID", + description: "The user ID of the task assignee. Run **List User ID Options** to obtain a valid user ID.", + optional: true, + }, + priority: { + type: "integer", + label: "Priority", + description: "The priority of the task (non-negative integer).", + min: 0, + optional: true, + }, + }, + async run({ $ }) { + const response = await this.pipedriveApp.addTask({ + title: this.title, + project_id: this.projectId, + parent_task_id: this.parentTaskId, + description: this.description, + done: this.done, + milestone: this.milestone, + due_date: this.dueDate, + start_date: this.startDate, + assignee_id: this.assigneeId, + priority: this.priority, + }); + $.export("$summary", `Successfully created task ${response.data?.id}: ${this.title}`); + return response; + }, +}; diff --git a/components/pipedrive/actions/delete-project/delete-project.mjs b/components/pipedrive/actions/delete-project/delete-project.mjs new file mode 100644 index 0000000000000..3e8c6149b2100 --- /dev/null +++ b/components/pipedrive/actions/delete-project/delete-project.mjs @@ -0,0 +1,27 @@ +import pipedriveApp from "../../pipedrive.app.mjs"; + +export default { + key: "pipedrive-delete-project", + name: "Delete Project", + description: "Permanently deletes a project. This is irreversible. Run **List Projects** first to obtain a valid project ID. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Projects#deleteProject)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: true, + openWorldHint: true, + readOnlyHint: false, + }, + props: { + pipedriveApp, + projectId: { + type: "string", + label: "Project ID", + description: "The ID of the project to delete. Run **List Projects** first to obtain a valid project ID.", + }, + }, + async run({ $ }) { + const response = await this.pipedriveApp.deleteProject(this.projectId); + $.export("$summary", `Successfully deleted project ${this.projectId}`); + return response; + }, +}; diff --git a/components/pipedrive/actions/delete-task/delete-task.mjs b/components/pipedrive/actions/delete-task/delete-task.mjs new file mode 100644 index 0000000000000..ad4e23fc87028 --- /dev/null +++ b/components/pipedrive/actions/delete-task/delete-task.mjs @@ -0,0 +1,27 @@ +import pipedriveApp from "../../pipedrive.app.mjs"; + +export default { + key: "pipedrive-delete-task", + name: "Delete Task", + description: "Permanently deletes a task and all of its subtasks (BETA). This is irreversible. Run **List Tasks** first to obtain a valid task ID. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Tasks#deleteTask)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: true, + openWorldHint: true, + readOnlyHint: false, + }, + props: { + pipedriveApp, + taskId: { + type: "string", + label: "Task ID", + description: "The ID of the task to delete. Run **List Tasks** first to obtain a valid task ID.", + }, + }, + async run({ $ }) { + const response = await this.pipedriveApp.deleteTask(this.taskId); + $.export("$summary", `Successfully deleted task ${this.taskId}`); + return response; + }, +}; diff --git a/components/pipedrive/actions/get-project/get-project.mjs b/components/pipedrive/actions/get-project/get-project.mjs new file mode 100644 index 0000000000000..32a06a609be29 --- /dev/null +++ b/components/pipedrive/actions/get-project/get-project.mjs @@ -0,0 +1,27 @@ +import pipedriveApp from "../../pipedrive.app.mjs"; + +export default { + key: "pipedrive-get-project", + name: "Get Project", + description: "Gets a single project by its ID. Run **List Projects** first to obtain a valid project ID. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Projects#getProject)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: true, + }, + props: { + pipedriveApp, + projectId: { + type: "string", + label: "Project ID", + description: "The ID of the project to retrieve. Run **List Projects** first to obtain a valid project ID.", + }, + }, + async run({ $ }) { + const response = await this.pipedriveApp.getProject(this.projectId); + $.export("$summary", `Successfully retrieved project ${this.projectId}`); + return response; + }, +}; diff --git a/components/pipedrive/actions/get-task/get-task.mjs b/components/pipedrive/actions/get-task/get-task.mjs new file mode 100644 index 0000000000000..55344172f9575 --- /dev/null +++ b/components/pipedrive/actions/get-task/get-task.mjs @@ -0,0 +1,27 @@ +import pipedriveApp from "../../pipedrive.app.mjs"; + +export default { + key: "pipedrive-get-task", + name: "Get Task", + description: "Gets a single task by its ID (BETA). Run **List Tasks** first to obtain a valid task ID. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Tasks#getTask)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: true, + }, + props: { + pipedriveApp, + taskId: { + type: "string", + label: "Task ID", + description: "The ID of the task to retrieve. Run **List Tasks** first to obtain a valid task ID.", + }, + }, + async run({ $ }) { + const response = await this.pipedriveApp.getTask(this.taskId); + $.export("$summary", `Successfully retrieved task ${this.taskId}`); + return response; + }, +}; diff --git a/components/pipedrive/actions/list-filters/list-filters.mjs b/components/pipedrive/actions/list-filters/list-filters.mjs new file mode 100644 index 0000000000000..caebae031fe87 --- /dev/null +++ b/components/pipedrive/actions/list-filters/list-filters.mjs @@ -0,0 +1,32 @@ +import pipedriveApp from "../../pipedrive.app.mjs"; +import constants from "../../common/constants.mjs"; + +export default { + key: "pipedrive-list-filters", + name: "List Filters", + description: "List filters in your Pipedrive account, optionally scoped to a single entity type. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Filters#getFilters)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: true, + }, + props: { + pipedriveApp, + type: { + type: "string", + label: "Type", + description: "The entity type to filter by. When omitted, filters of every type are returned.", + options: constants.FILTER_TYPE_OPTIONS, + optional: true, + }, + }, + async run({ $ }) { + const response = await this.pipedriveApp.getFilters({ + type: this.type, + }); + $.export("$summary", `Successfully listed ${response.data?.length ?? 0} filter(s)`); + return response; + }, +}; diff --git a/components/pipedrive/actions/list-organizations/list-organizations.mjs b/components/pipedrive/actions/list-organizations/list-organizations.mjs new file mode 100644 index 0000000000000..5866368e4ee11 --- /dev/null +++ b/components/pipedrive/actions/list-organizations/list-organizations.mjs @@ -0,0 +1,135 @@ +import pipedriveApp from "../../pipedrive.app.mjs"; +import constants from "../../common/constants.mjs"; + +export default { + key: "pipedrive-list-organizations", + name: "List Organizations", + description: "List organizations in your Pipedrive account. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Organizations#getOrganizations)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: true, + }, + props: { + pipedriveApp, + filterId: { + propDefinition: [ + pipedriveApp, + "filterId", + () => ({ + filterType: "org", + }), + ], + label: "Filter ID", + description: "The ID of the filter to apply to organizations", + }, + organizationIds: { + propDefinition: [ + pipedriveApp, + "organizationId", + ], + type: "string[]", + label: "Organization IDs", + description: "The IDs of the organizations to list (up to 100). **Filter ID** takes precedence over **Organization IDs** when supplied.", + }, + ownerId: { + propDefinition: [ + pipedriveApp, + "userId", + ], + label: "Owner ID", + description: "ID of the user who owns the organization. If omitted, organizations owned by any user are returned. **Filter ID** takes precedence over **Owner ID** when supplied.", + }, + updatedSince: { + type: "string", + label: "Updated Since", + description: "If set, only organizations with an update_time later than or equal to this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z.", + optional: true, + }, + updatedUntil: { + type: "string", + label: "Updated Until", + description: "If set, only organizations with an update_time earlier than this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z.", + optional: true, + }, + sortBy: { + type: "string", + label: "Sort By", + description: "The field to sort by", + options: constants.ORGANIZATION_SORT_BY_OPTIONS, + optional: true, + }, + sortDirection: { + type: "string", + label: "Sort Direction", + description: "The direction to sort by", + options: constants.SORT_DIRECTION_OPTIONS, + optional: true, + }, + includeFields: { + type: "string[]", + label: "Include Fields", + description: "Additional fields to include in the response", + options: constants.ORGANIZATION_INCLUDE_FIELDS_OPTIONS, + optional: true, + }, + customFields: { + type: "string[]", + label: "Custom Fields", + description: "Optional string array of custom field keys to include in the response.", + optional: true, + }, + includeOptionLabels: { + type: "boolean", + label: "Include Option Labels", + description: "When `true`, single-option and multi-option custom field values include the option labels alongside their IDs. Defaults to `false`.", + optional: true, + }, + includeLabels: { + type: "boolean", + label: "Include Labels", + description: "When `true`, the response includes an array of label objects (`{ id, label, color }`) for each organization. Defaults to `false`.", + optional: true, + }, + limit: { + type: "integer", + label: "Limit", + description: "For pagination, the limit of entries to be returned. If not provided, 100 items will be returned. Maximum allowed value is 500.", + max: 500, + optional: true, + }, + cursor: { + type: "string", + label: "Cursor", + description: "For pagination, the cursor to the next page of results. If not provided, the first page will be returned.", + optional: true, + }, + }, + async run({ $ }) { + const response = await this.pipedriveApp.getOrganizations({ + filter_id: this.filterId, + ids: this.organizationIds + ? this.organizationIds.join(",") + : undefined, + owner_id: this.ownerId, + updated_since: this.updatedSince, + updated_until: this.updatedUntil, + sort_by: this.sortBy, + sort_direction: this.sortDirection, + include_fields: this.includeFields + ? this.includeFields.join(",") + : undefined, + custom_fields: this.customFields + ? this.customFields.join(",") + : undefined, + include_option_labels: this.includeOptionLabels, + include_labels: this.includeLabels, + limit: this.limit, + cursor: this.cursor, + }); + $.export("$summary", `Successfully listed ${response.data?.length ?? 0} organization(s)`); + return response; + }, +}; diff --git a/components/pipedrive/actions/list-persons/list-persons.mjs b/components/pipedrive/actions/list-persons/list-persons.mjs new file mode 100644 index 0000000000000..33f1b6bb55702 --- /dev/null +++ b/components/pipedrive/actions/list-persons/list-persons.mjs @@ -0,0 +1,151 @@ +import pipedriveApp from "../../pipedrive.app.mjs"; +import constants from "../../common/constants.mjs"; + +export default { + key: "pipedrive-list-persons", + name: "List Persons", + description: "List persons in your Pipedrive account. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Persons#getPersons)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: true, + }, + props: { + pipedriveApp, + filterId: { + propDefinition: [ + pipedriveApp, + "filterId", + () => ({ + filterType: "people", + }), + ], + label: "Filter ID", + description: "The ID of the filter to apply to persons", + }, + personIds: { + propDefinition: [ + pipedriveApp, + "personId", + ], + type: "string[]", + label: "Person IDs", + description: "The IDs of the persons to list (up to 100). **Filter ID** takes precedence over **Person IDs** when supplied.", + }, + ownerId: { + propDefinition: [ + pipedriveApp, + "userId", + ], + label: "Owner ID", + description: "ID of the user who owns the person. If omitted, persons owned by any user are returned. **Filter ID** takes precedence over **Owner ID** when supplied.", + }, + organizationId: { + propDefinition: [ + pipedriveApp, + "organizationId", + ], + description: "If supplied, only persons linked to the given organization will be returned. **Filter ID** takes precedence over **Organization ID** when supplied.", + }, + dealId: { + propDefinition: [ + pipedriveApp, + "dealId", + ], + description: "If supplied, only persons linked to the given deal will be returned. **Filter ID** takes precedence over **Deal ID** when supplied.", + }, + updatedSince: { + type: "string", + label: "Updated Since", + description: "If set, only persons with an update_time later than or equal to this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z.", + optional: true, + }, + updatedUntil: { + type: "string", + label: "Updated Until", + description: "If set, only persons with an update_time earlier than this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z.", + optional: true, + }, + sortBy: { + type: "string", + label: "Sort By", + description: "The field to sort by", + options: constants.PERSON_SORT_BY_OPTIONS, + optional: true, + }, + sortDirection: { + type: "string", + label: "Sort Direction", + description: "The direction to sort by", + options: constants.SORT_DIRECTION_OPTIONS, + optional: true, + }, + includeFields: { + type: "string[]", + label: "Include Fields", + description: "Additional fields to include in the response. `marketing_status` and `doi_status` can only be included when the user's country is set in Pipedrive.", + options: constants.PERSON_INCLUDE_FIELDS_OPTIONS, + optional: true, + }, + customFields: { + type: "string[]", + label: "Custom Fields", + description: "Optional string array of custom field keys to include in the response.", + optional: true, + }, + includeOptionLabels: { + type: "boolean", + label: "Include Option Labels", + description: "When `true`, single-option and multi-option custom field values include the option labels alongside their IDs. Defaults to `false`.", + optional: true, + }, + includeLabels: { + type: "boolean", + label: "Include Labels", + description: "When `true`, the response includes an array of label objects (`{ id, label, color }`) for each person. Defaults to `false`.", + optional: true, + }, + limit: { + type: "integer", + label: "Limit", + description: "For pagination, the limit of entries to be returned. If not provided, 100 items will be returned. Maximum allowed value is 500.", + max: 500, + optional: true, + }, + cursor: { + type: "string", + label: "Cursor", + description: "For pagination, the cursor to the next page of results. If not provided, the first page will be returned.", + optional: true, + }, + }, + async run({ $ }) { + const response = await this.pipedriveApp.getPersons({ + filter_id: this.filterId, + ids: this.personIds + ? this.personIds.join(",") + : undefined, + owner_id: this.ownerId, + org_id: this.organizationId, + deal_id: this.dealId, + updated_since: this.updatedSince, + updated_until: this.updatedUntil, + sort_by: this.sortBy, + sort_direction: this.sortDirection, + include_fields: this.includeFields + ? this.includeFields.join(",") + : undefined, + custom_fields: this.customFields + ? this.customFields.join(",") + : undefined, + include_option_labels: this.includeOptionLabels, + include_labels: this.includeLabels, + limit: this.limit, + cursor: this.cursor, + }); + $.export("$summary", `Successfully listed ${response.data?.length ?? 0} person(s)`); + return response; + }, +}; diff --git a/components/pipedrive/actions/list-project-boards/list-project-boards.mjs b/components/pipedrive/actions/list-project-boards/list-project-boards.mjs new file mode 100644 index 0000000000000..fbb280b0545a6 --- /dev/null +++ b/components/pipedrive/actions/list-project-boards/list-project-boards.mjs @@ -0,0 +1,24 @@ +import pipedriveApp from "../../pipedrive.app.mjs"; + +export default { + key: "pipedrive-list-project-boards", + name: "List Project Boards", + description: "Lists all active project boards. Run this first to obtain a valid board ID for **Create Project**, **Update Project**, and **List Project Phases**. [See the documentation](https://developers.pipedrive.com/docs/api/v1/ProjectBoards)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: true, + }, + props: { + pipedriveApp, + }, + async run({ $ }) { + const response = await this.pipedriveApp.getProjectBoards({ + $, + }); + $.export("$summary", `Successfully listed ${response.data?.length ?? 0} project boards`); + return response; + }, +}; diff --git a/components/pipedrive/actions/list-project-phases/list-project-phases.mjs b/components/pipedrive/actions/list-project-phases/list-project-phases.mjs new file mode 100644 index 0000000000000..7a0bd09bcfb49 --- /dev/null +++ b/components/pipedrive/actions/list-project-phases/list-project-phases.mjs @@ -0,0 +1,30 @@ +import pipedriveApp from "../../pipedrive.app.mjs"; + +export default { + key: "pipedrive-list-project-phases", + name: "List Project Phases", + description: "Lists the phases for a given board. Run **List Project Boards** first to obtain a board ID, then run this to obtain a valid phase ID for **Create Project** or **Update Project**. [See the documentation](https://developers.pipedrive.com/docs/api/v1/ProjectPhases)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: true, + }, + props: { + pipedriveApp, + boardId: { + type: "string", + label: "Board ID", + description: "The ID of the board to list phases for (required by the API). Run **List Project Boards** first to obtain a valid board ID.", + }, + }, + async run({ $ }) { + const response = await this.pipedriveApp.getProjectPhases({ + boardId: this.boardId, + $, + }); + $.export("$summary", `Successfully listed ${response.data?.length ?? 0} phases for board ${this.boardId}`); + return response; + }, +}; diff --git a/components/pipedrive/actions/list-projects/list-projects.mjs b/components/pipedrive/actions/list-projects/list-projects.mjs new file mode 100644 index 0000000000000..b67ca67987fd4 --- /dev/null +++ b/components/pipedrive/actions/list-projects/list-projects.mjs @@ -0,0 +1,84 @@ +import pipedriveApp from "../../pipedrive.app.mjs"; +import constants from "../../common/constants.mjs"; + +export default { + key: "pipedrive-list-projects", + name: "List Projects", + description: "Lists projects in your Pipedrive account. Use the returned IDs with **Get Project**, **Update Project**, **Delete Project**, or **Create Task**. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Projects#getProjects)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: true, + }, + props: { + pipedriveApp, + status: { + type: "string", + label: "Status", + description: "Filter by project status. One of: open, completed, canceled, deleted (deleted excluded by default).", + options: constants.PROJECT_STATUS_OPTIONS, + optional: true, + }, + phaseId: { + type: "string", + label: "Phase ID", + description: "Filter by phase ID. Run **List Project Phases** first to obtain a valid phase ID.", + optional: true, + }, + dealId: { + type: "string", + label: "Deal ID", + description: "Filter by associated deal ID.", + optional: true, + }, + personId: { + type: "string", + label: "Person ID", + description: "Filter by associated person ID. Use **List Persons** to obtain a valid person ID.", + optional: true, + }, + orgId: { + type: "string", + label: "Organization ID", + description: "Filter by associated organization ID. Use **List Organizations** to obtain a valid organization ID.", + optional: true, + }, + filterId: { + type: "integer", + label: "Filter ID", + description: "The ID of the filter to apply to projects. Use **List Filters** to obtain a valid filter ID.", + min: 1, + optional: true, + }, + limit: { + type: "integer", + label: "Limit", + description: "For pagination, the number of entries to return. Min 1, max 1000. Note: the API enforces a server-side cap of 500. Defaults to 100 if omitted.", + min: 1, + max: 1000, + optional: true, + }, + cursor: { + type: "string", + label: "Cursor", + description: "For pagination, the cursor to the next page of results (from additional_data.next_cursor). If omitted, the first page is returned.", + optional: true, + }, + }, + async run({ $ }) { + const response = await this.pipedriveApp.listProjects({ + status: this.status, + phase_id: this.phaseId, + deal_id: this.dealId, + person_id: this.personId, + org_id: this.orgId, + filter_id: this.filterId, + limit: this.limit, + cursor: this.cursor, + }); + $.export("$summary", `Successfully listed ${response.data?.length ?? 0} projects`); + return response; + }, +}; diff --git a/components/pipedrive/actions/list-tasks/list-tasks.mjs b/components/pipedrive/actions/list-tasks/list-tasks.mjs new file mode 100644 index 0000000000000..eaa42d1b39b55 --- /dev/null +++ b/components/pipedrive/actions/list-tasks/list-tasks.mjs @@ -0,0 +1,74 @@ +import pipedriveApp from "../../pipedrive.app.mjs"; + +export default { + key: "pipedrive-list-tasks", + name: "List Tasks", + description: "Lists tasks in your Pipedrive account (BETA). Use **List Projects** to obtain a project ID to filter by. Use the returned IDs with **Get Task**, **Update Task**, or **Delete Task**. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Tasks#getTasks)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: true, + }, + props: { + pipedriveApp, + projectId: { + type: "string", + label: "Project ID", + description: "Filter tasks by project ID. Run **List Projects** first to obtain a valid project ID.", + optional: true, + }, + assigneeId: { + type: "string", + label: "Assignee ID", + description: "Filter tasks by assignee (user) ID. Run **List User ID Options** to obtain a valid user ID.", + optional: true, + }, + parentTaskId: { + type: "string", + label: "Parent Task ID", + description: "Filter by parent task ID. Omit for root-level tasks only; provide an integer to return subtasks of that task.", + optional: true, + }, + isDone: { + type: "boolean", + label: "Is Done", + description: "Filter by completion state (true = done, false = not done).", + optional: true, + }, + isMilestone: { + type: "boolean", + label: "Is Milestone", + description: "Filter to only milestone tasks (true) or non-milestone tasks (false).", + optional: true, + }, + limit: { + type: "integer", + label: "Limit", + description: "For pagination, the number of entries to return. Min 1, max 500 (the API cap). Defaults to 100 if omitted.", + min: 1, + max: 500, + optional: true, + }, + cursor: { + type: "string", + label: "Cursor", + description: "For pagination, the cursor to the next page of results (from additional_data.next_cursor). If omitted, the first page is returned.", + optional: true, + }, + }, + async run({ $ }) { + const response = await this.pipedriveApp.listTasks({ + project_id: this.projectId, + assignee_id: this.assigneeId, + parent_task_id: this.parentTaskId, + is_done: this.isDone, + is_milestone: this.isMilestone, + limit: this.limit, + cursor: this.cursor, + }); + $.export("$summary", `Successfully listed ${response.data?.length ?? 0} tasks`); + return response; + }, +}; diff --git a/components/pipedrive/actions/update-project/update-project.mjs b/components/pipedrive/actions/update-project/update-project.mjs new file mode 100644 index 0000000000000..57227eab09738 --- /dev/null +++ b/components/pipedrive/actions/update-project/update-project.mjs @@ -0,0 +1,87 @@ +import pipedriveApp from "../../pipedrive.app.mjs"; +import constants from "../../common/constants.mjs"; + +export default { + key: "pipedrive-update-project", + name: "Update Project", + description: "Updates an existing project. Run **List Projects** first to obtain a valid project ID; use **List Project Boards** and **List Project Phases** for board and phase IDs. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Projects#updateProject)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + props: { + pipedriveApp, + projectId: { + type: "string", + label: "Project ID", + description: "The ID of the project to update. Run **List Projects** first to obtain a valid project ID.", + }, + title: { + type: "string", + label: "Title", + description: "The updated title of the project.", + optional: true, + }, + description: { + type: "string", + label: "Description", + description: "The updated description of the project.", + optional: true, + }, + status: { + type: "string", + label: "Status", + description: "The updated status of the project. One of: open, completed, canceled, deleted.", + options: constants.PROJECT_STATUS_OPTIONS, + optional: true, + }, + boardId: { + type: "string", + label: "Board ID", + description: "The ID of the board. Run **List Project Boards** first to obtain a valid board ID.", + optional: true, + }, + phaseId: { + type: "string", + label: "Phase ID", + description: "The ID of the phase. Run **List Project Phases** first to obtain a valid phase ID.", + optional: true, + }, + ownerId: { + type: "string", + label: "Owner ID", + description: "The user ID of the project owner. Use **List Users** to obtain a valid user ID.", + optional: true, + }, + startDate: { + type: "string", + label: "Start Date", + description: "The start date of the project. Format: YYYY-MM-DD.", + optional: true, + }, + endDate: { + type: "string", + label: "End Date", + description: "The end date of the project. Format: YYYY-MM-DD.", + optional: true, + }, + }, + async run({ $ }) { + const response = await this.pipedriveApp.updateProject({ + projectId: this.projectId, + title: this.title, + description: this.description, + status: this.status, + board_id: this.boardId, + phase_id: this.phaseId, + owner_id: this.ownerId, + start_date: this.startDate, + end_date: this.endDate, + }); + $.export("$summary", `Successfully updated project ${this.projectId}`); + return response; + }, +}; diff --git a/components/pipedrive/actions/update-task/update-task.mjs b/components/pipedrive/actions/update-task/update-task.mjs new file mode 100644 index 0000000000000..0bce4218410c2 --- /dev/null +++ b/components/pipedrive/actions/update-task/update-task.mjs @@ -0,0 +1,90 @@ +import pipedriveApp from "../../pipedrive.app.mjs"; + +export default { + key: "pipedrive-update-task", + name: "Update Task", + description: "Updates an existing task (BETA). Run **List Tasks** first to obtain a valid task ID. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Tasks#updateTask)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + props: { + pipedriveApp, + taskId: { + type: "string", + label: "Task ID", + description: "The ID of the task to update. Run **List Tasks** first to obtain a valid task ID.", + }, + title: { + type: "string", + label: "Title", + description: "The updated title of the task.", + optional: true, + }, + description: { + type: "string", + label: "Description", + description: "The updated description of the task.", + optional: true, + }, + done: { + type: "integer", + label: "Done", + description: "Whether the task is done. Integer: 0 (not done) or 1 (done).", + min: 0, + max: 1, + optional: true, + }, + milestone: { + type: "integer", + label: "Milestone", + description: "Whether the task is a milestone. Integer: 0 (no) or 1 (yes).", + min: 0, + max: 1, + optional: true, + }, + dueDate: { + type: "string", + label: "Due Date", + description: "The due date of the task. Format: YYYY-MM-DD.", + optional: true, + }, + startDate: { + type: "string", + label: "Start Date", + description: "The start date of the task. Format: YYYY-MM-DD.", + optional: true, + }, + assigneeId: { + type: "string", + label: "Assignee ID", + description: "The user ID of the task assignee. Run **List User ID Options** to obtain a valid user ID.", + optional: true, + }, + priority: { + type: "integer", + label: "Priority", + description: "The priority of the task (non-negative integer).", + min: 0, + optional: true, + }, + }, + async run({ $ }) { + const response = await this.pipedriveApp.updateTask({ + taskId: this.taskId, + title: this.title, + description: this.description, + done: this.done, + milestone: this.milestone, + due_date: this.dueDate, + start_date: this.startDate, + assignee_id: this.assigneeId, + priority: this.priority, + }); + $.export("$summary", `Successfully updated task ${this.taskId}`); + return response; + }, +}; diff --git a/components/pipedrive/common/constants.mjs b/components/pipedrive/common/constants.mjs index 60299936c52e8..17cbcd6513748 100644 --- a/components/pipedrive/common/constants.mjs +++ b/components/pipedrive/common/constants.mjs @@ -7,6 +7,13 @@ const STATUS_OPTIONS = [ "deleted", ]; +const PROJECT_STATUS_OPTIONS = [ + "open", + "completed", + "canceled", + "deleted", +]; + const FIELD_OPTIONS = [ "custom_fields", "email", @@ -71,8 +78,80 @@ const DEAL_INCLUDE_FIELDS_OPTIONS = [ "source_lead_id", ]; +const PERSON_SORT_BY_OPTIONS = [ + "id", + "update_time", + "add_time", +]; + +const ORGANIZATION_SORT_BY_OPTIONS = [ + "id", + "update_time", + "add_time", +]; + +const ORGANIZATION_INCLUDE_FIELDS_OPTIONS = [ + "next_activity_id", + "last_activity_id", + "open_deals_count", + "related_open_deals_count", + "closed_deals_count", + "related_closed_deals_count", + "email_messages_count", + "people_count", + "activities_count", + "done_activities_count", + "undone_activities_count", + "files_count", + "notes_count", + "followers_count", + "won_deals_count", + "related_won_deals_count", + "lost_deals_count", + "related_lost_deals_count", + "smart_bcc_email", +]; + +const FILTER_TYPE_OPTIONS = [ + "deals", + "leads", + "org", + "people", + "products", + "activity", + "projects", +]; + +const PERSON_INCLUDE_FIELDS_OPTIONS = [ + "next_activity_id", + "last_activity_id", + "open_deals_count", + "related_open_deals_count", + "closed_deals_count", + "related_closed_deals_count", + "participant_open_deals_count", + "participant_closed_deals_count", + "email_messages_count", + "activities_count", + "done_activities_count", + "undone_activities_count", + "files_count", + "notes_count", + "followers_count", + "won_deals_count", + "related_won_deals_count", + "lost_deals_count", + "related_lost_deals_count", + "last_incoming_mail_time", + "last_outgoing_mail_time", + "marketing_status", + "doi_status", + "smart_bcc_email", +]; + export default { STATUS_OPTIONS, + PROJECT_STATUS_OPTIONS, FIELD_OPTIONS, VISIBLE_TO_OPTIONS, INCLUDE_FIELDS_OPTIONS, @@ -82,4 +161,9 @@ export default { DEAL_SORT_BY_OPTIONS, SORT_DIRECTION_OPTIONS, DEAL_INCLUDE_FIELDS_OPTIONS, + PERSON_SORT_BY_OPTIONS, + PERSON_INCLUDE_FIELDS_OPTIONS, + ORGANIZATION_SORT_BY_OPTIONS, + ORGANIZATION_INCLUDE_FIELDS_OPTIONS, + FILTER_TYPE_OPTIONS, }; diff --git a/components/pipedrive/package.json b/components/pipedrive/package.json index a16eb307c014f..279f6427e2614 100644 --- a/components/pipedrive/package.json +++ b/components/pipedrive/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/pipedrive", - "version": "0.14.0", + "version": "0.15.0", "description": "Pipedream Pipedrive Components", "main": "pipedrive.app.mjs", "keywords": [ diff --git a/components/pipedrive/pipedrive.app.mjs b/components/pipedrive/pipedrive.app.mjs index ced02f96e772e..dbf9f4a1d0d47 100644 --- a/components/pipedrive/pipedrive.app.mjs +++ b/components/pipedrive/pipedrive.app.mjs @@ -1,4 +1,5 @@ import pd from "pipedrive"; +import { axios } from "@pipedream/platform"; import constants from "./common/constants.mjs"; export default { @@ -745,6 +746,89 @@ export default { id: noteId, }); }, + listProjects(opts = {}) { + const projectApi = this.api("ProjectsApi", "v2"); + return projectApi.getProjects(opts); + }, + addProject(opts = {}) { + const projectApi = this.api("ProjectsApi", "v2"); + return projectApi.addProject({ + AddProjectRequest: opts, + }); + }, + getProject(projectId) { + const projectApi = this.api("ProjectsApi", "v2"); + return projectApi.getProject({ + id: projectId, + }); + }, + updateProject({ + projectId, ...opts + }) { + const projectApi = this.api("ProjectsApi", "v2"); + return projectApi.updateProject({ + id: projectId, + UpdateProjectRequest: opts, + }); + }, + deleteProject(projectId) { + const projectApi = this.api("ProjectsApi", "v2"); + return projectApi.deleteProject({ + id: projectId, + }); + }, + getProjectBoards({ $ }) { + return axios($, { + url: `${this.$auth.api_domain}/api/v2/boards`, + headers: { + Authorization: `Bearer ${this.$auth.oauth_access_token}`, + }, + }); + }, + getProjectPhases({ + boardId, $, + }) { + return axios($, { + url: `${this.$auth.api_domain}/api/v2/phases`, + headers: { + Authorization: `Bearer ${this.$auth.oauth_access_token}`, + }, + params: { + board_id: boardId, + }, + }); + }, + listTasks(opts = {}) { + const taskApi = this.api("TasksApi", "v2"); + return taskApi.getTasks(opts); + }, + addTask(opts = {}) { + const taskApi = this.api("TasksApi", "v2"); + return taskApi.addTask({ + AddTaskRequest: opts, + }); + }, + getTask(taskId) { + const taskApi = this.api("TasksApi", "v2"); + return taskApi.getTask({ + id: taskId, + }); + }, + updateTask({ + taskId, ...opts + }) { + const taskApi = this.api("TasksApi", "v2"); + return taskApi.updateTask({ + id: taskId, + UpdateTaskRequest: opts, + }); + }, + deleteTask(taskId) { + const taskApi = this.api("TasksApi", "v2"); + return taskApi.deleteTask({ + id: taskId, + }); + }, getPerson(personId) { const personsApi = this.api("PersonsApi", "v2"); return personsApi.getPerson({ From 25b4cd14c8ccc34246234f7e38dcfff216f3344b Mon Sep 17 00:00:00 2001 From: Michelle Bergeron Date: Mon, 6 Jul 2026 12:19:15 -0400 Subject: [PATCH 2/5] chore(pipedrive): bump versions on existing components Coordinated patch bump across the existing pipedrive actions and sources so their published versions advance alongside the app-file changes in this PR (new methods, propDefinitions, and constants used by the new Projects/Tasks/Persons/Organizations/Filters actions). --- components/pipedrive/actions/add-activity/add-activity.mjs | 2 +- components/pipedrive/actions/add-deal/add-deal.mjs | 2 +- components/pipedrive/actions/add-labels/add-labels.mjs | 2 +- components/pipedrive/actions/add-lead/add-lead.mjs | 2 +- components/pipedrive/actions/add-note/add-note.mjs | 2 +- .../pipedrive/actions/add-organization/add-organization.mjs | 2 +- components/pipedrive/actions/add-person/add-person.mjs | 2 +- components/pipedrive/actions/get-all-leads/get-all-leads.mjs | 2 +- components/pipedrive/actions/get-deal/get-deal.mjs | 2 +- components/pipedrive/actions/get-lead-by-id/get-lead-by-id.mjs | 2 +- .../pipedrive/actions/get-person-details/get-person-details.mjs | 2 +- components/pipedrive/actions/list-deals/list-deals.mjs | 2 +- .../list-lead-label-ids-options/list-lead-label-ids-options.mjs | 2 +- .../list-organization-label-ids-options.mjs | 2 +- .../list-person-label-ids-options.mjs | 2 +- .../actions/list-user-id-options/list-user-id-options.mjs | 2 +- components/pipedrive/actions/merge-deals/merge-deals.mjs | 2 +- components/pipedrive/actions/merge-persons/merge-persons.mjs | 2 +- .../actions/remove-duplicate-notes/remove-duplicate-notes.mjs | 2 +- components/pipedrive/actions/remove-labels/remove-labels.mjs | 2 +- components/pipedrive/actions/search-leads/search-leads.mjs | 2 +- components/pipedrive/actions/search-notes/search-notes.mjs | 2 +- components/pipedrive/actions/search-persons/search-persons.mjs | 2 +- components/pipedrive/actions/update-deal/update-deal.mjs | 2 +- components/pipedrive/actions/update-lead/update-lead.mjs | 2 +- components/pipedrive/actions/update-person/update-person.mjs | 2 +- .../pipedrive/sources/new-deal-instant/new-deal-instant.mjs | 2 +- .../pipedrive/sources/new-event-instant/new-event-instant.mjs | 2 +- .../pipedrive/sources/new-person-instant/new-person-instant.mjs | 2 +- .../sources/updated-deal-instant/updated-deal-instant.mjs | 2 +- .../sources/updated-lead-instant/updated-lead-instant.mjs | 2 +- .../sources/updated-person-instant/updated-person-instant.mjs | 2 +- 32 files changed, 32 insertions(+), 32 deletions(-) diff --git a/components/pipedrive/actions/add-activity/add-activity.mjs b/components/pipedrive/actions/add-activity/add-activity.mjs index a572464443144..e652508282d40 100644 --- a/components/pipedrive/actions/add-activity/add-activity.mjs +++ b/components/pipedrive/actions/add-activity/add-activity.mjs @@ -7,7 +7,7 @@ export default { key: "pipedrive-add-activity", name: "Add Activity", description: "Adds a new activity. Includes `more_activities_scheduled_in_context` property in response's `additional_data` which indicates whether there are more undone activities scheduled with the same deal, person or organization (depending on the supplied data). See the Pipedrive API docs for Activities [here](https://developers.pipedrive.com/docs/api/v1/#!/Activities). For info on [adding an activity in Pipedrive](https://developers.pipedrive.com/docs/api/v1/Activities#addActivity)", - version: "0.1.24", + version: "0.1.25", annotations: { destructiveHint: false, openWorldHint: true, diff --git a/components/pipedrive/actions/add-deal/add-deal.mjs b/components/pipedrive/actions/add-deal/add-deal.mjs index 6b44537497e84..f0c13ec8e4e3b 100644 --- a/components/pipedrive/actions/add-deal/add-deal.mjs +++ b/components/pipedrive/actions/add-deal/add-deal.mjs @@ -6,7 +6,7 @@ export default { key: "pipedrive-add-deal", name: "Add Deal", description: "Adds a new deal. See the Pipedrive API docs for Deals [here](https://developers.pipedrive.com/docs/api/v1/Deals#addDeal)", - version: "0.1.25", + version: "0.1.26", annotations: { destructiveHint: false, openWorldHint: true, diff --git a/components/pipedrive/actions/add-labels/add-labels.mjs b/components/pipedrive/actions/add-labels/add-labels.mjs index 63daed130fa5d..cb97c882ff111 100644 --- a/components/pipedrive/actions/add-labels/add-labels.mjs +++ b/components/pipedrive/actions/add-labels/add-labels.mjs @@ -5,7 +5,7 @@ export default { key: "pipedrive-add-labels", name: "Add Labels", description: "Adds labels to a lead, person, deal, or organization in Pipedrive. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Leads#updateLead)", - version: "0.0.4", + version: "0.0.5", annotations: { destructiveHint: true, openWorldHint: true, diff --git a/components/pipedrive/actions/add-lead/add-lead.mjs b/components/pipedrive/actions/add-lead/add-lead.mjs index 15508a757b056..0f8fb99d68253 100644 --- a/components/pipedrive/actions/add-lead/add-lead.mjs +++ b/components/pipedrive/actions/add-lead/add-lead.mjs @@ -6,7 +6,7 @@ export default { key: "pipedrive-add-lead", name: "Add Lead", description: "Create a new lead in Pipedrive. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Leads#addLead)", - version: "0.0.18", + version: "0.0.19", annotations: { destructiveHint: false, openWorldHint: true, diff --git a/components/pipedrive/actions/add-note/add-note.mjs b/components/pipedrive/actions/add-note/add-note.mjs index 86862980cff9d..e43c4ddffc17f 100644 --- a/components/pipedrive/actions/add-note/add-note.mjs +++ b/components/pipedrive/actions/add-note/add-note.mjs @@ -5,7 +5,7 @@ export default { key: "pipedrive-add-note", name: "Add Note", description: "Adds a new note. For info on [adding an note in Pipedrive](https://developers.pipedrive.com/docs/api/v1/Notes#addNote)", - version: "0.0.19", + version: "0.0.20", annotations: { destructiveHint: false, openWorldHint: true, diff --git a/components/pipedrive/actions/add-organization/add-organization.mjs b/components/pipedrive/actions/add-organization/add-organization.mjs index 53b68b46ebca7..cda3470edd2e8 100644 --- a/components/pipedrive/actions/add-organization/add-organization.mjs +++ b/components/pipedrive/actions/add-organization/add-organization.mjs @@ -5,7 +5,7 @@ export default { key: "pipedrive-add-organization", name: "Add Organization", description: "Adds a new organization. See the Pipedrive API docs for Organizations [here](https://developers.pipedrive.com/docs/api/v1/Organizations#addOrganization)", - version: "0.1.21", + version: "0.1.22", annotations: { destructiveHint: false, openWorldHint: true, diff --git a/components/pipedrive/actions/add-person/add-person.mjs b/components/pipedrive/actions/add-person/add-person.mjs index d518afbbe4288..a9e92ea74fef0 100644 --- a/components/pipedrive/actions/add-person/add-person.mjs +++ b/components/pipedrive/actions/add-person/add-person.mjs @@ -6,7 +6,7 @@ export default { key: "pipedrive-add-person", name: "Add Person", description: "Adds a new person. See the Pipedrive API docs for People [here](https://developers.pipedrive.com/docs/api/v1/Persons#addPerson)", - version: "0.1.24", + version: "0.1.25", annotations: { destructiveHint: false, openWorldHint: true, diff --git a/components/pipedrive/actions/get-all-leads/get-all-leads.mjs b/components/pipedrive/actions/get-all-leads/get-all-leads.mjs index 2d0b66b5db77c..d8c84ce8b1b8c 100644 --- a/components/pipedrive/actions/get-all-leads/get-all-leads.mjs +++ b/components/pipedrive/actions/get-all-leads/get-all-leads.mjs @@ -4,7 +4,7 @@ export default { key: "pipedrive-get-all-leads", name: "Get All Leads", description: "Get all leads from Pipedrive. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Leads#getLeads)", - version: "0.0.4", + version: "0.0.5", type: "action", annotations: { destructiveHint: false, diff --git a/components/pipedrive/actions/get-deal/get-deal.mjs b/components/pipedrive/actions/get-deal/get-deal.mjs index bfda6dbecbf41..1324afef8a418 100644 --- a/components/pipedrive/actions/get-deal/get-deal.mjs +++ b/components/pipedrive/actions/get-deal/get-deal.mjs @@ -4,7 +4,7 @@ export default { key: "pipedrive-get-deal", name: "Get Deal", description: "Get a deal by its ID. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Deals)", - version: "0.0.2", + version: "0.0.3", type: "action", annotations: { destructiveHint: false, diff --git a/components/pipedrive/actions/get-lead-by-id/get-lead-by-id.mjs b/components/pipedrive/actions/get-lead-by-id/get-lead-by-id.mjs index c05eaeb1dd018..1dd49a7933959 100644 --- a/components/pipedrive/actions/get-lead-by-id/get-lead-by-id.mjs +++ b/components/pipedrive/actions/get-lead-by-id/get-lead-by-id.mjs @@ -4,7 +4,7 @@ export default { key: "pipedrive-get-lead-by-id", name: "Get Lead by ID", description: "Get a lead by its ID. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Leads#getLead)", - version: "0.0.9", + version: "0.0.10", annotations: { destructiveHint: false, openWorldHint: true, diff --git a/components/pipedrive/actions/get-person-details/get-person-details.mjs b/components/pipedrive/actions/get-person-details/get-person-details.mjs index 8d63c053e833c..5a691042cd5f7 100644 --- a/components/pipedrive/actions/get-person-details/get-person-details.mjs +++ b/components/pipedrive/actions/get-person-details/get-person-details.mjs @@ -5,7 +5,7 @@ export default { key: "pipedrive-get-person-details", name: "Get person details", description: "Get details of a person by their ID. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Persons#getPerson)", - version: "0.0.10", + version: "0.0.11", annotations: { destructiveHint: false, openWorldHint: true, diff --git a/components/pipedrive/actions/list-deals/list-deals.mjs b/components/pipedrive/actions/list-deals/list-deals.mjs index 839667c50c6bb..ac62dbd92ac50 100644 --- a/components/pipedrive/actions/list-deals/list-deals.mjs +++ b/components/pipedrive/actions/list-deals/list-deals.mjs @@ -5,7 +5,7 @@ export default { key: "pipedrive-list-deals", name: "List Deals", description: "List deals in your Pipedrive account. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Deals#listDeals)", - version: "0.0.2", + version: "0.0.3", type: "action", annotations: { destructiveHint: false, diff --git a/components/pipedrive/actions/list-lead-label-ids-options/list-lead-label-ids-options.mjs b/components/pipedrive/actions/list-lead-label-ids-options/list-lead-label-ids-options.mjs index e4c6a4672a4f2..69fd8939f8aa7 100644 --- a/components/pipedrive/actions/list-lead-label-ids-options/list-lead-label-ids-options.mjs +++ b/components/pipedrive/actions/list-lead-label-ids-options/list-lead-label-ids-options.mjs @@ -4,7 +4,7 @@ export default { key: "pipedrive-list-lead-label-ids-options", name: "List Lead Label IDs Options", description: "Retrieves available options for the Lead Label IDs field.", - version: "0.0.1", + version: "0.0.2", type: "action", annotations: { destructiveHint: false, diff --git a/components/pipedrive/actions/list-organization-label-ids-options/list-organization-label-ids-options.mjs b/components/pipedrive/actions/list-organization-label-ids-options/list-organization-label-ids-options.mjs index db2515db8c0b3..41ee3bdf9409c 100644 --- a/components/pipedrive/actions/list-organization-label-ids-options/list-organization-label-ids-options.mjs +++ b/components/pipedrive/actions/list-organization-label-ids-options/list-organization-label-ids-options.mjs @@ -4,7 +4,7 @@ export default { key: "pipedrive-list-organization-label-ids-options", name: "List Organization Label IDs Options", description: "Retrieves available options for the Organization Label IDs field.", - version: "0.0.1", + version: "0.0.2", type: "action", annotations: { destructiveHint: false, diff --git a/components/pipedrive/actions/list-person-label-ids-options/list-person-label-ids-options.mjs b/components/pipedrive/actions/list-person-label-ids-options/list-person-label-ids-options.mjs index 39b2ce216c09f..dc5d004b1ff8b 100644 --- a/components/pipedrive/actions/list-person-label-ids-options/list-person-label-ids-options.mjs +++ b/components/pipedrive/actions/list-person-label-ids-options/list-person-label-ids-options.mjs @@ -4,7 +4,7 @@ export default { key: "pipedrive-list-person-label-ids-options", name: "List Person Label IDs Options", description: "Retrieves available options for the Person Label IDs field.", - version: "0.0.1", + version: "0.0.2", type: "action", annotations: { destructiveHint: false, diff --git a/components/pipedrive/actions/list-user-id-options/list-user-id-options.mjs b/components/pipedrive/actions/list-user-id-options/list-user-id-options.mjs index 919bf939c5be2..26e79da80743d 100644 --- a/components/pipedrive/actions/list-user-id-options/list-user-id-options.mjs +++ b/components/pipedrive/actions/list-user-id-options/list-user-id-options.mjs @@ -4,7 +4,7 @@ export default { key: "pipedrive-list-user-id-options", name: "List User ID Options", description: "Retrieves available options for the User ID field.", - version: "0.0.1", + version: "0.0.2", type: "action", annotations: { destructiveHint: false, diff --git a/components/pipedrive/actions/merge-deals/merge-deals.mjs b/components/pipedrive/actions/merge-deals/merge-deals.mjs index 13389a1db15dd..20bdf758cc744 100644 --- a/components/pipedrive/actions/merge-deals/merge-deals.mjs +++ b/components/pipedrive/actions/merge-deals/merge-deals.mjs @@ -4,7 +4,7 @@ export default { key: "pipedrive-merge-deals", name: "Merge Deals", description: "Merge two deals in Pipedrive. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Deals#mergeDeals)", - version: "0.0.9", + version: "0.0.10", annotations: { destructiveHint: false, openWorldHint: true, diff --git a/components/pipedrive/actions/merge-persons/merge-persons.mjs b/components/pipedrive/actions/merge-persons/merge-persons.mjs index 95f25fe50378e..31e156d464bf9 100644 --- a/components/pipedrive/actions/merge-persons/merge-persons.mjs +++ b/components/pipedrive/actions/merge-persons/merge-persons.mjs @@ -4,7 +4,7 @@ export default { key: "pipedrive-merge-persons", name: "Merge Persons", description: "Merge two persons in Pipedrive. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Persons#mergePersons)", - version: "0.0.9", + version: "0.0.10", annotations: { destructiveHint: false, openWorldHint: true, diff --git a/components/pipedrive/actions/remove-duplicate-notes/remove-duplicate-notes.mjs b/components/pipedrive/actions/remove-duplicate-notes/remove-duplicate-notes.mjs index 955b99daf07a2..649552bb950d7 100644 --- a/components/pipedrive/actions/remove-duplicate-notes/remove-duplicate-notes.mjs +++ b/components/pipedrive/actions/remove-duplicate-notes/remove-duplicate-notes.mjs @@ -5,7 +5,7 @@ export default { key: "pipedrive-remove-duplicate-notes", name: "Remove Duplicate Notes", description: "Remove duplicate notes from an object in Pipedrive. See the documentation for [getting notes](https://developers.pipedrive.com/docs/api/v1/Notes#getNotes) and [deleting notes](https://developers.pipedrive.com/docs/api/v1/Notes#deleteNote)", - version: "0.0.12", + version: "0.0.13", annotations: { destructiveHint: true, openWorldHint: true, diff --git a/components/pipedrive/actions/remove-labels/remove-labels.mjs b/components/pipedrive/actions/remove-labels/remove-labels.mjs index 650c69443ba01..589a2f231cfdb 100644 --- a/components/pipedrive/actions/remove-labels/remove-labels.mjs +++ b/components/pipedrive/actions/remove-labels/remove-labels.mjs @@ -12,7 +12,7 @@ export default { key: "pipedrive-remove-labels", name: "Remove Labels", description: "Removes one or more specific labels from a lead, person, deal, or organization in Pipedrive, leaving all other labels intact. [See the documentation](https://developers.pipedrive.com/docs/api/v1)", - version: "0.0.1", + version: "0.0.2", type: "action", annotations: { destructiveHint: true, diff --git a/components/pipedrive/actions/search-leads/search-leads.mjs b/components/pipedrive/actions/search-leads/search-leads.mjs index bc5aecc0abd9a..ae81b47b71fc5 100644 --- a/components/pipedrive/actions/search-leads/search-leads.mjs +++ b/components/pipedrive/actions/search-leads/search-leads.mjs @@ -5,7 +5,7 @@ export default { key: "pipedrive-search-leads", name: "Search Leads", description: "Search for leads by name or email. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Leads#searchLeads)", - version: "0.0.9", + version: "0.0.10", annotations: { destructiveHint: false, openWorldHint: true, diff --git a/components/pipedrive/actions/search-notes/search-notes.mjs b/components/pipedrive/actions/search-notes/search-notes.mjs index 1d1b1f9b0777e..3200b3a4b7e27 100644 --- a/components/pipedrive/actions/search-notes/search-notes.mjs +++ b/components/pipedrive/actions/search-notes/search-notes.mjs @@ -4,7 +4,7 @@ export default { key: "pipedrive-search-notes", name: "Search Notes", description: "Search for notes in Pipedrive. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Notes#getNotes)", - version: "0.0.12", + version: "0.0.13", annotations: { destructiveHint: false, openWorldHint: true, diff --git a/components/pipedrive/actions/search-persons/search-persons.mjs b/components/pipedrive/actions/search-persons/search-persons.mjs index f46ace9958dd8..db9943a8d0a4f 100644 --- a/components/pipedrive/actions/search-persons/search-persons.mjs +++ b/components/pipedrive/actions/search-persons/search-persons.mjs @@ -8,7 +8,7 @@ export default { key: "pipedrive-search-persons", name: "Search persons", description: "Searches all Persons by `name`, `email`, `phone`, `notes` and/or custom fields. This endpoint is a wrapper of `/v1/itemSearch` with a narrower OAuth scope. Found Persons can be filtered by Organization ID. See the Pipedrive API docs [here](https://developers.pipedrive.com/docs/api/v1/Persons#searchPersons)", - version: "0.1.24", + version: "0.1.25", annotations: { destructiveHint: false, openWorldHint: true, diff --git a/components/pipedrive/actions/update-deal/update-deal.mjs b/components/pipedrive/actions/update-deal/update-deal.mjs index cf3d64affdb72..7c87a1cda5055 100644 --- a/components/pipedrive/actions/update-deal/update-deal.mjs +++ b/components/pipedrive/actions/update-deal/update-deal.mjs @@ -5,7 +5,7 @@ export default { key: "pipedrive-update-deal", name: "Update Deal", description: "Updates the properties of a deal. See the Pipedrive API docs for Deals [here](https://developers.pipedrive.com/docs/api/v1/Deals#updateDeal)", - version: "0.1.23", + version: "0.1.24", annotations: { destructiveHint: true, openWorldHint: true, diff --git a/components/pipedrive/actions/update-lead/update-lead.mjs b/components/pipedrive/actions/update-lead/update-lead.mjs index 6d2af70fd6714..bf69141a026f7 100644 --- a/components/pipedrive/actions/update-lead/update-lead.mjs +++ b/components/pipedrive/actions/update-lead/update-lead.mjs @@ -5,7 +5,7 @@ export default { key: "pipedrive-update-lead", name: "Update Lead", description: "Updates a lead in Pipedrive. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Leads#updateLead)", - version: "0.0.5", + version: "0.0.6", annotations: { destructiveHint: true, openWorldHint: true, diff --git a/components/pipedrive/actions/update-person/update-person.mjs b/components/pipedrive/actions/update-person/update-person.mjs index 55f94c5764689..cf0b2e6ef43d1 100644 --- a/components/pipedrive/actions/update-person/update-person.mjs +++ b/components/pipedrive/actions/update-person/update-person.mjs @@ -6,7 +6,7 @@ export default { key: "pipedrive-update-person", name: "Update Person", description: "Updates an existing person in Pipedrive. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Persons#updatePerson)", - version: "0.0.16", + version: "0.0.17", annotations: { destructiveHint: true, openWorldHint: true, diff --git a/components/pipedrive/sources/new-deal-instant/new-deal-instant.mjs b/components/pipedrive/sources/new-deal-instant/new-deal-instant.mjs index cd957fb9cc0dd..06a69f4f2eebb 100644 --- a/components/pipedrive/sources/new-deal-instant/new-deal-instant.mjs +++ b/components/pipedrive/sources/new-deal-instant/new-deal-instant.mjs @@ -6,7 +6,7 @@ export default { key: "pipedrive-new-deal-instant", name: "New Deal (Instant)", description: "Emit new event when a new deal is created.", - version: "0.0.17", + version: "0.0.18", type: "source", dedupe: "unique", methods: { diff --git a/components/pipedrive/sources/new-event-instant/new-event-instant.mjs b/components/pipedrive/sources/new-event-instant/new-event-instant.mjs index 7a17467458571..c102068fc8408 100644 --- a/components/pipedrive/sources/new-event-instant/new-event-instant.mjs +++ b/components/pipedrive/sources/new-event-instant/new-event-instant.mjs @@ -5,7 +5,7 @@ export default { key: "pipedrive-new-event-instant", name: "New Event (Instant)", description: "Emit new event when a new webhook event is received. [See the documentation](https://developers.pipedrive.com/docs/api/v1/Webhooks#addWebhook)", - version: "0.0.8", + version: "0.0.9", type: "source", dedupe: "unique", props: { diff --git a/components/pipedrive/sources/new-person-instant/new-person-instant.mjs b/components/pipedrive/sources/new-person-instant/new-person-instant.mjs index 4d2da6bb0ef01..0335f2280df30 100644 --- a/components/pipedrive/sources/new-person-instant/new-person-instant.mjs +++ b/components/pipedrive/sources/new-person-instant/new-person-instant.mjs @@ -6,7 +6,7 @@ export default { key: "pipedrive-new-person-instant", name: "New Person (Instant)", description: "Emit new event when a new person is created.", - version: "0.0.17", + version: "0.0.18", type: "source", dedupe: "unique", methods: { diff --git a/components/pipedrive/sources/updated-deal-instant/updated-deal-instant.mjs b/components/pipedrive/sources/updated-deal-instant/updated-deal-instant.mjs index b12da88dc31f0..df68e4896b262 100644 --- a/components/pipedrive/sources/updated-deal-instant/updated-deal-instant.mjs +++ b/components/pipedrive/sources/updated-deal-instant/updated-deal-instant.mjs @@ -7,7 +7,7 @@ export default { key: "pipedrive-updated-deal-instant", name: "Deal Updated (Instant)", description: "Emit new event when a deal is updated.", - version: "0.1.13", + version: "0.1.14", type: "source", dedupe: "unique", methods: { diff --git a/components/pipedrive/sources/updated-lead-instant/updated-lead-instant.mjs b/components/pipedrive/sources/updated-lead-instant/updated-lead-instant.mjs index 833d3629dbbb0..d95288ba22c54 100644 --- a/components/pipedrive/sources/updated-lead-instant/updated-lead-instant.mjs +++ b/components/pipedrive/sources/updated-lead-instant/updated-lead-instant.mjs @@ -7,7 +7,7 @@ export default { key: "pipedrive-updated-lead-instant", name: "Lead Updated (Instant)", description: "Emit new event when a lead is updated.", - version: "0.1.13", + version: "0.1.14", type: "source", dedupe: "unique", methods: { diff --git a/components/pipedrive/sources/updated-person-instant/updated-person-instant.mjs b/components/pipedrive/sources/updated-person-instant/updated-person-instant.mjs index 24681b662817f..24f504fef36ea 100644 --- a/components/pipedrive/sources/updated-person-instant/updated-person-instant.mjs +++ b/components/pipedrive/sources/updated-person-instant/updated-person-instant.mjs @@ -7,7 +7,7 @@ export default { key: "pipedrive-updated-person-instant", name: "Person Updated (Instant)", description: "Emit new event when a person is updated.", - version: "0.1.13", + version: "0.1.14", type: "source", dedupe: "unique", methods: { From 075983ab2ad821bcce912bb69e132a7a692f8975 Mon Sep 17 00:00:00 2001 From: Michelle Bergeron Date: Mon, 6 Jul 2026 13:26:58 -0400 Subject: [PATCH 3/5] =?UTF-8?q?refactor(pipedrive):=20review=20response=20?= =?UTF-8?q?=E2=80=94=20share=20prop=20defs,=20tighten=20specs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add `projectStatus` and `projectPhaseId` propDefinitions on pipedriveApp so create-project, list-projects, and update-project can reuse them via propDefinition + per-action description overrides instead of each duplicating the same schema inline. * Have the three task actions (create/list/update-task) reference the existing `userId` propDefinition for `assigneeId`, matching how list-deals/list-organizations reference it for `ownerId`. Gives the agent a searchable user-picker and switches assignee_id to integer (matches the Pipedrive v2 tasks endpoint's declared type). * list-projects: cap `limit.max` at 500 to match the API's server-side cap, and tighten the description to stop advertising a higher ceiling. * list-tasks: rewrite the `parentTaskId` description so it accurately reflects the v2 semantics — omit returns all tasks, an integer returns subtasks; the API also accepts null for root-level-only but this prop can't represent null, so we call that out. * create-project: point users to Pipedrive Settings → Labels for the label IDs `labelIds` expects (there is no dedicated list-project-labels action to reference). Not applied: * Reviewer suggested routing getProjectBoards / getProjectPhases through a shared request helper. No such helper exists in pipedrive.app.mjs — every other method uses the Pipedrive JS SDK (`this.api(...).getX()`); those two use raw axios only because the SDK doesn't cover v2 boards or phases. Introducing a helper is a real cleanup, but the premise (that one already exists) was incorrect, so leaving as-is. * Reviewer suggested listProjects drops `deal_id`, `person_id`, and `org_id` because they're unsupported. Verified against Pipedrive's v2 OpenAPI: all three ARE supported query params on GET /projects, and the action forwards them correctly. --- .../actions/create-project/create-project.mjs | 19 +++++++++--------- .../actions/create-task/create-task.mjs | 7 +++++-- .../actions/list-projects/list-projects.mjs | 20 +++++++++---------- .../actions/list-tasks/list-tasks.mjs | 9 ++++++--- .../actions/update-project/update-project.mjs | 16 +++++++-------- .../actions/update-task/update-task.mjs | 7 +++++-- components/pipedrive/pipedrive.app.mjs | 13 ++++++++++++ 7 files changed, 56 insertions(+), 35 deletions(-) diff --git a/components/pipedrive/actions/create-project/create-project.mjs b/components/pipedrive/actions/create-project/create-project.mjs index 304dc6cb5c86d..a9bd717ca0c81 100644 --- a/components/pipedrive/actions/create-project/create-project.mjs +++ b/components/pipedrive/actions/create-project/create-project.mjs @@ -1,5 +1,4 @@ import pipedriveApp from "../../pipedrive.app.mjs"; -import constants from "../../common/constants.mjs"; export default { key: "pipedrive-create-project", @@ -26,11 +25,10 @@ export default { optional: true, }, status: { - type: "string", - label: "Status", - description: "The status of the project. One of: open, completed, canceled, deleted.", - options: constants.PROJECT_STATUS_OPTIONS, - optional: true, + propDefinition: [ + pipedriveApp, + "projectStatus", + ], }, boardId: { type: "string", @@ -39,10 +37,11 @@ export default { optional: true, }, phaseId: { - type: "string", - label: "Phase ID", + propDefinition: [ + pipedriveApp, + "projectPhaseId", + ], description: "The ID of the phase this project belongs to. Run **List Project Phases** (with the chosen board ID) first to obtain a valid phase ID.", - optional: true, }, ownerId: { type: "string", @@ -83,7 +82,7 @@ export default { labelIds: { type: "string[]", label: "Label IDs", - description: "Array of label IDs to associate with the project.", + description: "Array of numeric project-label IDs to associate with the project. Project labels are managed in Pipedrive under **Settings → Labels** — copy the numeric ID for each label you want to apply.", optional: true, }, }, diff --git a/components/pipedrive/actions/create-task/create-task.mjs b/components/pipedrive/actions/create-task/create-task.mjs index 338a76f7e29bf..475bb411a817e 100644 --- a/components/pipedrive/actions/create-task/create-task.mjs +++ b/components/pipedrive/actions/create-task/create-task.mjs @@ -64,9 +64,12 @@ export default { optional: true, }, assigneeId: { - type: "string", + propDefinition: [ + pipedriveApp, + "userId", + ], label: "Assignee ID", - description: "The user ID of the task assignee. Run **List User ID Options** to obtain a valid user ID.", + description: "The user ID of the task assignee.", optional: true, }, priority: { diff --git a/components/pipedrive/actions/list-projects/list-projects.mjs b/components/pipedrive/actions/list-projects/list-projects.mjs index b67ca67987fd4..fc533f1ba7b5f 100644 --- a/components/pipedrive/actions/list-projects/list-projects.mjs +++ b/components/pipedrive/actions/list-projects/list-projects.mjs @@ -1,5 +1,4 @@ import pipedriveApp from "../../pipedrive.app.mjs"; -import constants from "../../common/constants.mjs"; export default { key: "pipedrive-list-projects", @@ -15,17 +14,18 @@ export default { props: { pipedriveApp, status: { - type: "string", - label: "Status", + propDefinition: [ + pipedriveApp, + "projectStatus", + ], description: "Filter by project status. One of: open, completed, canceled, deleted (deleted excluded by default).", - options: constants.PROJECT_STATUS_OPTIONS, - optional: true, }, phaseId: { - type: "string", - label: "Phase ID", + propDefinition: [ + pipedriveApp, + "projectPhaseId", + ], description: "Filter by phase ID. Run **List Project Phases** first to obtain a valid phase ID.", - optional: true, }, dealId: { type: "string", @@ -55,9 +55,9 @@ export default { limit: { type: "integer", label: "Limit", - description: "For pagination, the number of entries to return. Min 1, max 1000. Note: the API enforces a server-side cap of 500. Defaults to 100 if omitted.", + description: "For pagination, the number of entries to return. Min 1, max 500 (server-side cap). Defaults to 100 if omitted.", min: 1, - max: 1000, + max: 500, optional: true, }, cursor: { diff --git a/components/pipedrive/actions/list-tasks/list-tasks.mjs b/components/pipedrive/actions/list-tasks/list-tasks.mjs index eaa42d1b39b55..f7eb71b2e78b0 100644 --- a/components/pipedrive/actions/list-tasks/list-tasks.mjs +++ b/components/pipedrive/actions/list-tasks/list-tasks.mjs @@ -20,15 +20,18 @@ export default { optional: true, }, assigneeId: { - type: "string", + propDefinition: [ + pipedriveApp, + "userId", + ], label: "Assignee ID", - description: "Filter tasks by assignee (user) ID. Run **List User ID Options** to obtain a valid user ID.", + description: "Filter tasks by assignee (user) ID.", optional: true, }, parentTaskId: { type: "string", label: "Parent Task ID", - description: "Filter by parent task ID. Omit for root-level tasks only; provide an integer to return subtasks of that task.", + description: "Filter by parent task ID. Omit to return all tasks (default); provide an integer to return only subtasks of that specific task. (Note: the API also accepts `null` to return only root-level tasks, but this prop cannot represent a null value — use a downstream filter step to restrict to root-level tasks.)", optional: true, }, isDone: { diff --git a/components/pipedrive/actions/update-project/update-project.mjs b/components/pipedrive/actions/update-project/update-project.mjs index 57227eab09738..99f0ac0e94f1a 100644 --- a/components/pipedrive/actions/update-project/update-project.mjs +++ b/components/pipedrive/actions/update-project/update-project.mjs @@ -1,5 +1,4 @@ import pipedriveApp from "../../pipedrive.app.mjs"; -import constants from "../../common/constants.mjs"; export default { key: "pipedrive-update-project", @@ -32,11 +31,11 @@ export default { optional: true, }, status: { - type: "string", - label: "Status", + propDefinition: [ + pipedriveApp, + "projectStatus", + ], description: "The updated status of the project. One of: open, completed, canceled, deleted.", - options: constants.PROJECT_STATUS_OPTIONS, - optional: true, }, boardId: { type: "string", @@ -45,10 +44,11 @@ export default { optional: true, }, phaseId: { - type: "string", - label: "Phase ID", + propDefinition: [ + pipedriveApp, + "projectPhaseId", + ], description: "The ID of the phase. Run **List Project Phases** first to obtain a valid phase ID.", - optional: true, }, ownerId: { type: "string", diff --git a/components/pipedrive/actions/update-task/update-task.mjs b/components/pipedrive/actions/update-task/update-task.mjs index 0bce4218410c2..7f79f9ba04fc0 100644 --- a/components/pipedrive/actions/update-task/update-task.mjs +++ b/components/pipedrive/actions/update-task/update-task.mjs @@ -59,9 +59,12 @@ export default { optional: true, }, assigneeId: { - type: "string", + propDefinition: [ + pipedriveApp, + "userId", + ], label: "Assignee ID", - description: "The user ID of the task assignee. Run **List User ID Options** to obtain a valid user ID.", + description: "The user ID of the task assignee.", optional: true, }, priority: { diff --git a/components/pipedrive/pipedrive.app.mjs b/components/pipedrive/pipedrive.app.mjs index dbf9f4a1d0d47..f962afece30d8 100644 --- a/components/pipedrive/pipedrive.app.mjs +++ b/components/pipedrive/pipedrive.app.mjs @@ -159,6 +159,19 @@ export default { optional: true, options: constants.STATUS_OPTIONS, }, + projectStatus: { + type: "string", + label: "Status", + description: "The status of the project. One of: open, completed, canceled, deleted.", + options: constants.PROJECT_STATUS_OPTIONS, + optional: true, + }, + projectPhaseId: { + type: "string", + label: "Phase ID", + description: "The ID of the project phase. Run **List Project Phases** first to obtain a valid phase ID.", + optional: true, + }, dealId: { type: "string", label: "Deal ID", From 22f0f9e45e29182bc60536fc270ebaa5349ea293 Mon Sep 17 00:00:00 2001 From: Michelle Bergeron Date: Mon, 6 Jul 2026 14:10:43 -0400 Subject: [PATCH 4/5] =?UTF-8?q?fix(pipedrive):=20projects/tasks=20methods?= =?UTF-8?q?=20must=20not=20use=20the=20JS=20SDK=20=E2=80=94=20v2=20classes?= =?UTF-8?q?=20don't=20exist?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `pipedrive@^24.1.1` JS SDK does not export ProjectsApi or TasksApi in its v2 module (v1 has them; v2 only exposes Activities, Beta, Deals, ItemSearch, Leads, Organizations, Persons, Pipelines, Products, Stages). Runtime instantiation confirms: `pd.v2.ProjectsApi is not a constructor`. All ten project/task app methods (`listProjects`, `addProject`, `getProject`, `updateProject`, `deleteProject`, `listTasks`, `addTask`, `getTask`, `updateTask`, `deleteTask`) were calling `this.api("ProjectsApi", "v2")` / `this.api("TasksApi", "v2")` — every one of them would TypeError on first invocation. Actions publish cleanly but crash on the first eval. Rewrite the ten methods to use raw axios against `/api/v2/*` — same pattern boards/phases already needed (the SDK never had those classes either). Introduce a small `_v2Request` helper on the app so the auth header + baseURL + method dispatch live in one place, and fold `getProjectBoards` / `getProjectPhases` through it so they stop duplicating axios setup (addresses the earlier reviewer note). Method signatures now take a first-argument object with `$` explicitly (matching the boards/phases pattern), so update all twelve action call-sites to pass `$` through for step-trace attribution. --- .../actions/create-project/create-project.mjs | 1 + .../actions/create-task/create-task.mjs | 1 + .../actions/delete-project/delete-project.mjs | 5 +- .../actions/delete-task/delete-task.mjs | 5 +- .../actions/get-project/get-project.mjs | 5 +- .../pipedrive/actions/get-task/get-task.mjs | 5 +- .../actions/list-projects/list-projects.mjs | 1 + .../actions/list-tasks/list-tasks.mjs | 1 + .../actions/update-project/update-project.mjs | 1 + .../actions/update-task/update-task.mjs | 1 + components/pipedrive/pipedrive.app.mjs | 147 +++++++++++------- 11 files changed, 117 insertions(+), 56 deletions(-) diff --git a/components/pipedrive/actions/create-project/create-project.mjs b/components/pipedrive/actions/create-project/create-project.mjs index a9bd717ca0c81..5ebba16837c87 100644 --- a/components/pipedrive/actions/create-project/create-project.mjs +++ b/components/pipedrive/actions/create-project/create-project.mjs @@ -88,6 +88,7 @@ export default { }, async run({ $ }) { const response = await this.pipedriveApp.addProject({ + $, title: this.title, description: this.description, status: this.status, diff --git a/components/pipedrive/actions/create-task/create-task.mjs b/components/pipedrive/actions/create-task/create-task.mjs index 475bb411a817e..2e22dd2ed7124 100644 --- a/components/pipedrive/actions/create-task/create-task.mjs +++ b/components/pipedrive/actions/create-task/create-task.mjs @@ -82,6 +82,7 @@ export default { }, async run({ $ }) { const response = await this.pipedriveApp.addTask({ + $, title: this.title, project_id: this.projectId, parent_task_id: this.parentTaskId, diff --git a/components/pipedrive/actions/delete-project/delete-project.mjs b/components/pipedrive/actions/delete-project/delete-project.mjs index 3e8c6149b2100..8983db3e3b327 100644 --- a/components/pipedrive/actions/delete-project/delete-project.mjs +++ b/components/pipedrive/actions/delete-project/delete-project.mjs @@ -20,7 +20,10 @@ export default { }, }, async run({ $ }) { - const response = await this.pipedriveApp.deleteProject(this.projectId); + const response = await this.pipedriveApp.deleteProject({ + $, + projectId: this.projectId, + }); $.export("$summary", `Successfully deleted project ${this.projectId}`); return response; }, diff --git a/components/pipedrive/actions/delete-task/delete-task.mjs b/components/pipedrive/actions/delete-task/delete-task.mjs index ad4e23fc87028..124ef7817dcbb 100644 --- a/components/pipedrive/actions/delete-task/delete-task.mjs +++ b/components/pipedrive/actions/delete-task/delete-task.mjs @@ -20,7 +20,10 @@ export default { }, }, async run({ $ }) { - const response = await this.pipedriveApp.deleteTask(this.taskId); + const response = await this.pipedriveApp.deleteTask({ + $, + taskId: this.taskId, + }); $.export("$summary", `Successfully deleted task ${this.taskId}`); return response; }, diff --git a/components/pipedrive/actions/get-project/get-project.mjs b/components/pipedrive/actions/get-project/get-project.mjs index 32a06a609be29..f2f8757f3580f 100644 --- a/components/pipedrive/actions/get-project/get-project.mjs +++ b/components/pipedrive/actions/get-project/get-project.mjs @@ -20,7 +20,10 @@ export default { }, }, async run({ $ }) { - const response = await this.pipedriveApp.getProject(this.projectId); + const response = await this.pipedriveApp.getProject({ + $, + projectId: this.projectId, + }); $.export("$summary", `Successfully retrieved project ${this.projectId}`); return response; }, diff --git a/components/pipedrive/actions/get-task/get-task.mjs b/components/pipedrive/actions/get-task/get-task.mjs index 55344172f9575..5d16b38a9491a 100644 --- a/components/pipedrive/actions/get-task/get-task.mjs +++ b/components/pipedrive/actions/get-task/get-task.mjs @@ -20,7 +20,10 @@ export default { }, }, async run({ $ }) { - const response = await this.pipedriveApp.getTask(this.taskId); + const response = await this.pipedriveApp.getTask({ + $, + taskId: this.taskId, + }); $.export("$summary", `Successfully retrieved task ${this.taskId}`); return response; }, diff --git a/components/pipedrive/actions/list-projects/list-projects.mjs b/components/pipedrive/actions/list-projects/list-projects.mjs index fc533f1ba7b5f..84f725d3e1864 100644 --- a/components/pipedrive/actions/list-projects/list-projects.mjs +++ b/components/pipedrive/actions/list-projects/list-projects.mjs @@ -69,6 +69,7 @@ export default { }, async run({ $ }) { const response = await this.pipedriveApp.listProjects({ + $, status: this.status, phase_id: this.phaseId, deal_id: this.dealId, diff --git a/components/pipedrive/actions/list-tasks/list-tasks.mjs b/components/pipedrive/actions/list-tasks/list-tasks.mjs index f7eb71b2e78b0..e84573f778845 100644 --- a/components/pipedrive/actions/list-tasks/list-tasks.mjs +++ b/components/pipedrive/actions/list-tasks/list-tasks.mjs @@ -63,6 +63,7 @@ export default { }, async run({ $ }) { const response = await this.pipedriveApp.listTasks({ + $, project_id: this.projectId, assignee_id: this.assigneeId, parent_task_id: this.parentTaskId, diff --git a/components/pipedrive/actions/update-project/update-project.mjs b/components/pipedrive/actions/update-project/update-project.mjs index 99f0ac0e94f1a..e4708231d414e 100644 --- a/components/pipedrive/actions/update-project/update-project.mjs +++ b/components/pipedrive/actions/update-project/update-project.mjs @@ -71,6 +71,7 @@ export default { }, async run({ $ }) { const response = await this.pipedriveApp.updateProject({ + $, projectId: this.projectId, title: this.title, description: this.description, diff --git a/components/pipedrive/actions/update-task/update-task.mjs b/components/pipedrive/actions/update-task/update-task.mjs index 7f79f9ba04fc0..15112dabcca46 100644 --- a/components/pipedrive/actions/update-task/update-task.mjs +++ b/components/pipedrive/actions/update-task/update-task.mjs @@ -77,6 +77,7 @@ export default { }, async run({ $ }) { const response = await this.pipedriveApp.updateTask({ + $, taskId: this.taskId, title: this.title, description: this.description, diff --git a/components/pipedrive/pipedrive.app.mjs b/components/pipedrive/pipedrive.app.mjs index f962afece30d8..741c2b2076d7b 100644 --- a/components/pipedrive/pipedrive.app.mjs +++ b/components/pipedrive/pipedrive.app.mjs @@ -759,87 +759,130 @@ export default { id: noteId, }); }, - listProjects(opts = {}) { - const projectApi = this.api("ProjectsApi", "v2"); - return projectApi.getProjects(opts); + // Projects, project boards + phases, and Tasks live on Pipedrive's + // /api/v2/* REST endpoints but the JS SDK's v2 exports don't include + // ProjectsApi, TasksApi, BoardsApi, or PhasesApi. Route through raw + // axios with a small helper that stamps the auth header + baseURL. + _v2Request({ + $, path, method = "GET", params, data, + }) { + return axios($, { + method, + url: `${this.$auth.api_domain}/api/v2${path}`, + headers: { + Authorization: `Bearer ${this.$auth.oauth_access_token}`, + }, + params, + data, + }); }, - addProject(opts = {}) { - const projectApi = this.api("ProjectsApi", "v2"); - return projectApi.addProject({ - AddProjectRequest: opts, + listProjects({ + $, ...params + } = {}) { + return this._v2Request({ + $, + path: "/projects", + params, }); }, - getProject(projectId) { - const projectApi = this.api("ProjectsApi", "v2"); - return projectApi.getProject({ - id: projectId, + addProject({ + $, ...data + } = {}) { + return this._v2Request({ + $, + method: "POST", + path: "/projects", + data, + }); + }, + getProject({ + $, projectId, + }) { + return this._v2Request({ + $, + path: `/projects/${projectId}`, }); }, updateProject({ - projectId, ...opts + $, projectId, ...data }) { - const projectApi = this.api("ProjectsApi", "v2"); - return projectApi.updateProject({ - id: projectId, - UpdateProjectRequest: opts, + return this._v2Request({ + $, + method: "PATCH", + path: `/projects/${projectId}`, + data, }); }, - deleteProject(projectId) { - const projectApi = this.api("ProjectsApi", "v2"); - return projectApi.deleteProject({ - id: projectId, + deleteProject({ + $, projectId, + }) { + return this._v2Request({ + $, + method: "DELETE", + path: `/projects/${projectId}`, }); }, - getProjectBoards({ $ }) { - return axios($, { - url: `${this.$auth.api_domain}/api/v2/boards`, - headers: { - Authorization: `Bearer ${this.$auth.oauth_access_token}`, - }, + getProjectBoards({ $ } = {}) { + return this._v2Request({ + $, + path: "/boards", }); }, getProjectPhases({ - boardId, $, + $, boardId, }) { - return axios($, { - url: `${this.$auth.api_domain}/api/v2/phases`, - headers: { - Authorization: `Bearer ${this.$auth.oauth_access_token}`, - }, + return this._v2Request({ + $, + path: "/phases", params: { board_id: boardId, }, }); }, - listTasks(opts = {}) { - const taskApi = this.api("TasksApi", "v2"); - return taskApi.getTasks(opts); + listTasks({ + $, ...params + } = {}) { + return this._v2Request({ + $, + path: "/tasks", + params, + }); }, - addTask(opts = {}) { - const taskApi = this.api("TasksApi", "v2"); - return taskApi.addTask({ - AddTaskRequest: opts, + addTask({ + $, ...data + } = {}) { + return this._v2Request({ + $, + method: "POST", + path: "/tasks", + data, }); }, - getTask(taskId) { - const taskApi = this.api("TasksApi", "v2"); - return taskApi.getTask({ - id: taskId, + getTask({ + $, taskId, + }) { + return this._v2Request({ + $, + path: `/tasks/${taskId}`, }); }, updateTask({ - taskId, ...opts + $, taskId, ...data }) { - const taskApi = this.api("TasksApi", "v2"); - return taskApi.updateTask({ - id: taskId, - UpdateTaskRequest: opts, + return this._v2Request({ + $, + method: "PATCH", + path: `/tasks/${taskId}`, + data, }); }, - deleteTask(taskId) { - const taskApi = this.api("TasksApi", "v2"); - return taskApi.deleteTask({ - id: taskId, + deleteTask({ + $, taskId, + }) { + return this._v2Request({ + $, + method: "DELETE", + path: `/tasks/${taskId}`, }); }, getPerson(personId) { From 3445f0d2dfec5151e6a99d28fff3b22650cc77a3 Mon Sep 17 00:00:00 2001 From: Michelle Bergeron Date: Mon, 6 Jul 2026 14:29:27 -0400 Subject: [PATCH 5/5] refactor(pipedrive): share boardId + ownerId propDefs between create/update-project MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add a new `projectBoardId` propDefinition on pipedriveApp; create-project and update-project now reference it via propDefinition and only override their descriptions. Matches the `projectStatus` / `projectPhaseId` pattern. * Point `ownerId` in both actions at the existing `userId` propDef instead of duplicating the inline `string` schema — inherits its integer type (correct per Pipedrive v2) and its searchable user picker. Matches how `assigneeId` in the task actions was resolved in the previous review pass. --- .../actions/create-project/create-project.mjs | 14 +++++++++----- .../actions/update-project/update-project.mjs | 14 +++++++++----- components/pipedrive/pipedrive.app.mjs | 6 ++++++ 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/components/pipedrive/actions/create-project/create-project.mjs b/components/pipedrive/actions/create-project/create-project.mjs index 5ebba16837c87..d5e81318c8e00 100644 --- a/components/pipedrive/actions/create-project/create-project.mjs +++ b/components/pipedrive/actions/create-project/create-project.mjs @@ -31,10 +31,11 @@ export default { ], }, boardId: { - type: "string", - label: "Board ID", + propDefinition: [ + pipedriveApp, + "projectBoardId", + ], description: "The ID of the board this project belongs to. Run **List Project Boards** first to obtain a valid board ID.", - optional: true, }, phaseId: { propDefinition: [ @@ -44,9 +45,12 @@ export default { description: "The ID of the phase this project belongs to. Run **List Project Phases** (with the chosen board ID) first to obtain a valid phase ID.", }, ownerId: { - type: "string", + propDefinition: [ + pipedriveApp, + "userId", + ], label: "Owner ID", - description: "The user ID of the project owner. Run **List User ID Options** to obtain a valid user ID.", + description: "The user ID of the project owner.", optional: true, }, startDate: { diff --git a/components/pipedrive/actions/update-project/update-project.mjs b/components/pipedrive/actions/update-project/update-project.mjs index e4708231d414e..f1345124cc5a3 100644 --- a/components/pipedrive/actions/update-project/update-project.mjs +++ b/components/pipedrive/actions/update-project/update-project.mjs @@ -38,10 +38,11 @@ export default { description: "The updated status of the project. One of: open, completed, canceled, deleted.", }, boardId: { - type: "string", - label: "Board ID", + propDefinition: [ + pipedriveApp, + "projectBoardId", + ], description: "The ID of the board. Run **List Project Boards** first to obtain a valid board ID.", - optional: true, }, phaseId: { propDefinition: [ @@ -51,9 +52,12 @@ export default { description: "The ID of the phase. Run **List Project Phases** first to obtain a valid phase ID.", }, ownerId: { - type: "string", + propDefinition: [ + pipedriveApp, + "userId", + ], label: "Owner ID", - description: "The user ID of the project owner. Use **List Users** to obtain a valid user ID.", + description: "The user ID of the project owner.", optional: true, }, startDate: { diff --git a/components/pipedrive/pipedrive.app.mjs b/components/pipedrive/pipedrive.app.mjs index 741c2b2076d7b..4c130dfe6db8e 100644 --- a/components/pipedrive/pipedrive.app.mjs +++ b/components/pipedrive/pipedrive.app.mjs @@ -172,6 +172,12 @@ export default { description: "The ID of the project phase. Run **List Project Phases** first to obtain a valid phase ID.", optional: true, }, + projectBoardId: { + type: "string", + label: "Board ID", + description: "The ID of the project board. Run **List Project Boards** first to obtain a valid board ID.", + optional: true, + }, dealId: { type: "string", label: "Deal ID",