Skip to content

Pipedrive - search-notes & remove-duplicate-notes actions #17045

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

michelle0927
Copy link
Collaborator

@michelle0927 michelle0927 commented Jun 9, 2025

Resolves #17009

Summary by CodeRabbit

  • New Features

    • Added the ability to search notes with advanced filtering options.
    • Introduced an action to remove duplicate notes from Pipedrive objects.
  • Improvements

    • Enhanced note management and pagination capabilities for more efficient data retrieval.
  • Chores

    • Updated version numbers for several actions and triggers to reflect recent changes.
    • Bumped package version to 0.6.0.

Copy link

vercel bot commented Jun 9, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

3 Skipped Deployments
Name Status Preview Comments Updated (UTC)
docs-v2 ⬜️ Ignored (Inspect) Visit Preview Jun 11, 2025 5:42pm
pipedream-docs ⬜️ Ignored (Inspect) Jun 11, 2025 5:42pm
pipedream-docs-redirect-do-not-edit ⬜️ Ignored (Inspect) Jun 11, 2025 5:42pm

Copy link
Contributor

coderabbitai bot commented Jun 9, 2025

Walkthrough

This update introduces two new actions for Pipedrive: one for searching notes with advanced filtering and another for detecting and removing duplicate notes, including optional keyword-based filtering. Supporting methods for note management and pagination are added to the app module. Several existing actions and sources receive version number bumps, with no other logic changes.

Changes

File(s) Change Summary
components/pipedrive/actions/add-activity/add-activity.mjs
components/pipedrive/actions/add-deal/add-deal.mjs
components/pipedrive/actions/add-lead/add-lead.mjs
components/pipedrive/actions/add-note/add-note.mjs
components/pipedrive/actions/add-organization/add-organization.mjs
components/pipedrive/actions/add-person/add-person.mjs
components/pipedrive/actions/search-persons/search-persons.mjs
components/pipedrive/actions/update-deal/update-deal.mjs
components/pipedrive/actions/update-person/update-person.mjs
components/pipedrive/sources/new-deal-instant/new-deal-instant.mjs
components/pipedrive/sources/new-person-instant/new-person-instant.mjs
components/pipedrive/sources/updated-deal-instant/updated-deal-instant.mjs
components/pipedrive/sources/updated-person-instant/updated-person-instant.mjs
Version number increment only; no functional or logic changes
components/pipedrive/actions/remove-duplicate-notes/remove-duplicate-notes.mjs New action: Identifies and removes duplicate notes for Pipedrive objects, with optional keyword filtering
components/pipedrive/actions/search-notes/search-notes.mjs New action: Searches notes with multiple filters, term search, sorting, and result limiting
components/pipedrive/pipedrive.app.mjs Adds methods: getNotes, deleteNote, paginate, getPaginatedResources for note and pagination support
components/pipedrive/package.json Package version updated from 0.5.1 to 0.6.0

Sequence Diagram(s)

Remove Duplicate Notes Action

sequenceDiagram
    participant User
    participant RemoveDuplicateNotesAction
    participant PipedriveApp

    User->>RemoveDuplicateNotesAction: Run action with object ID(s) and optional keyword
    RemoveDuplicateNotesAction->>PipedriveApp: getNotes (with filters)
    PipedriveApp-->>RemoveDuplicateNotesAction: Return all notes
    RemoveDuplicateNotesAction->>RemoveDuplicateNotesAction: Filter notes by keyword (if provided)
    RemoveDuplicateNotesAction->>RemoveDuplicateNotesAction: Identify duplicates by normalized content
    loop For each duplicate note
        RemoveDuplicateNotesAction->>PipedriveApp: deleteNote(noteId)
    end
    RemoveDuplicateNotesAction-->>User: Return summary and unique notes
Loading

Search Notes Action

sequenceDiagram
    participant User
    participant SearchNotesAction
    participant PipedriveApp

    User->>SearchNotesAction: Run action with filters/search term
    SearchNotesAction->>PipedriveApp: getNotes (with filters)
    PipedriveApp-->>SearchNotesAction: Return notes
    SearchNotesAction->>SearchNotesAction: Filter notes by search term (if provided)
    SearchNotesAction-->>User: Return filtered notes and summary
Loading

Assessment against linked issues

Objective Addressed Explanation
Add "search note" action in a specific deal in Pipedrive (#17009)
Detect if a note’s body in a deal is a duplicate (#17009)
Auto-delete or merge duplicate notes in a deal (#17009)

Poem

In the warren of code, where features grow,
Rabbits found notes that doubled in tow.
With a hop and a search, and a clever new trick,
Duplicates vanish—oh, that was quick!
Now, with each update and version anew,
Pipedrive is cleaner—thanks to this crew! 🐇✨

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

components/pipedrive/actions/remove-duplicate-notes/remove-duplicate-notes.mjs

Oops! Something went wrong! :(

ESLint: 8.57.1

Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'jsonc-eslint-parser' imported from /eslint.config.mjs
at Object.getPackageJSONURL (node:internal/modules/package_json_reader:255:9)
at packageResolve (node:internal/modules/esm/resolve:767:81)
at moduleResolve (node:internal/modules/esm/resolve:853:18)
at defaultResolve (node:internal/modules/esm/resolve:983:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:801:12)
at #cachedDefaultResolve (node:internal/modules/esm/loader:725:25)
at ModuleLoader.resolve (node:internal/modules/esm/loader:708:38)
at ModuleLoader.getModuleJobForImport (node:internal/modules/esm/loader:309:38)
at #link (node:internal/modules/esm/module_job:201:49)


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ff56676 and 52270ef.

📒 Files selected for processing (1)
  • components/pipedrive/actions/remove-duplicate-notes/remove-duplicate-notes.mjs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/pipedrive/actions/remove-duplicate-notes/remove-duplicate-notes.mjs
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Publish TypeScript components
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Lint Code Base
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (3)
components/pipedrive/actions/search-notes/search-notes.mjs (1)

136-167: Consider performance implications of client-side filtering.

The current implementation fetches all notes matching the API filters and then applies the search term filter locally. For large datasets, this could be inefficient and may hit memory or timeout limits.

Consider implementing server-side search if the Pipedrive API supports it, or add pagination limits when using search terms to prevent excessive data retrieval.

components/pipedrive/actions/remove-duplicate-notes/remove-duplicate-notes.mjs (2)

129-131: Consider implementing parallel deletion for better performance.

Sequential deletion of duplicates could be slow for large numbers of duplicates. Consider implementing parallel deletion with appropriate rate limiting.

-    for (const note of duplicates) {
-      try {
-        await this.pipedriveApp.deleteNote(note.duplicate.id);
-        deletionResults.push({ id: note.duplicate.id, success: true });
-      } catch (error) {
-        console.error(`Failed to delete note ${note.duplicate.id}:`, error);
-        deletionResults.push({ id: note.duplicate.id, success: false, error: error.message });
-      }
-    }
+    const batchSize = 5; // Adjust based on API rate limits
+    const deletionResults = [];
+    
+    for (let i = 0; i < duplicates.length; i += batchSize) {
+      const batch = duplicates.slice(i, i + batchSize);
+      const batchPromises = batch.map(async (note) => {
+        try {
+          await this.pipedriveApp.deleteNote(note.duplicate.id);
+          return { id: note.duplicate.id, success: true };
+        } catch (error) {
+          console.error(`Failed to delete note ${note.duplicate.id}:`, error);
+          return { id: note.duplicate.id, success: false, error: error.message };
+        }
+      });
+      
+      const batchResults = await Promise.all(batchPromises);
+      deletionResults.push(...batchResults);
+    }

3-8: Consider adding a dry-run mode for destructive operations.

Since this action performs destructive operations (deleting notes), consider adding a dry-run mode that identifies duplicates without actually deleting them.

Add a dryRun prop to allow users to preview what would be deleted:

   props: {
     pipedriveApp,
+    dryRun: {
+      type: "boolean",
+      label: "Dry Run",
+      description: "If true, identify duplicates without actually deleting them",
+      default: false,
+      optional: true,
+    },
     leadId: {

Then modify the deletion logic to conditionally skip actual deletion:

     for (const note of duplicates) {
-      try {
-        await this.pipedriveApp.deleteNote(note.duplicate.id);
-        deletionResults.push({ id: note.duplicate.id, success: true });
-      } catch (error) {
-        console.error(`Failed to delete note ${note.duplicate.id}:`, error);
-        deletionResults.push({ id: note.duplicate.id, success: false, error: error.message });
-      }
+      if (!this.dryRun) {
+        try {
+          await this.pipedriveApp.deleteNote(note.duplicate.id);
+          deletionResults.push({ id: note.duplicate.id, success: true });
+        } catch (error) {
+          console.error(`Failed to delete note ${note.duplicate.id}:`, error);
+          deletionResults.push({ id: note.duplicate.id, success: false, error: error.message });
+        }
+      } else {
+        deletionResults.push({ id: note.duplicate.id, success: true, dryRun: true });
+      }
     }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 084e31f and bbe30b4.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (17)
  • components/pipedrive/actions/add-activity/add-activity.mjs (1 hunks)
  • components/pipedrive/actions/add-deal/add-deal.mjs (1 hunks)
  • components/pipedrive/actions/add-lead/add-lead.mjs (1 hunks)
  • components/pipedrive/actions/add-note/add-note.mjs (1 hunks)
  • components/pipedrive/actions/add-organization/add-organization.mjs (1 hunks)
  • components/pipedrive/actions/add-person/add-person.mjs (1 hunks)
  • components/pipedrive/actions/remove-duplicate-notes/remove-duplicate-notes.mjs (1 hunks)
  • components/pipedrive/actions/search-notes/search-notes.mjs (1 hunks)
  • components/pipedrive/actions/search-persons/search-persons.mjs (1 hunks)
  • components/pipedrive/actions/update-deal/update-deal.mjs (1 hunks)
  • components/pipedrive/actions/update-person/update-person.mjs (1 hunks)
  • components/pipedrive/package.json (1 hunks)
  • components/pipedrive/pipedrive.app.mjs (2 hunks)
  • components/pipedrive/sources/new-deal-instant/new-deal-instant.mjs (1 hunks)
  • components/pipedrive/sources/new-person-instant/new-person-instant.mjs (1 hunks)
  • components/pipedrive/sources/updated-deal-instant/updated-deal-instant.mjs (1 hunks)
  • components/pipedrive/sources/updated-person-instant/updated-person-instant.mjs (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Publish TypeScript components
  • GitHub Check: Verify TypeScript components
  • GitHub Check: pnpm publish
  • GitHub Check: Lint Code Base
🔇 Additional comments (18)
components/pipedrive/pipedrive.app.mjs (4)

358-361: LGTM! Note retrieval method correctly implemented.

The getNotes method follows the established pattern used by other API methods in this module and correctly instantiates the NotesApi.


432-437: LGTM! Note deletion method correctly implemented.

The deleteNote method follows the established pattern and correctly passes the note ID as expected by the Pipedrive API.


464-471: LGTM! Pagination utility correctly implemented.

The getPaginatedResources method correctly collects all results from the paginate generator and follows JavaScript async iteration patterns properly.


438-463:

✅ Verification successful

Verify pagination structure with Pipedrive API documentation.

The pagination logic assumes the response structure additional_data.pagination.more_items_in_collection, but this should be verified against the Pipedrive API documentation to ensure consistency across different endpoints.


🌐 Web query:

What is the standard pagination response structure for Pipedrive API v1 and v2?

💡 Result:

Pipedrive's API employs two primary pagination methods across its endpoints: cursor-based pagination and offset-based pagination. The choice between these methods depends on the specific API version and endpoint.

1. Cursor-Based Pagination:

This method is utilized in Pipedrive API v2 and certain v1 endpoints, such as /v1/activities/collection, /v1/deals/collection, /v1/organizations/collection, and /v1/persons/collection. It offers efficient and stable performance when traversing large datasets.

  • Request Parameters:

    • cursor (string): An opaque string representing the first item on the next page.
    • limit (integer): The number of items to return per page. Defaults to 100 if not specified; maximum is 500.
  • Response Structure:

    • success (boolean): Indicates the success of the request.
    • data (array): Contains the list of items for the current page.
    • additional_data (object): Includes pagination details.
      • next_cursor (string|null): The cursor for the next page. If null, there are no more pages.

Example Response:

{
  "success": true,
  "data": [
    {
      // Item data
    }
  ],
  "additional_data": {
    "next_cursor": "eyJhY3Rpdml0eSI6NDJ9"
  }
}

(pipedrive.readme.io)

2. Offset-Based Pagination:

This method is employed in Pipedrive API v1 for most list and item collection endpoints.

  • Request Parameters:

    • start (integer): The offset to start fetching items. Defaults to 0 if not specified.
    • limit (integer): The number of items to return per page. Defaults to 100 if not specified; maximum is 500.
  • Response Structure:

    • success (boolean): Indicates the success of the request.
    • data (array): Contains the list of items for the current page.
    • additional_data (object): Includes pagination details.
      • pagination (object):
        • start (integer): The offset used in the request.
        • limit (integer): The limit used in the request.
        • more_items_in_collection (boolean): Indicates if more items are available.
        • next_start (integer): The offset for the next page.

Example Response:

{
  "success": true,
  "data": [
    {
      // Item data
    }
  ],
  "additional_data": {
    "pagination": {
      "start": 0,
      "limit": 100,
      "more_items_in_collection": true,
      "next_start": 100
    }
  }
}

(pipedrive.readme.io)

Understanding these pagination structures is crucial for effectively navigating and retrieving data from Pipedrive's API.

Citations:


Offset-based pagination logic aligns with Pipedrive v1 API

The current implementation uses

  • params.start / params.limit
  • checks additional_data.pagination.more_items_in_collection

which matches Pipedrive’s offset-based pagination (v1) response structure. No changes are required here unless you plan to consume cursor-based (v2) endpoints—those would use additional_data.next_cursor and a different request parameter (cursor) instead.

components/pipedrive/package.json (1)

3-3: LGTM! Appropriate version bump for new features.

The minor version increment from 0.5.1 to 0.6.0 correctly follows semantic versioning for the addition of new note management functionality.

components/pipedrive/actions/add-activity/add-activity.mjs (1)

10-10: LGTM! Coordinated version bump for release consistency.

The patch version increment aligns with the overall package version update and maintains consistency across the Pipedrive integration components.

components/pipedrive/actions/add-person/add-person.mjs (1)

9-9: LGTM! Coordinated version bump for release consistency.

The patch version increment maintains consistency across the Pipedrive integration components and aligns with the package version update.

components/pipedrive/actions/update-deal/update-deal.mjs (1)

8-8: Align version bump with coordinated release.
The patch version has been correctly incremented from 0.1.11 to 0.1.12 in sync with other Pipedrive actions. No further logic changes are required.

components/pipedrive/actions/add-deal/add-deal.mjs (1)

8-8: Approve version increment.
The action’s version has been updated from 0.1.9 to 0.1.10 to align with the coordinated release. No code or behavior changes detected.

components/pipedrive/actions/add-lead/add-lead.mjs (1)

9-9: Approve version bump.
Updated the version from 0.0.3 to 0.0.4 to match the overarching Pipedrive integration release. Implementation remains unchanged.

components/pipedrive/sources/new-deal-instant/new-deal-instant.mjs (1)

9-9: Approve source version update.
Bumped the source version from 0.0.5 to 0.0.6 in line with other Pipedrive components. No functional modifications needed.

components/pipedrive/actions/add-note/add-note.mjs (1)

8-8: Approve version synchronization.
The version of the “Add Note” action has been correctly incremented from 0.0.7 to 0.0.8 alongside other coordinated Pipedrive updates. Behavior is unchanged.

components/pipedrive/sources/updated-deal-instant/updated-deal-instant.mjs (1)

9-9: Version bump approved
Updated to "0.0.6" to align with the coordinated Pipedrive integration release.

components/pipedrive/sources/new-person-instant/new-person-instant.mjs (1)

9-9: Version bump approved
Bumped to "0.0.6" in sync with other instant source components.

components/pipedrive/actions/search-persons/search-persons.mjs (1)

10-10: Version bump approved
Action version updated to "0.1.10" consistent with the broader action updates.

components/pipedrive/actions/add-organization/add-organization.mjs (1)

8-8: Version bump approved
Version incremented to "0.1.10" matching the coordinated release across Pipedrive actions.

components/pipedrive/actions/update-person/update-person.mjs (1)

9-9: Version bump approved
Updated to "0.0.2" to keep parity with the minor version rollout.

components/pipedrive/sources/updated-person-instant/updated-person-instant.mjs (1)

9-9: LGTM! Standard version bump.

Version increment from "0.0.5" to "0.0.6" is properly implemented with no functional changes.

lcaresia
lcaresia previously approved these changes Jun 10, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
components/pipedrive/actions/remove-duplicate-notes/remove-duplicate-notes.mjs (2)

67-71: ⚠️ Potential issue

Validate add_time before sorting to avoid NaN comparisons

new Date(<invalid>) yields Invalid Date; subtracting two invalid dates returns NaN, producing an unstable sort that can throw in V8 (Array.prototype.sort expects the callback to return a finite number). Use a safe fallback when add_time is missing or malformed.

-      const sortedNotes = notes.sort((a, b) => {
-        const dateA = new Date(a.add_time);
-        const dateB = new Date(b.add_time);
-        return dateA - dateB;
-      });
+      const sortedNotes = notes.sort((a, b) => {
+        const dateA = new Date(a.add_time || 0);
+        const dateB = new Date(b.add_time || 0);
+        if (isNaN(dateA) || isNaN(dateB)) {
+          return 0;              // keep original order for invalid dates
+        }
+        return dateA - dateB;
+      });

125-127: 🛠️ Refactor suggestion

Add per-deletion error handling so one failure doesn’t abort the run

A single 4xx/5xx response will currently reject the entire action, leaving subsequent duplicates undeleted. Wrap each deletion in try/catch, gather results, and report partial success.

-    for (const note of duplicates) {
-      await this.pipedriveApp.deleteNote(note.duplicate.id);
-    }
+    const deletionResults = [];
+    for (const { duplicate } of duplicates) {
+      try {
+        await this.pipedriveApp.deleteNote(duplicate.id);
+        deletionResults.push({ id: duplicate.id, success: true });
+      } catch (err) {
+        console.error(`Failed to delete note ${duplicate.id}`, err);
+        deletionResults.push({ id: duplicate.id, success: false, error: err.message });
+      }
+    }
+
+    const successfulDeletions = deletionResults.filter(r => r.success).length;
+    const failedDeletions     = deletionResults.length - successfulDeletions;
+
+    // update summary / result accordingly

Update the returned result and $summary to reflect successfulDeletions vs failedDeletions.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f23c3b1 and cdd06b8.

📒 Files selected for processing (1)
  • components/pipedrive/actions/remove-duplicate-notes/remove-duplicate-notes.mjs (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: pnpm publish
  • GitHub Check: Lint Code Base
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Publish TypeScript components
🔇 Additional comments (1)
components/pipedrive/actions/remove-duplicate-notes/remove-duplicate-notes.mjs (1)

112-114: Null-safe keyword filtering looks good

Using optional chaining on note.content prevents crashes on null/undefined notes.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
components/pipedrive/actions/remove-duplicate-notes/remove-duplicate-notes.mjs (3)

68-72: 🛠️ Refactor suggestion

add_time validation still missing – potential NaN sort ordering

new Date(a.add_time) returns Invalid Date when add_time is null/invalid, leading the comparison callback to return NaN → undefined ordering and hard-to-trace bugs.
The same issue was raised on a previous commit and remains unaddressed.

-const sortedNotes = notes.sort((a, b) => {
-  const dateA = new Date(a.add_time);
-  const dateB = new Date(b.add_time);
-  return dateA - dateB;
-});
+const sortedNotes = notes.sort((a, b) => {
+  const dateA = new Date(a.add_time || 0);
+  const dateB = new Date(b.add_time || 0);
+  if (isNaN(dateA) || isNaN(dateB)) return 0; // keep relative order
+  return dateA - dateB;
+});

107-117: 🛠️ Refactor suggestion

Undefined params still forwarded to the API

Keys with undefined values are still passed to getPaginatedResources, risking "undefined" string-serialization by the HTTP client. The earlier refactor suggestion to build the params object dynamically (and to throw if all IDs are missing) hasn’t been applied.

-  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,
-  },
+  params: Object.fromEntries(
+    Object.entries({
+      user_id: this.userId,
+      lead_id: this.leadId,
+      deal_id: this.dealId,
+      person_id: this.personId,
+      org_id: this.organizationId,
+      project_id: this.projectId,
+    }).filter(([, v]) => v != null),
+  ),

Consider throwing early if no ID is supplied.


133-135: 🛠️ Refactor suggestion

Sequential deletes without error handling

A single failure in deleteNote aborts the entire loop, leaving other duplicates undeleted. Add per-note try / catch and track successes/failures, or use Promise.allSettled with a throttle.

-for (const note of duplicates) {
-  await this.pipedriveApp.deleteNote(note.duplicate.id);
-}
+const deletionResults = [];
+for (const note of duplicates) {
+  try {
+    await this.pipedriveApp.deleteNote(note.duplicate.id);
+    deletionResults.push({ id: note.duplicate.id, success: true });
+  } catch (err) {
+    console.error(`Failed to delete note ${note.duplicate.id}:`, err);
+    deletionResults.push({ id: note.duplicate.id, success: false, error: err.message });
+  }
+}

Update the summary to reflect partial failures.

🧹 Nitpick comments (1)
components/pipedrive/actions/remove-duplicate-notes/remove-duplicate-notes.mjs (1)

124-128: Dead interim result object

result is initialised (lines 124-128) and then immediately overwritten at line 137. Remove the first assignment to reduce noise.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cdd06b8 and ff56676.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • components/pipedrive/actions/remove-duplicate-notes/remove-duplicate-notes.mjs (1 hunks)
  • components/pipedrive/package.json (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/pipedrive/package.json
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Publish TypeScript components
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Lint Code Base
  • GitHub Check: pnpm publish

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Pipedrive
2 participants