Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/pipedrive/actions/add-activity/add-activity.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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.9",
version: "0.1.10",
type: "action",
props: {
pipedriveApp,
Expand Down
2 changes: 1 addition & 1 deletion components/pipedrive/actions/add-deal/add-deal.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,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.9",
version: "0.1.10",
type: "action",
props: {
pipedriveApp,
Expand Down
2 changes: 1 addition & 1 deletion components/pipedrive/actions/add-lead/add-lead.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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.3",
version: "0.0.4",
type: "action",
props: {
pipedrive,
Expand Down
2 changes: 1 addition & 1 deletion components/pipedrive/actions/add-note/add-note.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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.7",
version: "0.0.8",
type: "action",
props: {
pipedriveApp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.9",
version: "0.1.10",
type: "action",
props: {
pipedriveApp,
Expand Down
2 changes: 1 addition & 1 deletion components/pipedrive/actions/add-person/add-person.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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.9",
version: "0.1.10",
type: "action",
props: {
pipedriveApp,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import pipedriveApp from "../../pipedrive.app.mjs";

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.1",
type: "action",
props: {
pipedriveApp,
leadId: {
propDefinition: [
pipedriveApp,
"leadId",
],
description: "The ID of the lead that the notes are attached to",
},
dealId: {
propDefinition: [
pipedriveApp,
"dealId",
],
description: "The ID of the deal that the notes are attached to",
},
personId: {
propDefinition: [
pipedriveApp,
"personId",
],
description: "The ID of the person that the notes are attached to",
},
organizationId: {
propDefinition: [
pipedriveApp,
"organizationId",
],
description: "The ID of the organization that the notes are attached to",
},
userId: {
propDefinition: [
pipedriveApp,
"userId",
],
description: "The ID of the user that the notes are attached to",
},
projectId: {
propDefinition: [
pipedriveApp,
"projectId",
],
description: "The ID of the project that the notes are attached to",
},
keyword: {
type: "string",
label: "Keyword",
description: "Only remove duplicate notes that contain the specified keyword(s)",
optional: true,
},
},
methods: {
getDuplicateNotes(notes) {
const seenContent = new Map();
const uniqueNotes = [];
const duplicates = [];

// Sort notes by add_time (ascending) to keep the oldest duplicate
const sortedNotes = notes.sort((a, b) => {
const dateA = new Date(a.add_time);
const dateB = new Date(b.add_time);
return dateA - dateB;
});

for (const note of sortedNotes) {
// Normalize content by removing extra whitespace and converting to lowercase
const normalizedContent = note.content?.trim().toLowerCase();

if (!normalizedContent) {
// Skip notes with empty content
continue;
}

if (seenContent.has(normalizedContent)) {
// This is a duplicate
duplicates.push({
duplicate: note,
original: seenContent.get(normalizedContent),
});
} else {
// This is the first occurrence
seenContent.set(normalizedContent, note);
uniqueNotes.push(note);
}
}

return {
uniqueNotes,
duplicates,
duplicateCount: duplicates.length,
};
},
},
async run({ $ }) {
let notes = await this.pipedriveApp.getPaginatedResources({
fn: this.pipedriveApp.getNotes,
params: {
user_id: this.userId,
lead_id: this.leadId,
deal_id: this.dealId,
person_id: this.personId,
org_id: this.organizationId,
project_id: this.projectId,
},
});

if (this.keyword) {
notes = notes.filter((note) =>
note.content.toLowerCase().includes(this.keyword.toLowerCase()));
}

let result = {
notes,
totalNotes: notes.length,
};

const {
uniqueNotes, duplicates, duplicateCount,
} = this.getDuplicateNotes(notes);

for (const note of duplicates) {
await this.pipedriveApp.deleteNote(note.duplicate.id);
}

result = {
notes: uniqueNotes,
totalNotes: uniqueNotes.length,
duplicatesFound: duplicateCount,
duplicates: duplicates,
originalCount: notes.length,
};

$.export("$summary", `Found ${notes.length} total note(s), removed ${duplicateCount} duplicate(s), returning ${uniqueNotes.length} unique note(s)`);

return result;
},
};
179 changes: 179 additions & 0 deletions components/pipedrive/actions/search-notes/search-notes.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import pipedriveApp from "../../pipedrive.app.mjs";

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.1",
type: "action",
props: {
pipedriveApp,
searchTerm: {
type: "string",
label: "Search Term",
description: "The term to search for in the note content",
optional: true,
},
leadId: {
propDefinition: [
pipedriveApp,
"leadId",
],
description: "The ID of the lead that the note is attached to",
},
dealId: {
propDefinition: [
pipedriveApp,
"dealId",
],
description: "The ID of the deal that the note is attached to",
},
personId: {
propDefinition: [
pipedriveApp,
"personId",
],
description: "The ID of the person that the note is attached to",
},
organizationId: {
propDefinition: [
pipedriveApp,
"organizationId",
],
description: "The ID of the organization that the note is attached to",
},
userId: {
propDefinition: [
pipedriveApp,
"userId",
],
description: "The ID of the user that the note is attached to",
},
projectId: {
propDefinition: [
pipedriveApp,
"projectId",
],
description: "The ID of the project that the note is attached to",
},
sortField: {
type: "string",
label: "Sort Field",
description: "The field name to sort by",
options: [
"id",
"user_id",
"deal_id",
"org_id",
"person_id",
"content",
"add_time",
"update_time",
],
optional: true,
},
sortDirection: {
type: "string",
label: "Sort Direction",
description: "The direction to sort the results in",
options: [
"ASC",
"DESC",
],
default: "DESC",
optional: true,
},
startDate: {
type: "string",
label: "Start Date",
description: "The date in format of YYYY-MM-DD from which notes to fetch",
optional: true,
},
endDate: {
type: "string",
label: "End Date",
description: "The date in format of YYYY-MM-DD until which notes to fetch to",
optional: true,
},
pinnedToLeadFlag: {
type: "boolean",
label: "Pinned to Lead Flag",
description: "If `true`, the results are filtered by note to lead pinning state",
optional: true,
},
pinnedToDealFlag: {
type: "boolean",
label: "Pinned to Deal Flag",
description: "If `true`, the results are filtered by note to deal pinning state",
optional: true,
},
pinnedToOrganizationFlag: {
type: "boolean",
label: "Pinned to Organization Flag",
description: "If `true`, the results are filtered by note to organization pinning state",
optional: true,
},
pinnedToPersonFlag: {
type: "boolean",
label: "Pinned to Person Flag",
description: "If `true`, the results are filtered by note to person pinning state",
optional: true,
},
pinnedToProjectFlag: {
type: "boolean",
label: "Pinned to Project Flag",
description: "If `true`, the results are filtered by note to project pinning state",
optional: true,
},
maxResults: {
type: "integer",
label: "Max Results",
description: "The maximum number of results to return",
optional: true,
},
},
async run({ $ }) {
let notes = await this.pipedriveApp.getPaginatedResources({
fn: this.pipedriveApp.getNotes,
params: {
user_id: this.userId,
lead_id: this.leadId,
deal_id: this.dealId,
person_id: this.personId,
org_id: this.organizationId,
project_id: this.projectId,
sort: this.sortField
? `${this.sortField} ${this.sortDirection}`
: undefined,
pinned_to_lead_flag: this.pinnedToLeadFlag
? 1
: 0,
pinned_to_deal_flag: this.pinnedToDealFlag
? 1
: 0,
pinned_to_organization_flag: this.pinnedToOrganizationFlag
? 1
: 0,
pinned_to_person_flag: this.pinnedToPersonFlag
? 1
: 0,
pinned_to_project_flag: this.pinnedToProjectFlag
? 1
: 0,
start_date: this.startDate,
end_date: this.endDate,
},
max: this.maxResults,
});

if (this.searchTerm) {
notes = notes.filter((note) =>
note.content.toLowerCase().includes(this.searchTerm.toLowerCase()));
}

$.export("$summary", `Successfully found ${notes.length} note${notes.length === 1
? ""
: "s"}`);
return notes;
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,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.9",
version: "0.1.10",
type: "action",
props: {
pipedriveApp,
Expand Down
2 changes: 1 addition & 1 deletion components/pipedrive/actions/update-deal/update-deal.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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.11",
version: "0.1.12",
type: "action",
props: {
pipedriveApp,
Expand Down
Loading
Loading