-
Notifications
You must be signed in to change notification settings - Fork 5.5k
18138 components taiga #18378
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
18138 components taiga #18378
Conversation
- Bump version to 0.1.0 in package.json and add dependency on @pipedream/platform. - Introduce new actions for creating, updating, and deleting issues, tasks, and user stories. - Add sources for tracking changes and deletions of issues and tasks. - Implement utility functions for parsing and cleaning objects in common/utils.mjs. - Enhance prop definitions for better integration with Taiga API.
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
WalkthroughIntroduces a full Taiga integration: adds API client and propDefinitions, utilities, and multiple actions for creating, reading, updating, and deleting issues, tasks, and user stories. Implements instant webhook sources (new/changed/deleted, including status changes) with a shared base handling webhook creation, secret validation, and event emission. Updates package metadata. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Action as Pipedream Action
participant TaigaApp as Taiga App Client
participant TaigaAPI as Taiga API
rect rgba(225,245,254,0.6)
note right of User: Create/Update flow
User->>Action: Configure props (project, fields)
Action->>TaigaApp: (optional) get* (e.g., getIssue/getTask) for version
TaigaApp->>TaigaAPI: GET resource
TaigaAPI-->>TaigaApp: 200 { resource with version }
end
rect rgba(232,245,233,0.6)
Action->>TaigaApp: create*/update*({ mapped payload })
TaigaApp->>TaigaAPI: POST/PATCH with payload
TaigaAPI-->>TaigaApp: 200 { id, ... }
TaigaApp-->>Action: Response
Action-->>User: $summary (Created/Updated: id)
end
sequenceDiagram
autonumber
participant Source as Webhook Source
participant Base as Common Base
participant TaigaApp as Taiga App Client
participant TaigaAPI as Taiga API
participant PD as Pipedream Runtime
rect rgba(255,249,196,0.6)
note right of Source: Activation
Source->>Base: activate()
Base->>Base: generate secretKey
Base->>TaigaApp: createHook({ url, project, key, name })
TaigaApp->>TaigaAPI: POST /webhooks
TaigaAPI-->>TaigaApp: 201 { id }
TaigaApp-->>Base: hook id
Base->>Base: persist webhookId + secretKey
end
rect rgba(252,228,236,0.6)
note right of PD: Event handling
TaigaAPI-->>Source: POST webhook (headers, bodyRaw, body)
Source->>Base: run({ headers, bodyRaw, body })
Base->>Base: validate HMAC-SHA1 signature
alt filterEvent(body) === true
Base->>PD: $.emit({ id, summary, ts, body })
else
Base-->>PD: ignore
end
end
rect rgba(224,242,241,0.6)
note right of Source: Deactivation
Source->>Base: deactivate()
Base->>TaigaApp: deleteHook(webhookId)
TaigaApp->>TaigaAPI: DELETE /webhooks/{id}
TaigaAPI-->>TaigaApp: 204
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60–90 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. 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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 16
🧹 Nitpick comments (30)
components/taiga/sources/changed-task-status-instant/test-event.mjs (1)
123-126: Align status slug with name.User story status shows name "In progress" but slug "new". Suggest slug "in-progress".
- "slug": "new", + "slug": "in-progress",components/taiga/sources/changed-task-instant/test-event.mjs (1)
123-126: Align status slug with name.User story status shows name "In progress" but slug "new". Suggest slug "in-progress".
- "slug": "new", + "slug": "in-progress",components/taiga/sources/new-issue-instant/test-event.mjs (1)
36-41: Fix owner permalink/username mismatch.owner.permalink ends with /username but owner.username is "pipedreamsage". Align for clarity (unless intentionally different).
- "username": "pipedreamsage", + "username": "username",components/taiga/sources/deleted-issue-instant/test-event.mjs (1)
14-15: Normalize custom_attributes_values to an object.Other samples use {}. Using {} avoids null checks in consumers.
- "custom_attributes_values": null, + "custom_attributes_values": {},components/taiga/common/utils.mjs (1)
1-3: Don’t treat 0/false as “no value” in parseObject.The
!objguard collapses0andfalsetoundefined. Limit this tonull | undefined | "". Also safely trim beforeJSON.parsewithout changing the fallback.export const parseObject = (obj) => { - if (!obj) return undefined; + if (obj === null || obj === undefined || obj === "") return undefined; ... - if (typeof obj === "string") { - try { - return JSON.parse(obj); - } catch (e) { - return obj; - } - } + if (typeof obj === "string") { + const s = obj.trim(); + try { + return JSON.parse(s); + } catch (e) { + return obj; + } + }Also applies to: 16-21
components/taiga/sources/new-task-instant/test-event.mjs (1)
6-6: Nit: normalize profile permalink.Use a consistent username in the sample to avoid confusion when testing.
- "permalink": "https://tree.taiga.io/profile/yourprofile", + "permalink": "https://tree.taiga.io/profile/username",components/taiga/actions/delete-issue/delete-issue.mjs (1)
27-35: Return a useful fallback on 204 No Content responses.Taiga delete endpoints may return 204; bubble up a stable object.
const response = await this.taiga.deleteIssue({ $, issueId: this.issueId, }); $.export("$summary", `Deleted issue: ${this.issueId}`); - return response; + return response ?? { success: true, issueId: this.issueId };components/taiga/sources/new-task-instant/new-task-instant.mjs (1)
14-19: More informative summary for users.Include
refandsubjectwhen present.- getSummary(body) { - return `New Task: ${body.data.id}`; - }, + getSummary(body) { + const d = body?.data ?? {}; + const id = d.ref ?? d.id; + const subject = d.subject ? ` — ${d.subject}` : ""; + return `New Task: ${id}${subject}`; + },components/taiga/sources/deleted-issue-instant/deleted-issue-instant.mjs (1)
8-8: Grammar nit in description.Use “an issue”.
- description: "Emit new event when a issue is deleted in the selected project. [See the documentation](https://docs.taiga.io/api.html#webhooks-create)", + description: "Emit new event when an issue is deleted in the selected project. [See the documentation](https://docs.taiga.io/api.html#webhooks-create)",components/taiga/actions/delete-task/delete-task.mjs (1)
27-35: Return a useful fallback on 204 No Content responses.Mirror the delete‑issue suggestion for consistency.
const response = await this.taiga.deleteTask({ $, taskId: this.taskId, }); $.export("$summary", `Deleted task: ${this.taskId}`); - return response; + return response ?? { success: true, taskId: this.taskId };components/taiga/actions/get-userstory/get-userstory.mjs (1)
27-35: Consistency: use API response ID in summary (like get‑issue).- $.export("$summary", `Retrieved user story: ${this.userStoryId}`); - return response; + $.export("$summary", `Retrieved user story: ${response.id}`); + return response;components/taiga/actions/update-project/update-project.mjs (2)
1-1: ImportcleanObjto avoid sending undefineds.Matches pattern used by other update actions.
-import { buildProjectData } from "../../common/utils.mjs"; +import { buildProjectData, cleanObj } from "../../common/utils.mjs";
42-50: Restrict Owner options to project members.Prevents selecting a non‑member as owner.
- owner: { - propDefinition: [ - taiga, - "userId", - ], + owner: { + propDefinition: [ + taiga, + "userId", + ({ projectId }) => ({ projectId }), + ], label: "Owner", description: "User to set as project owner", optional: true, },components/taiga/sources/changed-issue-status-instant/changed-issue-status-instant.mjs (2)
17-19: Harden filter against missing fields.Avoid potential TypeError if
changeordiffis absent.- filterEvent(body) { - return body.type === "issue" && body.action === "change" && body.change.diff.status; - }, + filterEvent(body) { + return body.type === "issue" + && body.action === "change" + && body.change?.diff?.status != null; + },
14-16: Optional: richer summary.If
statusdiff is[old, next], include the new status in the summary for better UX.- getSummary(body) { - return `Changed Issue Status: ${body.data.id}`; - }, + getSummary(body) { + const next = Array.isArray(body.change?.diff?.status) ? body.change.diff.status[1] : undefined; + return `Changed Issue Status: ${body.data.id}${next != null ? ` → ${next}` : ""}`; + },components/taiga/sources/changed-task-instant/changed-task-instant.mjs (1)
17-19: Harden filter against missing fields.Use optional chaining so unexpected payloads don’t throw.
- filterEvent(body) { - return body.type === "task" && body.action === "change" && !body.change.diff.status; - }, + filterEvent(body) { + return body.type === "task" + && body.action === "change" + && !(body.change?.diff?.status != null); + },components/taiga/sources/common/base.mjs (2)
21-28: Add getters/setters for the webhook secret.methods: { _setWebhookId(id) { this.db.set("webhookId", id); }, _getWebhookId() { return this.db.get("webhookId"); }, + _setWebhookSecret(secret) { + this.db.set("webhookSecret", secret); + }, + _getWebhookSecret() { + return this.db.get("webhookSecret"); + }, },
41-44: Guard deactivate when no webhook is registered.Prevents unnecessary API calls / errors.
async deactivate() { const webhookId = this._getWebhookId(); - await this.taiga.deleteHook(webhookId); + if (webhookId) { + await this.taiga.deleteHook(webhookId); + } },components/taiga/actions/create-task/create-task.mjs (2)
1-1: Also importcleanObjfor consistency with other actions.-import { parseObject } from "../../common/utils.mjs"; +import { parseObject, cleanObj } from "../../common/utils.mjs";
120-136: Clean the payload before sending.Avoid sending undefined fields; matches the pattern in update actions.
- const response = await this.taiga.createTask({ + const response = await this.taiga.createTask({ $, - data: { + data: cleanObj({ subject: this.subject, description: this.description, project: this.projectId, status: this.status, assigned_to: this.assignedTo, user_story: this.userStoryId, tags: parseObject(this.tags), is_blocked: this.isBlocked, milestone: this.milestone, user_story_order: this.usOrder, taskboard_order: this.taskboardOrder, watchers: parseObject(this.watchers), - }, + }), });components/taiga/sources/changed-task-status-instant/changed-task-status-instant.mjs (1)
14-16: Make summary resilient to partial payloadsGuard against missing
dataorid.- getSummary(body) { - return `Changed Task Status: ${body.data.id}`; - }, + getSummary(body) { + const id = body?.data?.id ?? body?.id ?? "unknown"; + return `Changed Task Status: ${id}`; + },components/taiga/sources/deleted-task-instant/deleted-task-instant.mjs (2)
17-19: Minor: defensive checks on event filterNot strictly required, but keeps the source robust if payloads vary.
- filterEvent(body) { - return body.type === "task" && body.action === "delete"; - }, + filterEvent(body) { + return body?.type === "task" && body?.action === "delete"; + },
14-16: Minor: resilient summaryAvoids errors when
datais missing.- getSummary(body) { - return `Deleted Task: ${body.data.id}`; - }, + getSummary(body) { + const id = body?.data?.id ?? body?.id ?? "unknown"; + return `Deleted Task: ${id}`; + },components/taiga/actions/update-issue/update-issue.mjs (1)
154-158: Normalizetagsandwatcherslike in create actionsPrevents API errors when inputs are JSON strings or arrays of string IDs.
- tags: this.tags, + tags: parseObject(this.tags), blocked_note: this.blockedNote, is_blocked: this.isBlocked, milestone: this.milestone, - watchers: this.watchers, + watchers: parseObject(this.watchers),components/taiga/actions/delete-userstory/delete-userstory.mjs (1)
33-34: Prefer response ID in summaryUses the actual deleted entity ID if returned; falls back to input.
- $.export("$summary", `Deleted user story: ${this.userStoryId}`); + $.export("$summary", `Deleted user story: ${response?.id ?? this.userStoryId}`);components/taiga/actions/create-userstory/create-userstory.mjs (1)
154-154: Optional: coerce watcher IDs to numbersIf the prop returns string IDs, coercing avoids type issues server-side. Skip if the API accepts strings.
- watchers: parseObject(this.watchers), + watchers: (() => { + const w = parseObject(this.watchers); + return Array.isArray(w) && w.every((v) => /^\d+$/.test(String(v))) ? w.map((v) => Number(v)) : w; + })(),components/taiga/actions/create-issue/create-issue.mjs (1)
140-144: Consider parsingtagsandwatchersconsistently with other actionsThe
tagsandwatchersfields are being parsed usingparseObject(), but in the update actions (e.g.,update-issue,update-task,update-userstory), these fields are passed directly without parsing. This inconsistency could lead to different behaviors between create and update operations.Consider applying
parseObject()consistently across all actions or document why the difference is necessary. If the Taiga API accepts both parsed and unparsed formats, consider standardizing on one approach:- tags: parseObject(this.tags), + tags: this.tags, blocked_note: this.blockedNote, is_blocked: this.isBlocked, milestone: this.milestone, - watchers: parseObject(this.watchers), + watchers: this.watchers,Or alternatively, update the other actions to also use
parseObject()for consistency.components/taiga/sources/changed-issue-instant/changed-issue-instant.mjs (1)
8-8: Fix typo in descriptionThere's a grammatical error in the description.
- description: "Emit new event when a issue is updated in the selected project. [See the documentation](https://docs.taiga.io/api.html#webhooks-create)", + description: "Emit new event when an issue is updated in the selected project. [See the documentation](https://docs.taiga.io/api.html#webhooks-create)",components/taiga/taiga.app.mjs (2)
393-394: Improve example format for points fieldThe example JSON in the description uses escaped quotes which could confuse users when entering the value.
Provide a clearer example format:
- description: "A dictionary of points. The key is the id of the [role](https://docs.taiga.io/api.html#roles-list) and the value is the id of the [points](https://docs.taiga.io/api.html#points-list). Format: `{\"10469741\": 20817870, \"10469742\": 20817871, \"10469743\": 20817872, \"10469744\": 20817873}`", + description: "A dictionary of points. The key is the id of the [role](https://docs.taiga.io/api.html#roles-list) and the value is the id of the [points](https://docs.taiga.io/api.html#points-list). Example: `{\"10469741\": 20817870, \"10469742\": 20817871}`. When entering in the UI, use: {\"roleId\": pointId}",
18-20: Consider adding error details to improve debuggingThe catch blocks silently fall back to empty arrays, which might make debugging difficult for users.
Consider logging the error for debugging purposes while still returning the empty array:
} catch (error) { + console.error(`Failed to fetch projects: ${error.message}`); projects = []; }This pattern should be applied to all similar catch blocks throughout the file.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (32)
components/taiga/actions/create-issue/create-issue.mjs(1 hunks)components/taiga/actions/create-task/create-task.mjs(1 hunks)components/taiga/actions/create-userstory/create-userstory.mjs(1 hunks)components/taiga/actions/delete-issue/delete-issue.mjs(1 hunks)components/taiga/actions/delete-task/delete-task.mjs(1 hunks)components/taiga/actions/delete-userstory/delete-userstory.mjs(1 hunks)components/taiga/actions/get-issue/get-issue.mjs(1 hunks)components/taiga/actions/get-userstory/get-userstory.mjs(1 hunks)components/taiga/actions/update-issue/update-issue.mjs(1 hunks)components/taiga/actions/update-project/update-project.mjs(1 hunks)components/taiga/actions/update-task/update-task.mjs(1 hunks)components/taiga/actions/update-userstory/update-userstory.mjs(1 hunks)components/taiga/common/utils.mjs(1 hunks)components/taiga/package.json(2 hunks)components/taiga/sources/changed-issue-instant/changed-issue-instant.mjs(1 hunks)components/taiga/sources/changed-issue-instant/test-event.mjs(1 hunks)components/taiga/sources/changed-issue-status-instant/changed-issue-status-instant.mjs(1 hunks)components/taiga/sources/changed-issue-status-instant/test-event.mjs(1 hunks)components/taiga/sources/changed-task-instant/changed-task-instant.mjs(1 hunks)components/taiga/sources/changed-task-instant/test-event.mjs(1 hunks)components/taiga/sources/changed-task-status-instant/changed-task-status-instant.mjs(1 hunks)components/taiga/sources/changed-task-status-instant/test-event.mjs(1 hunks)components/taiga/sources/common/base.mjs(1 hunks)components/taiga/sources/deleted-issue-instant/deleted-issue-instant.mjs(1 hunks)components/taiga/sources/deleted-issue-instant/test-event.mjs(1 hunks)components/taiga/sources/deleted-task-instant/deleted-task-instant.mjs(1 hunks)components/taiga/sources/deleted-task-instant/test-event.mjs(1 hunks)components/taiga/sources/new-issue-instant/new-issue-instant.mjs(1 hunks)components/taiga/sources/new-issue-instant/test-event.mjs(1 hunks)components/taiga/sources/new-task-instant/new-task-instant.mjs(1 hunks)components/taiga/sources/new-task-instant/test-event.mjs(1 hunks)components/taiga/taiga.app.mjs(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2024-12-12T19:23:09.039Z
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/taiga/package.json
📚 Learning: 2024-10-08T15:33:38.240Z
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Applied to files:
components/taiga/sources/common/base.mjs
🧬 Code graph analysis (13)
components/taiga/common/utils.mjs (2)
components/akeneo/akeneo.app.mjs (1)
JSON(99-110)components/openai/actions/create-transcription/create-transcription.mjs (1)
v(110-112)
components/taiga/actions/update-issue/update-issue.mjs (5)
components/taiga/actions/create-issue/create-issue.mjs (1)
response(129-146)components/taiga/actions/get-issue/get-issue.mjs (1)
response(28-31)components/taiga/actions/update-task/update-task.mjs (1)
response(133-150)components/taiga/actions/update-userstory/update-userstory.mjs (1)
response(150-168)components/taiga/common/utils.mjs (2)
cleanObj(26-41)cleanObj(26-41)
components/taiga/actions/update-task/update-task.mjs (4)
components/taiga/actions/create-task/create-task.mjs (1)
response(120-136)components/taiga/actions/update-issue/update-issue.mjs (1)
response(142-161)components/taiga/actions/update-userstory/update-userstory.mjs (1)
response(150-168)components/taiga/common/utils.mjs (2)
cleanObj(26-41)cleanObj(26-41)
components/taiga/actions/delete-task/delete-task.mjs (4)
components/taiga/actions/delete-issue/delete-issue.mjs (1)
response(28-31)components/taiga/actions/delete-userstory/delete-userstory.mjs (1)
response(28-31)components/taiga/actions/get-issue/get-issue.mjs (1)
response(28-31)components/taiga/actions/get-userstory/get-userstory.mjs (1)
response(28-31)
components/taiga/actions/update-userstory/update-userstory.mjs (5)
components/taiga/actions/create-userstory/create-userstory.mjs (1)
response(137-156)components/taiga/actions/get-userstory/get-userstory.mjs (1)
response(28-31)components/taiga/actions/update-issue/update-issue.mjs (1)
response(142-161)components/taiga/actions/update-task/update-task.mjs (1)
response(133-150)components/taiga/common/utils.mjs (2)
cleanObj(26-41)cleanObj(26-41)
components/taiga/actions/get-userstory/get-userstory.mjs (3)
components/taiga/actions/delete-issue/delete-issue.mjs (1)
response(28-31)components/taiga/actions/delete-userstory/delete-userstory.mjs (1)
response(28-31)components/taiga/actions/get-issue/get-issue.mjs (1)
response(28-31)
components/taiga/actions/get-issue/get-issue.mjs (2)
components/taiga/actions/delete-issue/delete-issue.mjs (1)
response(28-31)components/taiga/actions/get-userstory/get-userstory.mjs (1)
response(28-31)
components/taiga/actions/delete-issue/delete-issue.mjs (3)
components/taiga/actions/delete-task/delete-task.mjs (1)
response(28-31)components/taiga/actions/delete-userstory/delete-userstory.mjs (1)
response(28-31)components/taiga/actions/get-issue/get-issue.mjs (1)
response(28-31)
components/taiga/actions/create-task/create-task.mjs (1)
components/taiga/common/utils.mjs (2)
parseObject(1-24)parseObject(1-24)
components/taiga/actions/create-issue/create-issue.mjs (2)
components/taiga/actions/create-task/create-task.mjs (1)
response(120-136)components/taiga/common/utils.mjs (2)
parseObject(1-24)parseObject(1-24)
components/taiga/actions/delete-userstory/delete-userstory.mjs (3)
components/taiga/actions/delete-issue/delete-issue.mjs (1)
response(28-31)components/taiga/actions/delete-task/delete-task.mjs (1)
response(28-31)components/taiga/actions/get-userstory/get-userstory.mjs (1)
response(28-31)
components/taiga/actions/update-project/update-project.mjs (3)
components/taiga/actions/update-issue/update-issue.mjs (1)
response(142-161)components/taiga/actions/update-task/update-task.mjs (1)
response(133-150)components/taiga/actions/update-userstory/update-userstory.mjs (1)
response(150-168)
components/taiga/actions/create-userstory/create-userstory.mjs (2)
components/taiga/actions/create-issue/create-issue.mjs (1)
response(129-146)components/taiga/common/utils.mjs (2)
parseObject(1-24)parseObject(1-24)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Publish TypeScript components
- GitHub Check: Verify TypeScript components
- GitHub Check: Lint Code Base
- GitHub Check: pnpm publish
🔇 Additional comments (10)
components/taiga/package.json (1)
3-3: LGTM: version bump and platform dependency.Looks good. Please confirm all new sources/actions rely only on @pipedream/platform ≥3.1.0 APIs; bump if any newer helpers are used.
Also applies to: 15-16
components/taiga/sources/changed-issue-status-instant/test-event.mjs (1)
1-81: LGTM: status-change diff matches data.status.Sample structure and fields look consistent.
components/taiga/sources/changed-issue-instant/test-event.mjs (1)
1-81: LGTM: change envelope and diff are consistent.No issues spotted.
components/taiga/sources/new-task-instant/test-event.mjs (1)
1-185: Sample payload looks comprehensive and matches the source filter (type=task, action=create).LGTM.
components/taiga/actions/get-issue/get-issue.mjs (1)
3-36: Straightforward get action; pattern matches the rest of the suite.LGTM.
components/taiga/sources/new-issue-instant/new-issue-instant.mjs (1)
4-22: LGTM.Pattern matches other sources; filter and summary look correct.
components/taiga/actions/create-task/create-task.mjs (1)
105-117: Multi-select forwatchersverified — no change required.userId propDefinition returns id as the option value (components/taiga/taiga.app.mjs); actions override to type "string[]" and pass watchers via parseObject(this.watchers) (components/taiga/actions/*); components/taiga/common/utils.mjs parseObject normalizes stringified numbers to numbers — the current implementation will send an array of IDs to the API.
components/taiga/actions/create-userstory/create-userstory.mjs (1)
8-9: LGTMAction shape, propDefinitions, and payload mapping look consistent with the rest of the Taiga components.
components/taiga/actions/update-issue/update-issue.mjs (1)
124-136: ```shell
#!/bin/bash
set -euo pipefail
echo "Repo root: $(pwd)"
echo "--- Searching for propDefinition occurrences (3 lines context) ---"
rg -n -C3 --hidden --no-ignore -S 'propDefinition' || true
echo "--- Searching for propDefinition.*userId ---"
rg -n -C3 --hidden --no-ignore -S 'propDefinition.*userId' || true
echo "--- Searching for "userId" and word-boundary userId ---"
rg -n -C3 --hidden --no-ignore -S '"userId"|\buserId\b' || true
echo "--- Searching for watchers occurrences ---"
rg -n -C3 --hidden --no-ignore -S '\bwatchers\b' || true
echo "--- Searching for taiga symbol occurrences ---"
rg -n -C3 --hidden --no-ignore -S '\btaiga\b' || true
echo "--- If components/taiga exists, listing and searching inside it ---"
if [ -d components/taiga ]; then
ls -la components/taiga || true
rg -n -C3 --hidden --no-ignore -S 'userId|propDefinition|propDefinitions|taiga' components/taiga || true
else
echo "components/taiga not found"
fi</blockquote></details> <details> <summary>components/taiga/taiga.app.mjs (1)</summary><blockquote> `468-480`: **Member filter is a default (overridable) — document or make it explicit** The code sets params.member = me.id but then spreads ...params, so callers can override member by passing params.member; Taiga's /projects endpoint supports the member filter. Either document this default behavior or add an explicit option (e.g., includeMember = true) and only set params.member when enabled. File: components/taiga/taiga.app.mjs Lines: 468-480async listProjects({ params, ...opts }) { const me = await this.getMe(); return await this._makeRequest({ path: "/projects", params: { member: me.id, ...params, }, ...opts, }); },> Likely an incorrect or invalid review comment. </blockquote></details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
components/taiga/sources/changed-issue-status-instant/changed-issue-status-instant.mjs
Outdated
Show resolved
Hide resolved
components/taiga/sources/changed-task-status-instant/changed-task-status-instant.mjs
Show resolved
Hide resolved
- Added parseObject utility for tags, watchers, and points in update-issue, update-task, and update-userstory actions. - Removed the update-project action as it is no longer needed. - Enhanced base source to include secret key validation for webhook security.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (5)
components/taiga/actions/update-issue/update-issue.mjs (2)
1-3: Resolved: tags/watchers normalization now consistentImporting and using
parseObjectaligns update with create; normalization looks good.
147-162: Removeprojectfrom PATCH payload to avoid unintended movesTaiga PATCH should include only changed fields (+
version). Sendingprojectcan move the issue or be rejected.File: components/taiga/actions/update-issue/update-issue.mjs — lines 147–162
data: cleanObj({ version: issue.version, subject: this.subject, description: this.description, priority: this.priority, severity: this.severity, status: this.status, type: this.type, assigned_to: this.assignedTo, tags: parseObject(this.tags), blocked_note: this.blockedNote, is_blocked: this.isBlocked, milestone: this.milestone, watchers: parseObject(this.watchers), - project: this.projectId, }),components/taiga/sources/common/base.mjs (3)
76-81: Use a stable dedupe id; avoid Date.now() in the id pathFalling back to
Date.now()in the id breaks dedupe on retries. Hash the raw body whenbody.idis absent and use that as the id.- const ts = body.created || Date.now(); - this.$emit(body, { - id: `${body.id}-${ts}`, + const ts = body.created ?? Date.now(); + const stableId = body.id || crypto.createHash("sha1").update(bodyRaw).digest("hex"); + this.$emit(body, { + id: stableId, summary: this.getSummary(body), ts, });
73-75: Always respond 200 on success; gate all processing behind verificationWithout an explicit 200, requests can hang with
customResponse: true. Also ensure nothing runs when verification fails.- if (!this.filterEvent(body)) return; - this.validateSecretKey(headers, bodyRaw); + if (!this.validateSecretKey(headers, bodyRaw)) return; + await this.http.respond({ status: 200 }); + if (!this.filterEvent(body)) return;
37-49: Block unauthenticated events and compare signatures in constant timeCurrently, failed verification still proceeds (run() doesn’t early return) and comparison uses
===. Handle missing secret/header, use timing‑safe compare, and return a boolean so callers can gate execution.- validateSecretKey(headers, bodyRaw) { - const secretKey = this._getSecretKey(); - const signature = headers["x-taiga-webhook-signature"]; - const hmac = crypto.createHmac("sha1", secretKey); - hmac.update(bodyRaw); - const signedMessage = hmac.digest("hex"); - - if (signature !== signedMessage) { - return this.http.respond({ - status: 401, - }); - } - }, + validateSecretKey(headers, bodyRaw) { + const secretKey = this._getSecretKey(); + const signatureHex = headers["x-taiga-webhook-signature"] || headers["X-TAIGA-WEBHOOK-SIGNATURE"]; + if (!secretKey || !signatureHex) { + this.http.respond({ status: 401 }); + return false; + } + const mac = crypto.createHmac("sha1", secretKey).update(bodyRaw).digest(); + let sigBuf; + try { + sigBuf = Buffer.from(signatureHex, "hex"); + } catch { + this.http.respond({ status: 401 }); + return false; + } + if (sigBuf.length !== mac.length || !crypto.timingSafeEqual(mac, sigBuf)) { + this.http.respond({ status: 401 }); + return false; + } + return true; + },
🧹 Nitpick comments (4)
components/taiga/actions/update-issue/update-issue.mjs (1)
141-143: Pass$togetIssuefor consistency and loggingOther actions include
$in read calls; do the same here.- const issue = await this.taiga.getIssue({ - issueId: this.issueId, - }); + const issue = await this.taiga.getIssue({ + $, + issueId: this.issueId, + });components/taiga/sources/common/base.mjs (3)
53-53: Add runtime‑compatible fallback forrandomUUIDMinor portability improvement for older Node environments.
- const secretKey = crypto.randomUUID(); + const secretKey = crypto.randomUUID?.() ?? crypto.randomBytes(16).toString("hex");
66-68: Guard deactivation when no webhookId is storedAvoids a spurious API call when the hook was never created.
- const webhookId = this._getWebhookId(); - await this.taiga.deleteHook(webhookId); + const webhookId = this._getWebhookId(); + if (!webhookId) return; + await this.taiga.deleteHook(webhookId);
1-1: Prefernode:cryptospecifierTiny nit for clarity that this is a Node built‑in.
-import crypto from "crypto"; +import crypto from "node:crypto";
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
components/taiga/actions/update-issue/update-issue.mjs(1 hunks)components/taiga/actions/update-task/update-task.mjs(1 hunks)components/taiga/actions/update-userstory/update-userstory.mjs(1 hunks)components/taiga/sources/changed-issue-instant/changed-issue-instant.mjs(1 hunks)components/taiga/sources/changed-issue-status-instant/changed-issue-status-instant.mjs(1 hunks)components/taiga/sources/common/base.mjs(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- components/taiga/sources/changed-issue-status-instant/changed-issue-status-instant.mjs
- components/taiga/actions/update-task/update-task.mjs
- components/taiga/actions/update-userstory/update-userstory.mjs
- components/taiga/sources/changed-issue-instant/changed-issue-instant.mjs
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2024-10-10T19:18:27.998Z
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#14265
File: components/the_magic_drip/sources/common.mjs:35-43
Timestamp: 2024-10-10T19:18:27.998Z
Learning: In `components/the_magic_drip/sources/common.mjs`, when processing items in `getAndProcessData`, `savedIds` is intentionally updated with IDs of both emitted and non-emitted items to avoid emitting retroactive events upon first deployment and ensure only new events are emitted as they occur.
Applied to files:
components/taiga/sources/common/base.mjs
📚 Learning: 2024-10-08T15:33:38.240Z
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Applied to files:
components/taiga/sources/common/base.mjs
🧬 Code graph analysis (1)
components/taiga/actions/update-issue/update-issue.mjs (5)
components/taiga/actions/update-task/update-task.mjs (1)
response(135-152)components/taiga/actions/update-userstory/update-userstory.mjs (1)
response(152-170)components/taiga/actions/create-issue/create-issue.mjs (1)
response(129-146)components/taiga/actions/get-issue/get-issue.mjs (1)
response(28-31)components/taiga/common/utils.mjs (4)
cleanObj(26-41)cleanObj(26-41)parseObject(1-24)parseObject(1-24)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Verify TypeScript components
- GitHub Check: Publish TypeScript components
- GitHub Check: Lint Code Base
- GitHub Check: pnpm publish
🔇 Additional comments (1)
components/taiga/sources/common/base.mjs (1)
52-64: Secret persistence + use during activation: goodYou now persist the webhook secret and pass it as
keyon creation. This enables proper verification. LGTM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @luancazarine lgtm! Ready for QA!
* Update Taiga component with new actions and sources - Bump version to 0.1.0 in package.json and add dependency on @pipedream/platform. - Introduce new actions for creating, updating, and deleting issues, tasks, and user stories. - Add sources for tracking changes and deletions of issues and tasks. - Implement utility functions for parsing and cleaning objects in common/utils.mjs. - Enhance prop definitions for better integration with Taiga API. * pnpm update * Refactor Taiga actions to utilize parseObject utility - Added parseObject utility for tags, watchers, and points in update-issue, update-task, and update-userstory actions. - Removed the update-project action as it is no longer needed. - Enhanced base source to include secret key validation for webhook security.
* Leonardo AI components * added unzoom image action * fixing link errors * more lint fixes * Merging pull request #18359 * fix: pagination prop and params struct * fix: no need for paginate here * chore: update version * chore: cleanup * chore: update package * feat: allow raw response * chore: bump package * fix: buffer response instead * Update components/google_drive/actions/download-file/download-file.mjs Co-authored-by: Jorge Cortes <[email protected]> * versions * pnpm-lock.yaml * pnpm-lock.yaml * pnpm-lock.yaml * feat: add content selector * chore: bump package * fix: comments * chore: bump versions * chore: fix versions * fixes: QA fixes * feat: add cursor to req * package.json --------- Co-authored-by: joao <[email protected]> Co-authored-by: joaocoform <[email protected]> Co-authored-by: Jorge Cortes <[email protected]> Co-authored-by: Michelle Bergeron <[email protected]> Co-authored-by: Luan Cazarine <[email protected]> * Merging pull request #18361 * update siteId prop * pnpm-lock.yaml * package.json version * Google Sheets - update row refresh fields (#18369) * change prop order and refresh fields * bump package.json * Pipedrive - fix app name (#18370) * use pipedriveApp instead of app * bump package.json * Pipedrive - pipelineId integer (#18372) * pipelineId - integer * bump versions * Adding app scaffolding for lightspeed_ecom_c_series * Adding app scaffolding for financial_data * Adding app scaffolding for microsoft_authenticator * Merging pull request #18345 * updates * versions * versions * Merging pull request #18368 * updates * remove console.log * versions * Coinbase Developer Platform - New Wallet Event (#18342) * new component * pnpm-lock.yaml * updates * updates * Hubspot - update search-crm (#18360) * update search-crm * limit results to one page * update version * package.json version * Merging pull request #18347 * widget props * fix version * Adding app scaffolding for rundeck * Merging pull request #18378 * Update Taiga component with new actions and sources - Bump version to 0.1.0 in package.json and add dependency on @pipedream/platform. - Introduce new actions for creating, updating, and deleting issues, tasks, and user stories. - Add sources for tracking changes and deletions of issues and tasks. - Implement utility functions for parsing and cleaning objects in common/utils.mjs. - Enhance prop definitions for better integration with Taiga API. * pnpm update * Refactor Taiga actions to utilize parseObject utility - Added parseObject utility for tags, watchers, and points in update-issue, update-task, and update-userstory actions. - Removed the update-project action as it is no longer needed. - Enhanced base source to include secret key validation for webhook security. * Merging pull request #18382 * add testSources prop * pnpm-lock.yaml * fix * Merging pull request #18323 * Added actions * Added actions * Added actions * Merging pull request #18377 * Added actions * Update components/weaviate/actions/create-class/create-class.mjs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Luan Cazarine <[email protected]> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Merging pull request #18376 * Adding app scaffolding for etrusted * Adding app scaffolding for intelliflo_office * Adding app scaffolding for thoughtspot * Adding app scaffolding for kordiam * Adding app scaffolding for ticketsauce * trustpilot fixes (#18152) * trustpilot fixes * more fixes * update versions * more version updates * fixes * Bump all Trustpilot actions to version 0.1.0 Major improvements and API updates across all actions: - Enhanced private API support with proper authentication - Improved parameter handling and validation - Better error handling and response structures - Added new conversation flow for product reviews - Fixed endpoint URLs to match latest API documentation - Streamlined request/response processing 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * up version and clean up sources * merge * fix business ID * delete temp action * Update components/trustpilot/sources/new-product-reviews/new-product-reviews.mjs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update components/trustpilot/sources/new-product-reviews/new-product-reviews.mjs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update components/trustpilot/sources/new-product-reviews/new-product-reviews.mjs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update components/trustpilot/sources/new-service-reviews/new-service-reviews.mjs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * comments * Pagination * fixes * comments * missed some `$`'s * unduplicated * more fixes * final comments * more comments * . --------- Co-authored-by: Claude <[email protected]> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Adding app scaffolding for peekalink * 18314 twilio (#18350) * Update Twilio component versions and dependencies - Update Twilio Send Message action adding detailed description for 'from' prop and refactoring phone number validation logic. - Incremented action versions for several Twilio actions. * pnpm update * Updating LinkedIn API version (#18399) * Merging pull request #18394 * Databricks API - Jobs action components (#18371) * Notion property building improvements (#18381) * validate property types * versions * Google Business - add debug log (#18407) * add debug log * bump versions * Notion API Key - update @pipedream/notion version (#18409) * update @pipedream/notion dependency version * pnpm-lock.yaml * Adding app scaffolding for reduct_video * Adding app scaffolding for shopware * Adding app scaffolding for instamojo * Hubspot - bug fix to sources w/ property changes (#18379) * updates * versions * Google sheets type fix (#18411) * Fixing worksheetId prop type from string to integer * Version bumps --------- Co-authored-by: Leo Vu <[email protected]> * Merging pull request #18393 * new components * remove console.log * versions * update * Merging pull request #18408 * 403 error message * versions * update * Merging pull request #18419 * Changes per PR Review * Removes leonardo_ai_actions.mdc not indented for merging * synced lockfile after install * fully lock form-data for leonardo_ai * conflict solving * lint fixes * Chipped down Readme, implemented async options in gen motion --------- Co-authored-by: jocarino <[email protected]> Co-authored-by: joao <[email protected]> Co-authored-by: joaocoform <[email protected]> Co-authored-by: Jorge Cortes <[email protected]> Co-authored-by: Michelle Bergeron <[email protected]> Co-authored-by: Luan Cazarine <[email protected]> Co-authored-by: michelle0927 <[email protected]> Co-authored-by: Andrew Chuang <[email protected]> Co-authored-by: danhsiung <[email protected]> Co-authored-by: Lucas Caresia <[email protected]> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Job <[email protected]> Co-authored-by: Claude <[email protected]> Co-authored-by: Guilherme Falcão <[email protected]> Co-authored-by: Leo Vu <[email protected]>
Resolves #18138
Summary by CodeRabbit
New Features
Chores