Skip to content

Conversation

@jcortes
Copy link
Collaborator

@jcortes jcortes commented Aug 6, 2025

WHY

Resolves #17702

Summary by CodeRabbit

  • New Features

    • Added actions to create, update, and retrieve hardware assets in Snipe-IT.
    • Introduced actions to create users, retrieve user assets, and fetch license details.
    • Enhanced Snipe-IT integration with dynamic property selection and comprehensive API support for assets, users, licenses, and related entities.
    • Added deep JSON parsing utility to handle nested custom fields safely.
  • Chores

    • Updated package version and added a dependency for improved platform compatibility.

@jcortes jcortes self-assigned this Aug 6, 2025
@vercel
Copy link

vercel bot commented Aug 6, 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 Aug 6, 2025 8:06pm
pipedream-docs ⬜️ Ignored (Inspect) Aug 6, 2025 8:06pm
pipedream-docs-redirect-do-not-edit ⬜️ Ignored (Inspect) Aug 6, 2025 8:06pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 6, 2025

Walkthrough

This update introduces a comprehensive Snipe-IT integration, adding a new app module with rich property definitions and methods for interacting with the Snipe-IT API. It implements six new actions: create hardware, get hardware, get user assets, create user, get license, and update hardware. The package version and dependencies are also updated. A utility function for safely parsing nested JSON strings is added.

Changes

Cohort / File(s) Change Summary
Snipe-IT App Core & API Methods
components/snipe_it/snipe_it.app.mjs
Adds extensive property definitions and implements all required Snipe-IT API methods for hardware, users, and licenses.
Create Hardware Action
components/snipe_it/actions/create-hardware/create-hardware.mjs
Adds action to create a new hardware asset using the app's property definitions and API methods.
Get Hardware Action
components/snipe_it/actions/get-hardware/get-hardware.mjs
Adds action to retrieve details for a specific hardware asset by its ID.
Get User Assets Action
components/snipe_it/actions/get-user-assets/get-user-assets.mjs
Adds action to fetch all assets currently assigned to a specific user.
Create User Action
components/snipe_it/actions/create-user/create-user.mjs
Adds action to create a new user with comprehensive profile information.
Get License Action
components/snipe_it/actions/get-license/get-license.mjs
Adds action to retrieve license details by license ID.
Update Hardware Action
components/snipe_it/actions/update-hardware/update-hardware.mjs
Adds action to update an existing hardware asset with partial or full information.
JSON Parsing Utility
components/snipe_it/common/utils.mjs
Adds a utility function to recursively parse nested JSON strings safely.
Package Metadata
components/snipe_it/package.json
Updates version to 0.1.0 and adds dependency on @pipedream/platform.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Action
    participant SnipeITApp
    participant SnipeITAPI

    User->>Action: Trigger action (e.g., Create Hardware)
    Action->>SnipeITApp: Call method (e.g., createHardware)
    SnipeITApp->>SnipeITAPI: Make HTTP request
    SnipeITAPI-->>SnipeITApp: Return API response
    SnipeITApp-->>Action: Return processed data
    Action-->>User: Return summary and response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Assessment against linked issues

Objective Addressed Explanation
Implement create-hardware action (17702)
Implement get-hardware action (17702)
Implement get-user-assets action (17702)
Implement create-user action (17702)
Implement get-license action (17702)
Implement update-hardware action (17702)

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes found.

Poem

In Snipe-IT fields where assets grow,
New actions hop—reviewers know!
Hardware, users, licenses too,
Rabbits code and hop right through.
With every patch and method spun,
Inventory magic—now it’s done!
🐇✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 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 4289286 and 072559b.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (9)
  • components/snipe_it/actions/create-hardware/create-hardware.mjs (1 hunks)
  • components/snipe_it/actions/create-user/create-user.mjs (1 hunks)
  • components/snipe_it/actions/get-hardware/get-hardware.mjs (1 hunks)
  • components/snipe_it/actions/get-license/get-license.mjs (1 hunks)
  • components/snipe_it/actions/get-user-assets/get-user-assets.mjs (1 hunks)
  • components/snipe_it/actions/update-hardware/update-hardware.mjs (1 hunks)
  • components/snipe_it/common/utils.mjs (1 hunks)
  • components/snipe_it/package.json (2 hunks)
  • components/snipe_it/snipe_it.app.mjs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • components/snipe_it/package.json
🚧 Files skipped from review as they are similar to previous changes (6)
  • components/snipe_it/actions/update-hardware/update-hardware.mjs
  • components/snipe_it/actions/create-user/create-user.mjs
  • components/snipe_it/actions/get-hardware/get-hardware.mjs
  • components/snipe_it/actions/create-hardware/create-hardware.mjs
  • components/snipe_it/actions/get-user-assets/get-user-assets.mjs
  • components/snipe_it/actions/get-license/get-license.mjs
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: in the salesloft api integration (components/salesloft/salesloft.app.mjs), the _makerequest method r...
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#16954
File: components/salesloft/salesloft.app.mjs:14-23
Timestamp: 2025-06-04T17:52:05.780Z
Learning: In the Salesloft API integration (components/salesloft/salesloft.app.mjs), the _makeRequest method returns response.data which directly contains arrays for list endpoints like listPeople, listCadences, listUsers, and listAccounts. The propDefinitions correctly call .map() directly on these responses without needing to destructure a nested data property.

Applied to files:

  • components/snipe_it/snipe_it.app.mjs
📚 Learning: the salesloft api list endpoints (listpeople, listcadences, listusers, listaccounts) return arrays d...
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#16954
File: components/salesloft/salesloft.app.mjs:14-23
Timestamp: 2025-06-04T17:52:05.780Z
Learning: The Salesloft API list endpoints (listPeople, listCadences, listUsers, listAccounts) return arrays directly in the response body, not wrapped in a metadata object with a nested data property. The _makeRequest method correctly returns response.data which contains the arrays that can be mapped over directly in propDefinitions.

Applied to files:

  • components/snipe_it/snipe_it.app.mjs
🧬 Code Graph Analysis (1)
components/snipe_it/snipe_it.app.mjs (6)
components/snipe_it/actions/get-hardware/get-hardware.mjs (1)
  • response (19-22)
components/snipe_it/actions/get-user-assets/get-user-assets.mjs (1)
  • response (24-27)
components/snipe_it/actions/create-hardware/create-hardware.mjs (1)
  • response (162-223)
components/snipe_it/actions/create-user/create-user.mjs (1)
  • response (179-206)
components/snipe_it/actions/update-hardware/update-hardware.mjs (1)
  • response (275-279)
components/snipe_it/actions/get-license/get-license.mjs (1)
  • response (24-27)
🔇 Additional comments (12)
components/snipe_it/common/utils.mjs (6)

1-6: LGTM on function signature and depth protection.

The function signature with a reasonable default maxDepth of 100 and the depth check to prevent infinite recursion are well implemented.


10-19: LGTM on JSON string detection and parsing logic.

The logic to detect JSON-like strings by checking for braces/brackets and safely parsing with try-catch is well implemented. The recursive call with decremented maxDepth maintains proper depth control.


21-32: LGTM on object processing logic.

The object handling correctly checks for circular references, adds the object to the seen set, and recursively processes all key-value pairs using a clean reduce pattern.


33-34: LGTM on array processing.

Array handling correctly maps through items and recursively processes each element.


42-44: LGTM on export structure.

The default export with named function property follows good module patterns and makes the function easily importable.


2-2: Fix WeakSet scoping issue for proper circular reference detection.

The WeakSet is declared outside the inner parse function, which means it persists across multiple calls to parseJson. This could lead to false positives for circular reference detection when processing different, unrelated objects across separate function calls.

Move the WeakSet declaration inside the inner parse function or reset it for each top-level call:

-const parseJson = (input, maxDepth = 100) => {
-  const seen = new WeakSet();
-  const parse = (value) => {
+const parseJson = (input, maxDepth = 100) => {
+  const parse = (value, seen = new WeakSet()) => {
     if (maxDepth <= 0) {
       return value;
     }
     if (typeof(value) === "string") {
       // Only parse if the string looks like a JSON object or array
       const trimmed = value.trim();
       if (
         (trimmed.startsWith("{") && trimmed.endsWith("}")) ||
         (trimmed.startsWith("[") && trimmed.endsWith("]"))
       ) {
         try {
-          return parseJson(JSON.parse(value), maxDepth - 1);
+          return parse(JSON.parse(value), seen);
         } catch (e) {
           return value;
         }
       }
       return value;
     } else if (typeof(value) === "object" && value !== null && !Array.isArray(value)) {
       if (seen.has(value)) {
         return value;
       }
       seen.add(value);
       return Object.entries(value)
         .reduce((acc, [
           key,
           val,
         ]) => Object.assign(acc, {
-          [key]: parse(val),
+          [key]: parse(val, seen),
         }), {});
     } else if (Array.isArray(value)) {
-      return value.map((item) => parse(item));
+      return value.map((item) => parse(item, seen));
     }
     return value;
   };

-  return parse(input);
+  return parse(input);

Likely an incorrect or invalid review comment.

components/snipe_it/snipe_it.app.mjs (6)

6-428: LGTM on comprehensive property definitions with consistent patterns.

The propDefinitions section is well-structured with:

  • Consistent typing and labeling across all properties
  • Proper use of optional flags where appropriate
  • Well-implemented async options that handle pagination
  • Good fallback handling with || [] for undefined rows
  • Descriptive labels that include helpful formatting hints (e.g., "YYYY-MM-DD format")
  • Appropriate use of secret: true for password fields

The async options pattern is consistent and robust across all dropdown properties.


430-432: LGTM on URL construction.

The getUrl method correctly constructs API URLs using the configured API URL and standard v1 API path.


433-439: LGTM on header configuration.

The getHeaders method properly sets up Bearer token authentication and appropriate content type headers for JSON API communication.


440-454: LGTM on makeRequest structure with axios integration.

The makeRequest method correctly integrates with the Pipedream axios instance and properly spreads additional arguments. The overall structure is sound aside from the error handling issue noted separately.


455-466: LGTM on HTTP convenience methods.

The post and patch methods are clean wrappers around makeRequest that properly set the HTTP method and spread additional arguments.


467-570: LGTM on comprehensive API method implementation.

The API methods section successfully implements all the operations specified in the PR objectives:

Hardware Operations:

  • createHardware - implements create-hardware objective
  • getHardware - implements get-hardware objective
  • updateHardware - implements update-hardware objective
  • listHardware - supports hardware selection in propDefinitions

User Operations:

  • createUser - implements create-user objective
  • getUserAssets - implements get-user-assets objective
  • listUsers - supports user selection in propDefinitions

License Operations:

  • getLicense - implements get-license objective
  • listLicenses - supports license selection in propDefinitions

Supporting Operations:
All the list methods for supporting entities (models, status labels, suppliers, locations, departments, companies, groups) properly support the async options in propDefinitions.

The methods follow consistent patterns:

  • Proper parameter destructuring with defaults
  • Correct HTTP method selection (GET for retrieval, POST for creation, PATCH for updates)
  • Appropriate path construction
  • Consistent argument spreading
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch snipe-it-new-components

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.
  • 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.

Support

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

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 generate unit tests to generate unit tests for 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: 5

🧹 Nitpick comments (1)
components/snipe_it/actions/get-hardware/get-hardware.mjs (1)

18-26: Consider refactoring for consistency with other actions.

The action works correctly but uses a different destructuring pattern than other actions in this integration. For consistency, consider updating to match the pattern used in get-license.mjs and get-user-assets.mjs.

  async run({ $ }) {
+   const {
+     app,
+     hardwareId,
+   } = this;
+
-   const response = await this.app.getHardware({
+   const response = await app.getHardware({
      $,
-     hardwareId: this.hardwareId,
+     hardwareId,
    });
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4ae047b and 4289286.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (8)
  • components/snipe_it/actions/create-hardware/create-hardware.mjs (1 hunks)
  • components/snipe_it/actions/create-user/create-user.mjs (1 hunks)
  • components/snipe_it/actions/get-hardware/get-hardware.mjs (1 hunks)
  • components/snipe_it/actions/get-license/get-license.mjs (1 hunks)
  • components/snipe_it/actions/get-user-assets/get-user-assets.mjs (1 hunks)
  • components/snipe_it/actions/update-hardware/update-hardware.mjs (1 hunks)
  • components/snipe_it/package.json (2 hunks)
  • components/snipe_it/snipe_it.app.mjs (1 hunks)
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: when exporting a summary message in the `run` method of an action, ensure the message is correctly f...
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12731
File: components/hackerone/actions/get-members/get-members.mjs:3-28
Timestamp: 2024-10-08T15:33:38.240Z
Learning: When exporting a summary message in the `run` method of an action, ensure the message is correctly formatted. For example, in the `hackerone-get-members` action, the correct format is `Successfully retrieved ${response.data.length} members`.

Applied to files:

  • components/snipe_it/actions/get-license/get-license.mjs
  • components/snipe_it/actions/get-hardware/get-hardware.mjs
  • components/snipe_it/actions/create-user/create-user.mjs
  • components/snipe_it/actions/create-hardware/create-hardware.mjs
  • components/snipe_it/actions/get-user-assets/get-user-assets.mjs
  • components/snipe_it/actions/update-hardware/update-hardware.mjs
📚 Learning: in `components/gainsight_px/actions/create-account/create-account.mjs`, the action name should be "c...
Learnt from: jcortes
PR: PipedreamHQ/pipedream#14467
File: components/gainsight_px/actions/create-account/create-account.mjs:4-6
Timestamp: 2024-10-30T15:24:39.294Z
Learning: In `components/gainsight_px/actions/create-account/create-account.mjs`, the action name should be "Create Account" instead of "Create Memory".

Applied to files:

  • components/snipe_it/actions/create-user/create-user.mjs
  • components/snipe_it/actions/create-hardware/create-hardware.mjs
📚 Learning: in the salesloft api integration (components/salesloft/salesloft.app.mjs), the _makerequest method r...
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#16954
File: components/salesloft/salesloft.app.mjs:14-23
Timestamp: 2025-06-04T17:52:05.780Z
Learning: In the Salesloft API integration (components/salesloft/salesloft.app.mjs), the _makeRequest method returns response.data which directly contains arrays for list endpoints like listPeople, listCadences, listUsers, and listAccounts. The propDefinitions correctly call .map() directly on these responses without needing to destructure a nested data property.

Applied to files:

  • components/snipe_it/snipe_it.app.mjs
📚 Learning: the salesloft api list endpoints (listpeople, listcadences, listusers, listaccounts) return arrays d...
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#16954
File: components/salesloft/salesloft.app.mjs:14-23
Timestamp: 2025-06-04T17:52:05.780Z
Learning: The Salesloft API list endpoints (listPeople, listCadences, listUsers, listAccounts) return arrays directly in the response body, not wrapped in a metadata object with a nested data property. The _makeRequest method correctly returns response.data which contains the arrays that can be mapped over directly in propDefinitions.

Applied to files:

  • components/snipe_it/snipe_it.app.mjs
📚 Learning: when developing pipedream components, do not add built-in node.js modules like `fs` to `package.json...
Learnt from: jcortes
PR: PipedreamHQ/pipedream#14935
File: components/sailpoint/package.json:15-18
Timestamp: 2024-12-12T19:23:09.039Z
Learning: When developing Pipedream components, do not add built-in Node.js modules like `fs` to `package.json` dependencies, as they are native modules provided by the Node.js runtime.

Applied to files:

  • components/snipe_it/package.json
🧬 Code Graph Analysis (4)
components/snipe_it/actions/get-license/get-license.mjs (1)
components/snipe_it/snipe_it.app.mjs (1)
  • response (443-447)
components/snipe_it/actions/get-hardware/get-hardware.mjs (3)
components/snipe_it/actions/get-license/get-license.mjs (1)
  • response (24-27)
components/snipe_it/actions/get-user-assets/get-user-assets.mjs (1)
  • response (24-27)
components/snipe_it/snipe_it.app.mjs (1)
  • response (443-447)
components/snipe_it/actions/create-user/create-user.mjs (1)
components/snipe_it/snipe_it.app.mjs (1)
  • response (443-447)
components/snipe_it/actions/create-hardware/create-hardware.mjs (4)
components/snipe_it/actions/get-hardware/get-hardware.mjs (1)
  • response (19-22)
components/snipe_it/actions/create-user/create-user.mjs (1)
  • response (179-206)
components/snipe_it/actions/update-hardware/update-hardware.mjs (1)
  • response (271-275)
components/snipe_it/snipe_it.app.mjs (1)
  • response (443-447)
🔇 Additional comments (10)
components/snipe_it/package.json (2)

3-3: LGTM: Appropriate version bump for new functionality.

The version increment from "0.0.1" to "0.1.0" correctly reflects the substantial addition of multiple action modules and expanded app functionality.


15-17: LGTM: Valid dependency addition.

The @pipedream/platform dependency is appropriate for Pipedream components and correctly specified with version constraint ^3.1.0.

components/snipe_it/actions/get-license/get-license.mjs (1)

1-32: LGTM: Well-structured action following best practices.

The action correctly implements the get license functionality with:

  • Proper use of propDefinitions for input validation
  • Correct async/await pattern for API calls
  • Well-formatted summary message following established conventions
  • Clear documentation reference
  • Appropriate error handling delegation to the app layer

The note about product_key vs serial field in the description is helpful for users.

components/snipe_it/actions/get-user-assets/get-user-assets.mjs (1)

1-32: LGTM: Consistent implementation with good user feedback.

The action properly implements user asset retrieval with:

  • Consistent structure matching other actions in the integration
  • Effective use of propDefinitions for input validation
  • Well-formatted summary message including asset count for user feedback
  • Clear description explaining the audit and inventory use case
  • Proper delegation of API interaction to the app layer
components/snipe_it/actions/update-hardware/update-hardware.mjs (2)

174-279: LGTM: Robust update logic with good validation.

The update implementation demonstrates several good practices:

  • Comprehensive field mapping from camelCase to snake_case
  • Conditional field inclusion to avoid sending empty values
  • Proper validation ensuring at least one field is provided for updates
  • Consistent destructuring pattern matching other actions
  • Appropriate error handling and user feedback

The data construction pattern efficiently handles optional fields and maintains API compatibility.


267-269: Good validation logic.

The check to ensure at least one field is provided prevents unnecessary API calls and provides clear user feedback for invalid operations.

components/snipe_it/actions/create-hardware/create-hardware.mjs (1)

164-217: Good use of conditional spreads for optional fields

The implementation correctly handles boolean fields by checking !== undefined to allow false values to be sent to the API. This is a good practice for boolean API parameters.

components/snipe_it/snipe_it.app.mjs (3)

11-24: Consistent pagination implementation

The pagination logic in async options functions looks correct, using limit and offset parameters. The implementation correctly calculates offset as page * 50.


233-244: Proper handling of sensitive fields

Password fields are correctly marked with secret: true to ensure they are properly masked in the UI and logs.


431-438: Well-implemented authentication and headers

The authentication setup correctly uses Bearer token authorization and appropriate content-type headers. The URL construction properly leverages the configured API URL from the auth object.

@vunguyenhung vunguyenhung merged commit 86f713b into master Aug 8, 2025
11 checks passed
@vunguyenhung vunguyenhung deleted the snipe-it-new-components branch August 8, 2025 02:50
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.

[Components] Snipe-IT

4 participants