diff --git a/components/trello/actions/add-attachment-to-card/add-attachment-to-card.mjs b/components/trello/actions/add-attachment-to-card/add-attachment-to-card.mjs index 7f401f3bfcb5f..12c31d0063404 100644 --- a/components/trello/actions/add-attachment-to-card/add-attachment-to-card.mjs +++ b/components/trello/actions/add-attachment-to-card/add-attachment-to-card.mjs @@ -1,26 +1,25 @@ import { ConfigurationError } from "@pipedream/platform"; import fs from "fs"; import FormData from "form-data"; -import common from "../common.mjs"; +import app from "../../trello.app.mjs"; export default { - ...common, key: "trello-add-attachment-to-card", name: "Add Attachment To Card", description: "Adds a file attachment on a card. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-cards/#api-cards-id-attachments-post)", - version: "0.0.1", + version: "0.0.2", type: "action", props: { - ...common.props, + app, board: { propDefinition: [ - common.props.app, + app, "board", ], }, cardId: { propDefinition: [ - common.props.app, + app, "cards", (c) => ({ board: c.board, @@ -33,49 +32,57 @@ export default { }, name: { propDefinition: [ - common.props.app, + app, "name", ], }, - url: { + fileType: { propDefinition: [ - common.props.app, - "url", + app, + "fileType", ], + reloadProps: true, }, - mimeType: { + url: { propDefinition: [ - common.props.app, - "mimeType", + app, + "url", ], + hidden: true, }, file: { propDefinition: [ - common.props.app, + app, "file", ], + hidden: true, + }, + mimeType: { + propDefinition: [ + app, + "mimeType", + ], + hidden: true, }, setCover: { type: "boolean", label: "Set Cover?", description: "Determines whether to use the new attachment as a cover for the Card", default: false, + optional: true, }, }, - methods: { - ...common.methods, - addAttachmentToCard({ - cardId, ...args - } = {}) { - return this.app.post({ - path: `/cards/${cardId}/attachments`, - ...args, - }); - }, + async additionalProps(props) { + const attachmentIsPath = this.fileType === "path"; + const attachmentIsUrl = this.fileType === "url"; + props.file.hidden = !attachmentIsPath; + props.mimeType.hidden = !attachmentIsPath; + props.url.hidden = !attachmentIsUrl; + + return {}; }, async run({ $ }) { const { - addAttachmentToCard, cardId, name, url, @@ -99,7 +106,7 @@ export default { const form = new FormData(); form.append("file", fs.createReadStream(file)); - response = await addAttachmentToCard({ + response = await this.app.addAttachmentToCard({ $, cardId, params, @@ -108,7 +115,7 @@ export default { }); } else { - response = await addAttachmentToCard({ + response = await this.app.addAttachmentToCard({ $, cardId, params: { diff --git a/components/trello/actions/add-checklist/add-checklist.mjs b/components/trello/actions/add-checklist/add-checklist.mjs index b47af479b96fa..0b97164741e8f 100644 --- a/components/trello/actions/add-checklist/add-checklist.mjs +++ b/components/trello/actions/add-checklist/add-checklist.mjs @@ -2,9 +2,9 @@ import app from "../../trello.app.mjs"; export default { key: "trello-add-checklist", - name: "Create a Checklist", + name: "Add Checklist", description: "Adds a new checklist to a card. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-cards/#api-cards-id-checklists-post).", - version: "0.2.0", + version: "0.2.1", type: "action", props: { app, @@ -42,34 +42,24 @@ export default { board: boardId, }), ], + label: "Copy from Checklist", }, pos: { - type: "string", - label: "Position", - description: "The position of the checklist on the card. One of: top, bottom, or a positive number.", - optional: true, - }, - }, - methods: { - addChecklist({ - cardId, ...args - } = {}) { - return this.app.post({ - path: `/cards/${cardId}/checklists`, - ...args, - }); + propDefinition: [ + app, + "pos", + ], }, }, async run({ $ }) { const { - addChecklist, cardId, name, idChecklistSource, pos, } = this; - const response = await addChecklist({ + const response = await this.app.addChecklist({ $, cardId, params: { @@ -79,7 +69,7 @@ export default { }, }); - $.export("$summary", "Successfully added checklist."); + $.export("$summary", `Successfully added checklist with ID: ${response.id}`); return response; }, diff --git a/components/trello/actions/add-comment/add-comment.mjs b/components/trello/actions/add-comment/add-comment.mjs index 96c8a7f605556..e9d15920e83b8 100644 --- a/components/trello/actions/add-comment/add-comment.mjs +++ b/components/trello/actions/add-comment/add-comment.mjs @@ -2,9 +2,9 @@ import app from "../../trello.app.mjs"; export default { key: "trello-add-comment", - name: "Create a Comment", + name: "Add Comment", description: "Create a new comment on a specific card. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-cards/#api-cards-id-actions-comments-post).", - version: "0.2.0", + version: "0.2.1", type: "action", props: { app, @@ -45,12 +45,11 @@ export default { }, async run({ $ }) { const { - addComment, cardId, text, } = this; - const response = await addComment({ + const response = await this.app.addComment({ $, cardId, params: { @@ -58,7 +57,7 @@ export default { }, }); - $.export("$summary", "Successfully added comment."); + $.export("$summary", `Successfully added comment with ID: ${response.id}`); return response; }, diff --git a/components/trello/actions/add-existing-label-to-card/add-existing-label-to-card.mjs b/components/trello/actions/add-existing-label-to-card/add-existing-label-to-card.mjs index 1c47f5c09ea91..fce3990ac1825 100644 --- a/components/trello/actions/add-existing-label-to-card/add-existing-label-to-card.mjs +++ b/components/trello/actions/add-existing-label-to-card/add-existing-label-to-card.mjs @@ -1,23 +1,22 @@ -import common from "../common.mjs"; +import app from "../../trello.app.mjs"; export default { - ...common, key: "trello-add-existing-label-to-card", name: "Add Existing Label to Card", description: "Adds an existing label to the specified card. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-cards/#api-cards-id-idlabels-post).", - version: "0.1.0", + version: "0.1.1", type: "action", props: { - ...common.props, + app, board: { propDefinition: [ - common.props.app, + app, "board", ], }, cardId: { propDefinition: [ - common.props.app, + app, "cards", (c) => ({ board: c.board, @@ -30,27 +29,18 @@ export default { }, value: { propDefinition: [ - common.props.app, + app, "label", (c) => ({ board: c.board, + card: c.cardId, + excludeCardLabels: true, }), ], }, }, - methods: { - ...common.methods, - addExistingLabelToCard({ - cardId, ...args - } = {}) { - return this.app.post({ - path: `/cards/${cardId}/idLabels`, - ...args, - }); - }, - }, async run({ $ }) { - const res = await this.addExistingLabelToCard({ + const res = await this.app.addExistingLabelToCard({ $, cardId: this.cardId, params: { diff --git a/components/trello/actions/add-member-to-card/add-member-to-card.mjs b/components/trello/actions/add-member-to-card/add-member-to-card.mjs index ff66c3e6b6bb8..e70949454049a 100644 --- a/components/trello/actions/add-member-to-card/add-member-to-card.mjs +++ b/components/trello/actions/add-member-to-card/add-member-to-card.mjs @@ -1,23 +1,22 @@ -import common from "../common.mjs"; +import app from "../../trello.app.mjs"; export default { - ...common, key: "trello-add-member-to-card", name: "Add Member to Card", description: "Adds a member to the specified card. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-cards/#api-cards-id-idmembers-post).", - version: "0.2.0", + version: "0.2.1", type: "action", props: { - ...common.props, + app, board: { propDefinition: [ - common.props.app, + app, "board", ], }, cardId: { propDefinition: [ - common.props.app, + app, "cards", (c) => ({ board: c.board, @@ -30,27 +29,18 @@ export default { }, value: { propDefinition: [ - common.props.app, + app, "member", (c) => ({ board: c.board, + card: c.cardId, + excludeCardMembers: true, }), ], }, }, - methods: { - ...common.methods, - addMemberToCard({ - cardId, ...args - } = {}) { - return this.app.post({ - path: `/cards/${cardId}/idMembers`, - ...args, - }); - }, - }, async run({ $ }) { - const res = await this.addMemberToCard({ + const res = await this.app.addMemberToCard({ $, cardId: this.cardId, params: { diff --git a/components/trello/actions/archive-card/archive-card.mjs b/components/trello/actions/archive-card/archive-card.mjs index 0e15e0369c5a7..678d67abd37a7 100644 --- a/components/trello/actions/archive-card/archive-card.mjs +++ b/components/trello/actions/archive-card/archive-card.mjs @@ -1,23 +1,22 @@ -import common from "../common.mjs"; +import app from "../../trello.app.mjs"; export default { - ...common, key: "trello-archive-card", name: "Archive Card", description: "Archives a card. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-cards/#api-cards-id-put).", - version: "0.2.0", + version: "0.2.1", type: "action", props: { - ...common.props, + app, board: { propDefinition: [ - common.props.app, + app, "board", ], }, cardId: { propDefinition: [ - common.props.app, + app, "cards", (c) => ({ board: c.board, diff --git a/components/trello/actions/close-board/close-board.mjs b/components/trello/actions/close-board/close-board.mjs deleted file mode 100644 index f286947b9992f..0000000000000 --- a/components/trello/actions/close-board/close-board.mjs +++ /dev/null @@ -1,31 +0,0 @@ -import common from "../common.mjs"; - -export default { - ...common, - key: "trello-close-board", - name: "Close Board", - description: "Closes a board. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-boards/#api-boards-id-put).", - version: "0.1.0", - type: "action", - props: { - ...common.props, - boardId: { - propDefinition: [ - common.props.app, - "board", - ], - description: "The ID of the Board to close", - }, - }, - async run({ $ }) { - const res = await this.app.updateBoard({ - $, - boardId: this.boardId, - data: { - closed: true, - }, - }); - $.export("$summary", `Successfully closed board ${this.boardId}`); - return res; - }, -}; diff --git a/components/trello/actions/common.mjs b/components/trello/actions/common/common.mjs similarity index 94% rename from components/trello/actions/common.mjs rename to components/trello/actions/common/common.mjs index 6e32f78c5ebf1..0fd5cade15a04 100644 --- a/components/trello/actions/common.mjs +++ b/components/trello/actions/common/common.mjs @@ -1,4 +1,4 @@ -import app from "../trello.app.mjs"; +import app from "../../trello.app.mjs"; export default { props: { diff --git a/components/trello/actions/complete-checklist-item/complete-checklist-item.mjs b/components/trello/actions/complete-checklist-item/complete-checklist-item.mjs index 4ee9cd982a226..350fe5f55db69 100644 --- a/components/trello/actions/complete-checklist-item/complete-checklist-item.mjs +++ b/components/trello/actions/complete-checklist-item/complete-checklist-item.mjs @@ -4,7 +4,7 @@ export default { key: "trello-complete-checklist-item", name: "Complete a Checklist Item", description: "Completes an existing checklist item in a card. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-cards/#api-cards-id-checkitem-idcheckitem-put).", - version: "0.2.0", + version: "0.2.1", type: "action", props: { app, @@ -20,6 +20,7 @@ export default { "cards", (c) => ({ board: c.board, + checklistCardsOnly: true, }), ], type: "string", @@ -46,24 +47,13 @@ export default { ], }, }, - methods: { - completeChecklistItem({ - cardId, checklistItemId, ...args - } = {}) { - return this.app.put({ - path: `/cards/${cardId}/checkItem/${checklistItemId}`, - ...args, - }); - }, - }, async run({ $ }) { const { - completeChecklistItem, cardId, checklistItemId, } = this; - const response = await completeChecklistItem({ + const response = await this.app.completeChecklistItem({ $, cardId, checklistItemId, @@ -72,7 +62,7 @@ export default { }, }); - $.export("$summary", "Successfully completed checklist item."); + $.export("$summary", `Successfully completed checklist item with ID: ${checklistItemId}`); return response; }, diff --git a/components/trello/actions/create-board/create-board.mjs b/components/trello/actions/create-board/create-board.mjs index 714ecca952b11..bdd57b75bebc8 100644 --- a/components/trello/actions/create-board/create-board.mjs +++ b/components/trello/actions/create-board/create-board.mjs @@ -1,10 +1,11 @@ import app from "../../trello.app.mjs"; +import constants from "../../common/constants.mjs"; export default { key: "trello-create-board", name: "Create a Board", - description: "Creates a new Trello board. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-boards/#api-boards-post).", - version: "0.2.0", + description: "Create a new Trello board or copy from an existing one. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-boards/#api-boards-post).", + version: "0.2.1", type: "action", props: { app, @@ -65,60 +66,35 @@ export default { label: "Power-Ups", description: "The Power-Ups that should be enabled on the new board. One of: `all`, `calendar`, `cardAging`, `recap`, `voting`.", optional: true, - options: [ - "all", - "calendar", - "cardAging", - "recap", - "voting", - ], + options: constants.POWER_UPS, }, prefsPermissionLevel: { type: "string", description: "The permissions level of the board. One of: org, private, public.", label: "Prefs Permission Level", optional: true, - options: [ - "org", - "private", - "public", - ], + options: constants.PREFS_PERMISSION_LEVELS, }, prefsVoting: { type: "string", label: "Prefs Voting", description: "Who can vote on this board. One of disabled, members, observers, org, public.", optional: true, - options: [ - "disabled", - "members", - "observers", - "org", - "public", - ], + options: constants.PREFS_VOTING, }, prefsComments: { type: "string", label: "Prefs Comments", description: "Who can comment on cards on this board. One of: disabled, members, observers, org, public.", optional: true, - options: [ - "disabled", - "members", - "observers", - "org", - "public", - ], + options: constants.PREFS_COMMENTS, }, prefsInvitations: { type: "string", label: "Prefs Invitations", description: "Determines what types of members can invite users to join. One of: admins, members.", optional: true, - options: [ - "admins", - "members", - ], + options: constants.PREFS_INVITATIONS, }, prefsSelfJoin: { type: "boolean", @@ -137,27 +113,14 @@ export default { label: "Prefs Background", description: "The id of a custom background or one of: `blue`, `orange`, `green`, `red`, `purple`, `pink`, `lime`, `sky`, `grey`.", optional: true, - options: [ - "blue", - "orange", - "green", - "red", - "purple", - "pink", - "lime", - "sky", - "grey", - ], + options: constants.PREFS_BACKGROUNDS, }, prefsCardAging: { type: "string", label: "Prefs Card Aging", description: "Determines the type of card aging that should take place on the board if card aging is enabled. One of: pirate, regular.", optional: true, - options: [ - "pirate", - "regular", - ], + options: constants.PREFS_CARD_AGING, }, }, async run({ $ }) { diff --git a/components/trello/actions/create-card/create-card.mjs b/components/trello/actions/create-card/create-card.mjs index b073448ee8c56..fddb8544440a2 100644 --- a/components/trello/actions/create-card/create-card.mjs +++ b/components/trello/actions/create-card/create-card.mjs @@ -1,26 +1,26 @@ +import app from "../../trello.app.mjs"; import fs from "fs"; import FormData from "form-data"; import { ConfigurationError } from "@pipedream/platform"; -import common from "../common.mjs"; +import constants from "../../common/constants.mjs"; export default { - ...common, key: "trello-create-card", name: "Create Card", description: "Creates a new card. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-cards/#api-cards-post).", - version: "0.1.0", + version: "0.1.1", type: "action", props: { - ...common.props, + app, board: { propDefinition: [ - common.props.app, + app, "board", ], }, name: { propDefinition: [ - common.props.app, + app, "name", ], description: "The name of the card.", @@ -28,31 +28,32 @@ export default { }, desc: { propDefinition: [ - common.props.app, + app, "desc", ], }, pos: { propDefinition: [ - common.props.app, + app, "pos", ], + description: "The position of the new card. `top`, `bottom`, or a positive float", }, due: { propDefinition: [ - common.props.app, + app, "due", ], }, dueComplete: { propDefinition: [ - common.props.app, + app, "dueComplete", ], }, idList: { propDefinition: [ - common.props.app, + app, "lists", (c) => ({ board: c.board, @@ -65,7 +66,7 @@ export default { }, idMembers: { propDefinition: [ - common.props.app, + app, "member", (c) => ({ board: c.board, @@ -78,7 +79,7 @@ export default { }, idLabels: { propDefinition: [ - common.props.app, + app, "label", (c) => ({ board: c.board, @@ -89,27 +90,38 @@ export default { description: "Array of labelIDs to add to the card", optional: true, }, - urlSource: { + fileType: { propDefinition: [ - common.props.app, - "url", + app, + "fileType", ], + optional: true, + reloadProps: true, }, - mimeType: { + urlSource: { propDefinition: [ - common.props.app, - "mimeType", + app, + "url", ], + hidden: true, }, file: { propDefinition: [ - common.props.app, + app, "file", ], + hidden: true, + }, + mimeType: { + propDefinition: [ + app, + "mimeType", + ], + hidden: true, }, idCardSource: { propDefinition: [ - common.props.app, + app, "cards", (c) => ({ board: c.board, @@ -118,44 +130,37 @@ export default { type: "string", label: "Copy Card", description: "Specify an existing card to copy contents from. Keep in mind that if you copy a card, the **File Attachment Path**, **File Attachment URL** and **File Attachment Type** fields will be ignored.", + reloadProps: true, }, keepFromSource: { type: "string[]", label: "Copy From Source", description: "Specify which properties to copy from the source card", - options: [ - "all", - "attachments", - "checklists", - "comments", - "due", - "labels", - "members", - "stickers", - ], + options: constants.CARD_KEEP_FROM_SOURCE_PROPERTIES, optional: true, + hidden: true, }, address: { propDefinition: [ - common.props.app, + app, "address", ], }, locationName: { propDefinition: [ - common.props.app, + app, "locationName", ], }, coordinates: { propDefinition: [ - common.props.app, + app, "coordinates", ], }, customFieldIds: { propDefinition: [ - common.props.app, + app, "customFieldIds", (c) => ({ boardId: c.board, @@ -164,8 +169,17 @@ export default { reloadProps: true, }, }, - async additionalProps() { + async additionalProps(existingProps) { const props = {}; + + const attachmentIsPath = this.fileType === "path"; + const attachmentIsUrl = this.fileType === "url"; + existingProps.file.hidden = !attachmentIsPath; + existingProps.mimeType.hidden = !attachmentIsPath; + existingProps.urlSource.hidden = !attachmentIsUrl; + + existingProps.keepFromSource.hidden = !this.idCardSource; + if (!this.customFieldIds?.length) { return props; } @@ -187,7 +201,6 @@ export default { return props; }, methods: { - ...common.methods, async getCustomFieldItems($) { const customFieldItems = []; for (const customFieldId of this.customFieldIds) { @@ -213,16 +226,9 @@ export default { } return customFieldItems; }, - createCard(args = {}) { - return this.app.post({ - path: "/cards", - ...args, - }); - }, }, async run({ $ }) { const { - createCard, name, desc, pos, @@ -268,15 +274,14 @@ export default { const form = new FormData(); form.append("fileSource", fs.createReadStream(file)); - response = await createCard({ + response = await this.app.createCard({ $, params, headers: form.getHeaders(), data: form, }); - } else { - response = await createCard({ + response = await this.app.createCard({ $, params: { ...params, diff --git a/components/trello/actions/create-checklist-item/create-checklist-item.mjs b/components/trello/actions/create-checklist-item/create-checklist-item.mjs index 2615ed122af50..cf8175c518072 100644 --- a/components/trello/actions/create-checklist-item/create-checklist-item.mjs +++ b/components/trello/actions/create-checklist-item/create-checklist-item.mjs @@ -4,7 +4,7 @@ export default { key: "trello-create-checklist-item", name: "Create a Checklist Item", description: "Creates a new checklist item in a card. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-checklists/#api-checklists-id-checkitems-post).", - version: "0.2.0", + version: "0.2.1", type: "action", props: { app, @@ -20,6 +20,7 @@ export default { "cards", ({ board }) => ({ board, + checklistCardsOnly: true, }), ], type: "string", @@ -56,26 +57,15 @@ export default { optional: true, }, }, - methods: { - createChecklistItem({ - checklistId, ...args - } = {}) { - return this.app.post({ - path: `/checklists/${checklistId}/checkItems`, - ...args, - }); - }, - }, async run({ $ }) { const { - createChecklistItem, checklistId, name, pos, checked, } = this; - const response = await createChecklistItem({ + const response = await this.app.createChecklistItem({ $, checklistId, params: { @@ -85,7 +75,7 @@ export default { }, }); - $.export("$summary", "Successfully created a checklist item"); + $.export("$summary", `Successfully created a checklist item with ID: ${response.id}`); return response; }, diff --git a/components/trello/actions/create-checklist/create-checklist.mjs b/components/trello/actions/create-checklist/create-checklist.mjs deleted file mode 100644 index 722cbfa4d3be1..0000000000000 --- a/components/trello/actions/create-checklist/create-checklist.mjs +++ /dev/null @@ -1,78 +0,0 @@ -import common from "../common.mjs"; - -export default { - ...common, - key: "trello-create-checklist", - name: "Create Checklist", - description: "Creates a checklist on the specified card. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-checklists/#api-checklists-post).", - version: "0.1.0", - type: "action", - props: { - ...common.props, - board: { - propDefinition: [ - common.props.app, - "board", - ], - }, - idCard: { - propDefinition: [ - common.props.app, - "cards", - (c) => ({ - board: c.board, - }), - ], - type: "string", - label: "Card", - description: "The ID of the Card that the checklist should be added to", - optional: false, - }, - name: { - propDefinition: [ - common.props.app, - "name", - ], - description: "The name of the checklist. Should be a string of length 1 to 16384.", - }, - pos: { - propDefinition: [ - common.props.app, - "pos", - ], - description: "The position of the new checklist. Valid values: `top`, `bottom`, or a positive float.", - }, - idChecklistSource: { - optional: true, - propDefinition: [ - common.props.app, - "checklist", - (c) => ({ - board: c.board, - }), - ], - }, - }, - methods: { - ...common.methods, - createChecklist(args = {}) { - return this.app.post({ - path: "/checklists", - ...args, - }); - }, - }, - async run({ $ }) { - const res = await this.createChecklist({ - $, - params: { - idCard: this.idCard, - name: this.name, - pos: this.pos, - idChecklistSource: this.idChecklistSource, - }, - }); - $.export("$summary", `Successfully created checklist ${res.name}`); - return res; - }, -}; diff --git a/components/trello/actions/create-comment-on-card/create-comment-on-card.mjs b/components/trello/actions/create-comment-on-card/create-comment-on-card.mjs deleted file mode 100644 index 1055f203d8845..0000000000000 --- a/components/trello/actions/create-comment-on-card/create-comment-on-card.mjs +++ /dev/null @@ -1,59 +0,0 @@ -import common from "../common.mjs"; - -export default { - ...common, - key: "trello-create-comment-on-card", - name: "Create Comment on Card", - description: "Creates a new comment on a card. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-cards/#api-cards-id-actions-comments-post).", - version: "0.1.0", - type: "action", - props: { - ...common.props, - board: { - propDefinition: [ - common.props.app, - "board", - ], - }, - cardId: { - propDefinition: [ - common.props.app, - "cards", - ({ board }) => ({ - board, - }), - ], - type: "string", - label: "Card", - description: "The ID of the card to create a new comment on", - optional: false, - }, - comment: { - type: "string", - label: "Comment", - description: "Text for the comment to be created.", - }, - }, - methods: { - ...common.methods, - createCommentOnCard({ - cardId, ...args - } = {}) { - return this.app.post({ - path: `/cards/${cardId}/actions/comments`, - ...args, - }); - }, - }, - async run({ $ }) { - const res = await this.createCommentOnCard({ - $, - cardId: this.cardId, - params: { - text: this.comment, - }, - }); - $.export("$summary", `Successfully added comment to card ${this.cardId}`); - return res; - }, -}; diff --git a/components/trello/actions/create-label/create-label.mjs b/components/trello/actions/create-label/create-label.mjs index 6fd4a182d6ca0..8e109639f8069 100644 --- a/components/trello/actions/create-label/create-label.mjs +++ b/components/trello/actions/create-label/create-label.mjs @@ -1,10 +1,11 @@ import app from "../../trello.app.mjs"; +import constants from "../../common/constants.mjs"; export default { key: "trello-create-label", name: "Create Label", description: "Creates a new label on the specified board. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-labels/#api-labels-post).", - version: "0.2.0", + version: "0.2.1", type: "action", props: { app, @@ -26,19 +27,7 @@ export default { type: "string", label: "Color", description: "The color for the label. One of: yellow, purple, blue, red, green, orange, black, sky, pink, lime, null (null means no color, and the label will not show on the front of cards)", - options: [ - "yellow", - "purple", - "blue", - "red", - "green", - "orange", - "black", - "sky", - "pink", - "lime", - "null", - ], + options: constants.LABEL_COLORS, }, }, methods: { @@ -50,15 +39,13 @@ export default { }, }, async run({ $ }) { - const { - createLabel, idBoard, name, color, } = this; - const response = await createLabel({ + const response = await this.app.createLabel({ $, params: { idBoard, @@ -67,7 +54,7 @@ export default { }, }); - $.export("$summary", "Successfully created a label"); + $.export("$summary", `Successfully created label ${this.name}`); return response; }, diff --git a/components/trello/actions/create-list/create-list.mjs b/components/trello/actions/create-list/create-list.mjs index 30a3add4509d9..b937590956ce0 100644 --- a/components/trello/actions/create-list/create-list.mjs +++ b/components/trello/actions/create-list/create-list.mjs @@ -4,7 +4,7 @@ export default { key: "trello-create-list", name: "Create a List", description: "Creates a new list. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-lists/#api-lists-post).", - version: "0.2.0", + version: "0.2.1", type: "action", props: { app, @@ -40,26 +40,18 @@ export default { app, "pos", ], - }, - }, - methods: { - createList(args = {}) { - return this.app.post({ - path: "/lists", - ...args, - }); + description: "Position of the list. `top`, `bottom`, or a positive floating point number", }, }, async run({ $ }) { const { - createList, name, idBoard, idListSource, pos, } = this; - const response = await createList({ + const response = await this.app.createList({ $, params: { name, @@ -69,7 +61,7 @@ export default { }, }); - $.export("$summary", "Successfully created list."); + $.export("$summary", `Successfully created list ${this.name}`); return response; }, diff --git a/components/trello/actions/delete-checklist/delete-checklist.mjs b/components/trello/actions/delete-checklist/delete-checklist.mjs index 6f8928216191d..582991e88559f 100644 --- a/components/trello/actions/delete-checklist/delete-checklist.mjs +++ b/components/trello/actions/delete-checklist/delete-checklist.mjs @@ -1,26 +1,26 @@ -import common from "../common.mjs"; +import app from "../../trello.app.mjs"; export default { - ...common, key: "trello-delete-checklist", name: "Delete Checklist", description: "Deletes the specified checklist. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-checklists/#api-checklists-id-delete).", - version: "0.2.0", + version: "0.2.1", type: "action", props: { - ...common.props, + app, board: { propDefinition: [ - common.props.app, + app, "board", ], }, carId: { propDefinition: [ - common.props.app, + app, "cards", (c) => ({ board: c.board, + checklistCardsOnly: true, }), ], type: "string", @@ -30,7 +30,7 @@ export default { }, checklistId: { propDefinition: [ - common.props.app, + app, "checklist", ({ carId }) => ({ card: carId, @@ -39,18 +39,8 @@ export default { description: "The ID of the checklist to delete", }, }, - methods: { - deleteChecklist({ - checklistId, ...args - } = {}) { - return this.app.delete({ - path: `/checklists/${checklistId}`, - ...args, - }); - }, - }, async run({ $ }) { - await this.deleteChecklist({ + await this.app.deleteChecklist({ $, checklistId: this.checklistId, }); diff --git a/components/trello/actions/find-labels/find-labels.mjs b/components/trello/actions/find-labels/find-labels.mjs index c777387e1f693..6964482a90056 100644 --- a/components/trello/actions/find-labels/find-labels.mjs +++ b/components/trello/actions/find-labels/find-labels.mjs @@ -1,11 +1,11 @@ -import common from "../common.mjs"; +import common from "../common/common.mjs"; export default { ...common, key: "trello-find-labels", name: "Find a Label", description: "Finds a label on a specific board by name. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-boards/#api-boards-id-labels-get)", - version: "0.2.0", + version: "0.2.1", type: "action", props: { ...common.props, @@ -23,7 +23,6 @@ export default { ], label: "Label Name", description: "Name of the label to find.", - optional: false, }, limit: { type: "integer", diff --git a/components/trello/actions/find-list/find-list.mjs b/components/trello/actions/find-list/find-list.mjs index e81364b5a242b..181941af53909 100644 --- a/components/trello/actions/find-list/find-list.mjs +++ b/components/trello/actions/find-list/find-list.mjs @@ -1,11 +1,11 @@ -import common from "../common.mjs"; +import common from "../common/common.mjs"; export default { ...common, key: "trello-find-list", name: "Find a List", description: "Finds a list on a specific board by name. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-boards/#api-boards-id-lists-get).", - version: "0.2.0", + version: "0.2.1", type: "action", props: { ...common.props, diff --git a/components/trello/actions/get-card/get-card.mjs b/components/trello/actions/get-card/get-card.mjs index 2f2d45466f2a7..001a1cacab555 100644 --- a/components/trello/actions/get-card/get-card.mjs +++ b/components/trello/actions/get-card/get-card.mjs @@ -1,11 +1,11 @@ -import common from "../common.mjs"; +import common from "../common/common.mjs"; export default { ...common, key: "trello-get-card", name: "Get Card", description: "Gets a card by its ID. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-cards/#api-cards-id-get).", - version: "0.2.0", + version: "0.2.1", type: "action", props: { ...common.props, diff --git a/components/trello/actions/get-list/get-list.mjs b/components/trello/actions/get-list/get-list.mjs index 038d12503be5b..ba7e28c7dd569 100644 --- a/components/trello/actions/get-list/get-list.mjs +++ b/components/trello/actions/get-list/get-list.mjs @@ -4,7 +4,7 @@ export default { key: "trello-get-list", name: "Get List", description: "Get information about a List. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-lists/#api-lists-id-get).", - version: "0.1.0", + version: "0.1.1", type: "action", props: { app, diff --git a/components/trello/actions/move-card-to-list/move-card-to-list.mjs b/components/trello/actions/move-card-to-list/move-card-to-list.mjs index a5507158b921b..955a81949c248 100644 --- a/components/trello/actions/move-card-to-list/move-card-to-list.mjs +++ b/components/trello/actions/move-card-to-list/move-card-to-list.mjs @@ -1,11 +1,11 @@ -import common from "../common.mjs"; +import common from "../common/common.mjs"; export default { ...common, key: "trello-move-card-to-list", name: "Move Card to List", description: "Moves a card to the specified board/list pair. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-cards/#api-cards-id-put).", - version: "0.2.0", + version: "0.2.1", type: "action", props: { ...common.props, diff --git a/components/trello/actions/remove-label-from-card/remove-label-from-card.mjs b/components/trello/actions/remove-label-from-card/remove-label-from-card.mjs index 7a4be7c28728a..ed42c8ba921b5 100644 --- a/components/trello/actions/remove-label-from-card/remove-label-from-card.mjs +++ b/components/trello/actions/remove-label-from-card/remove-label-from-card.mjs @@ -1,23 +1,22 @@ -import common from "../common.mjs"; +import app from "../../trello.app.mjs"; export default { - ...common, key: "trello-remove-label-from-card", name: "Remove Card Label", description: "Removes label from card. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-cards/#api-cards-id-idlabels-idlabel-delete).", - version: "0.2.0", + version: "0.2.1", type: "action", props: { - ...common.props, + app, board: { propDefinition: [ - common.props.app, + app, "board", ], }, cardId: { propDefinition: [ - common.props.app, + app, "cards", (c) => ({ board: c.board, @@ -30,27 +29,19 @@ export default { }, labelId: { propDefinition: [ - common.props.app, + app, "label", (c) => ({ board: c.board, + card: c.cardId, + cardLabelsOnly: true, }), ], description: "The ID of the Label to be removed from the card.", }, }, - methods: { - removeLabelFromCard({ - cardId, labelId, ...args - } = {}) { - return this.app.delete({ - path: `/cards/${cardId}/idLabels/${labelId}`, - ...args, - }); - }, - }, async run({ $ }) { - await this.removeLabelFromCard({ + await this.app.removeLabelFromCard({ $, cardId: this.cardId, labelId: this.labelId, diff --git a/components/trello/actions/rename-list/rename-list.mjs b/components/trello/actions/rename-list/rename-list.mjs index 76cb72c0f00e3..dc2040505f735 100644 --- a/components/trello/actions/rename-list/rename-list.mjs +++ b/components/trello/actions/rename-list/rename-list.mjs @@ -1,11 +1,11 @@ -import common from "../common.mjs"; +import common from "../common/common.mjs"; export default { ...common, key: "trello-rename-list", name: "Rename List", description: "Renames an existing list. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-lists/#api-lists-id-put).", - version: "0.1.0", + version: "0.1.1", type: "action", props: { ...common.props, diff --git a/components/trello/actions/search-boards/search-boards.mjs b/components/trello/actions/search-boards/search-boards.mjs index e324ab52ba9f2..abb6023e68dee 100644 --- a/components/trello/actions/search-boards/search-boards.mjs +++ b/components/trello/actions/search-boards/search-boards.mjs @@ -1,44 +1,46 @@ -import common from "../common.mjs"; +import app from "../../trello.app.mjs"; export default { - ...common, key: "trello-search-boards", name: "Search Boards", description: "Searches for boards matching the specified query. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-search/#api-search-get).", - version: "0.3.0", + version: "0.3.1", type: "action", props: { - ...common.props, + app, query: { propDefinition: [ - common.props.app, + app, "query", ], }, idOrganizations: { propDefinition: [ - common.props.app, + app, "idOrganizations", ], description: "Specify the organizations to search for boards in", }, partial: { propDefinition: [ - common.props.app, + app, "partial", ], + optional: true, }, boardFields: { propDefinition: [ - common.props.app, + app, "boardFields", ], + optional: true, }, boardsLimit: { type: "integer", label: "Boards Limit", description: "The maximum number of boards to return.", default: 10, + optional: true, }, }, async run({ $ }) { diff --git a/components/trello/actions/search-cards/search-cards.mjs b/components/trello/actions/search-cards/search-cards.mjs index bce976526f035..da542c35f787b 100644 --- a/components/trello/actions/search-cards/search-cards.mjs +++ b/components/trello/actions/search-cards/search-cards.mjs @@ -1,46 +1,49 @@ -import common from "../common.mjs"; +import app from "../../trello.app.mjs"; export default { - ...common, key: "trello-search-cards", name: "Search Cards", description: "Searches for cards matching the specified query. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-search/#api-search-get).", - version: "0.2.0", + version: "0.2.1", type: "action", props: { - ...common.props, + app, query: { propDefinition: [ - common.props.app, + app, "query", ], }, idBoards: { propDefinition: [ - common.props.app, + app, "board", ], type: "string[]", label: "Boards", description: "The IDs of boards to search for cards in", + optional: true, }, partial: { propDefinition: [ - common.props.app, + app, "partial", ], + optional: true, }, cardFields: { propDefinition: [ - common.props.app, + app, "cardFields", ], + optional: true, }, cardsLimit: { type: "integer", label: "Cards Limit", description: "The maximum number of cards to return.", default: 10, + optional: true, }, }, async run({ $ }) { diff --git a/components/trello/actions/search-checklists/search-checklists.mjs b/components/trello/actions/search-checklists/search-checklists.mjs index e51b0314ccda7..7e8fac84be9b2 100644 --- a/components/trello/actions/search-checklists/search-checklists.mjs +++ b/components/trello/actions/search-checklists/search-checklists.mjs @@ -2,9 +2,9 @@ import app from "../../trello.app.mjs"; export default { key: "trello-search-checklists", - name: "Find Checklist", + name: "Search Checklists", description: "Find a checklist on a particular board or card by name. [See the documentation here](https://developer.atlassian.com/cloud/trello/rest/api-group-boards/#api-boards-id-checklists-get) and [here](https://developer.atlassian.com/cloud/trello/rest/api-group-cards/#api-cards-id-checklists-get).", - version: "0.2.0", + version: "0.2.1", type: "action", props: { app, @@ -19,102 +19,83 @@ export default { reloadProps: true, }, boardId: { - type: "string", - label: "Board ID", - description: "The ID of the board.", + propDefinition: [ + app, + "board", + ], hidden: true, }, cardId: { + propDefinition: [ + app, + "cards", + (c) => ({ + board: c.boardId, + }), + ], type: "string", label: "Card ID", - description: "The ID of the card.", + description: "The ID of the card", hidden: true, }, query: { type: "string", label: "Query", - description: "The query to search for.", + description: "The query to search for", }, checkItems: { type: "string", label: "Check Items", - description: "all or none", + description: "Whether to display checklist items in the result. Select `all` or `none`.", optional: true, options: [ "all", "none", ], + reloadProps: true, + hidden: true, }, checkItemFields: { - type: "string", + type: "string[]", label: "CheckItem Fields", - description: "all or a comma-separated list of: name, nameData, pos, state, type", - optional: true, - }, - filter: { - type: "string", - label: "Filter", - description: "all or none", - optional: true, + description: "Fields to include in the results. `all` or a list of: `name`, `nameData`, `pos`, `state`, `type`", options: [ "all", - "none", + "name", + "nameData", + "pos", + "state", + "type", ], + optional: true, + hidden: true, }, fields: { - type: "string", + type: "string[]", label: "Fields", - description: "`all` or a comma-separated list of: `idBoard`, `idCard`, `name`, `pos`. Eg: `idBoard,idCard,name,pos`. Eg: `all`.", + description: "Fields to include in the results. `all` or a list of: `idBoard`, `idCard`, `name`, `pos`. Eg: `idBoard,idCard,name,pos`. Eg: `all`.", + options: [ + "all", + "idBoard", + "idCard", + "name", + "pos", + ], optional: true, + hidden: true, }, }, - additionalProps() { - const { type } = this; - - const defaultProps = { - boardId: { - type: "string", - label: "Board ID", - description: "The ID of the board.", - hidden: false, - options: async () => { - const boards = await this.app.getBoards(); - return boards - .filter(({ closed }) => closed === false) - .map(({ - id: value, name: label, - }) => ({ - label, - value, - })); - }, - }, - }; + additionalProps(props) { + const isCardSearch = this.type === "card"; + props.boardId.hidden = false; + props.cardId.hidden = !isCardSearch; + props.checkItems.hidden = !isCardSearch; + props.checkItemFields.hidden = !isCardSearch; + props.fields.hidden = !isCardSearch; - if (type === "card") { - return { - ...defaultProps, - cardId: { - type: "string", - label: "Card ID", - description: "The ID of the card.", - hidden: false, - options: async () => { - const cards = await this.app.getCards({ - boardId: this.boardId, - }); - return cards.map(({ - id: value, name: label, - }) => ({ - label, - value, - })); - }, - }, - }; - } + props.checkItemFields.hidden = !(this.checkItems === "all"); - return defaultProps; + return {}; }, async run({ $ }) { const { @@ -125,32 +106,27 @@ export default { query, checkItems, checkItemFields, - filter, fields, } = this; let checklists = null; let matches = []; - const params = { - checkItems, - checkItem_fields: checkItemFields, - filter, - fields, - }; - if (type === "board") { checklists = await app.listBoardChecklists({ $, boardId, - params, }); } else if (type === "card") { checklists = await app.listCardChecklists({ $, cardId, - params, + params: { + checkItems, + checkItem_fields: checkItemFields?.length && checkItemFields.join(), + fields: fields?.length && fields.join(), + }, }); } @@ -161,6 +137,11 @@ export default { }); } + if (matches?.length) { + $.export("$summary", `Found ${matches.length} matching checklist${matches.length === 1 + ? "" + : "s"}`); + } return matches; }, }; diff --git a/components/trello/actions/search-members/search-members.mjs b/components/trello/actions/search-members/search-members.mjs index 3c70aaef309cb..8e8aeada74d78 100644 --- a/components/trello/actions/search-members/search-members.mjs +++ b/components/trello/actions/search-members/search-members.mjs @@ -4,7 +4,7 @@ export default { key: "trello-search-members", name: "Search Members", description: "Search for Trello members. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-search/#api-search-members-get).", - version: "0.2.0", + version: "0.2.1", type: "action", props: { app, @@ -13,12 +13,6 @@ export default { label: "Search Query", description: "Search query 1 to 16384 characters long", }, - limit: { - type: "integer", - label: "Limit", - description: "The maximum number of results to return. Maximum of 20.", - optional: true, - }, idBoard: { label: "Board ID", description: "The ID of the board to search for members.", @@ -38,32 +32,24 @@ export default { "idOrganizations", ], }, - onlyOrgMembers: { - type: "boolean", - label: "Only Organization Members", - description: "If true, only members of the organization will be returned.", + limit: { + type: "integer", + label: "Limit", + description: "The maximum number of results to return. Maximum of 20.", optional: true, }, }, - methods: { - searchMembers(args = {}) { - return this.app._makeRequest({ - path: "/search/members", - ...args, - }); - }, - }, async run({ $ }) { const { - searchMembers, query, limit, idBoard, idOrganization, - onlyOrgMembers, } = this; - const response = await searchMembers({ + const onlyOrgMembers = idBoard || idOrganization; + + const response = await this.app.searchMembers({ $, params: { query, @@ -74,7 +60,11 @@ export default { }, }); - $.export("$summary", "Successfully searched for members."); + if (response?.length) { + $.export("$summary", `Successfully found ${response.length} member${response.length === 1 + ? "" + : "s"}`); + } return response; }, diff --git a/components/trello/actions/update-card/update-card.mjs b/components/trello/actions/update-card/update-card.mjs index 10b14d59219f5..bc3a6e1f2a761 100644 --- a/components/trello/actions/update-card/update-card.mjs +++ b/components/trello/actions/update-card/update-card.mjs @@ -1,25 +1,24 @@ -import common from "../common.mjs"; +import app from "../../trello.app.mjs"; import pickBy from "lodash-es/pickBy.js"; import pick from "lodash-es/pick.js"; export default { - ...common, key: "trello-update-card", name: "Update Card", description: "Updates a card. [See the documentation](https://developer.atlassian.com/cloud/trello/rest/api-group-cards/#api-cards-id-put).", - version: "0.2.0", + version: "0.2.1", type: "action", props: { - ...common.props, + app, idBoard: { propDefinition: [ - common.props.app, + app, "board", ], }, cardId: { propDefinition: [ - common.props.app, + app, "cards", (c) => ({ board: c.idBoard, @@ -32,14 +31,14 @@ export default { }, name: { propDefinition: [ - common.props.app, + app, "name", ], description: "The new name for the card.", }, desc: { propDefinition: [ - common.props.app, + app, "desc", ], description: "The new description for the card.", @@ -49,10 +48,11 @@ export default { label: "Archived", description: "Whether to archive the card", default: false, + optional: true, }, idMembers: { propDefinition: [ - common.props.app, + app, "member", (c) => ({ board: c.idBoard, @@ -65,7 +65,7 @@ export default { }, idAttachmentCover: { propDefinition: [ - common.props.app, + app, "cardAttachmentId", ({ cardId }) => ({ cardId, @@ -77,7 +77,7 @@ export default { }, idList: { propDefinition: [ - common.props.app, + app, "lists", (c) => ({ board: c.idBoard, @@ -89,7 +89,7 @@ export default { }, idLabels: { propDefinition: [ - common.props.app, + app, "label", (c) => ({ board: c.idBoard, @@ -102,19 +102,20 @@ export default { }, pos: { propDefinition: [ - common.props.app, + app, "pos", ], + description: "The position of the new card. `top`, `bottom`, or a positive float", }, due: { propDefinition: [ - common.props.app, + app, "due", ], }, dueComplete: { propDefinition: [ - common.props.app, + app, "dueComplete", ], description: "Whether the due date should be marked complete.", @@ -123,30 +124,31 @@ export default { subscribed: { type: "boolean", label: "Subscribed", - description: "Whether the member is should be subscribed to the card.", + description: "Whether the member should be subscribed to the card.", default: false, + optional: true, }, address: { propDefinition: [ - common.props.app, + app, "address", ], }, locationName: { propDefinition: [ - common.props.app, + app, "locationName", ], }, coordinates: { propDefinition: [ - common.props.app, + app, "coordinates", ], }, customFieldIds: { propDefinition: [ - common.props.app, + app, "customFieldIds", (c) => ({ boardId: c.idBoard, @@ -178,7 +180,6 @@ export default { return props; }, methods: { - ...common.methods, async getCustomFieldItems($) { const customFieldItems = []; for (const customFieldId of this.customFieldIds) { diff --git a/components/trello/common/constants.mjs b/components/trello/common/constants.mjs new file mode 100644 index 0000000000000..3af98f23e14a2 --- /dev/null +++ b/components/trello/common/constants.mjs @@ -0,0 +1,128 @@ +const POSITIONS = [ + "top", + "bottom", +]; + +const CARD_FILTERS = [ + "all", + "closed", + "none", + "open", + "visible", +]; + +const LIST_FILTERS = [ + "all", + "closed", + "none", + "open", +]; + +const POWER_UPS = [ + "all", + "calendar", + "cardAging", + "recap", + "voting", +]; + +const PREFS_PERMISSION_LEVELS = [ + "org", + "private", + "public", +]; + +const PREFS_VOTING = [ + "disabled", + "members", + "observers", + "org", + "public", +]; + +const PREFS_COMMENTS = [ + "disabled", + "members", + "observers", + "org", + "public", +]; + +const PREFS_INVITATIONS = [ + "admins", + "members", +]; + +const PREFS_BACKGROUNDS = [ + "blue", + "orange", + "green", + "red", + "purple", + "pink", + "lime", + "sky", + "grey", +]; + +const PREFS_CARD_AGING = [ + "pirate", + "regular", +]; + +const LABEL_COLORS = [ + "yellow", + "purple", + "blue", + "red", + "green", + "orange", + "black", + "sky", + "pink", + "lime", + "null", +]; + +const NOTIFICATION_TIMES = [ + "5 minutes", + "10 minutes", + "15 minutes", + "30 minutes", + "1 hour", + "2 hours", + "3 hours", + "6 hours", + "12 hours", + "1 day", + "2 days", + "3 days", + "1 week", +]; + +const CARD_KEEP_FROM_SOURCE_PROPERTIES = [ + "all", + "attachments", + "checklists", + "comments", + "due", + "labels", + "members", + "stickers", +]; + +export default { + POSITIONS, + CARD_FILTERS, + LIST_FILTERS, + POWER_UPS, + PREFS_PERMISSION_LEVELS, + PREFS_VOTING, + PREFS_COMMENTS, + PREFS_INVITATIONS, + PREFS_BACKGROUNDS, + PREFS_CARD_AGING, + LABEL_COLORS, + NOTIFICATION_TIMES, + CARD_KEEP_FROM_SOURCE_PROPERTIES, +}; diff --git a/components/trello/common/fields.mjs b/components/trello/common/fields.mjs index 7aea4568b90ab..678968a99d370 100644 --- a/components/trello/common/fields.mjs +++ b/components/trello/common/fields.mjs @@ -1,5 +1,6 @@ export default { board: [ + "all", "closed", "dateLastActivity", "dateLastView", diff --git a/components/trello/package.json b/components/trello/package.json index 68799271364e9..e2930002d5276 100644 --- a/components/trello/package.json +++ b/components/trello/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/trello", - "version": "0.4.0", + "version": "0.4.1", "description": "Pipedream Trello Components", "main": "trello.app.mjs", "keywords": [ @@ -14,6 +14,7 @@ "crypto": "^1.0.1", "form-data": "^4.0.0", "lodash-es": "^4.17.21", + "mime": "^4.0.4", "ms": "^2.1.3" }, "gitHead": "e12480b94cc03bed4808ebc6b13e7fdb3a1ba535", diff --git a/components/trello/sources/card-archived/card-archived.mjs b/components/trello/sources/card-archived/card-archived.mjs index 3a9a793eb5d25..f896f86c02785 100644 --- a/components/trello/sources/card-archived/card-archived.mjs +++ b/components/trello/sources/card-archived/card-archived.mjs @@ -1,11 +1,12 @@ import common from "../common/common-webhook.mjs"; +import sampleEmit from "./test-event.mjs"; export default { ...common, key: "trello-card-archived", - name: "Card Archived (Instant)", + name: "Card Archived (Instant)", /* eslint-disable-line pipedream/source-name */ description: "Emit new event for each card archived.", - version: "0.1.0", + version: "0.1.1", type: "source", props: { ...common.props, @@ -16,7 +17,6 @@ export default { ], }, lists: { - optional: true, propDefinition: [ common.props.app, "lists", @@ -24,47 +24,35 @@ export default { board: c.board, }), ], + description: "If specified, events will only be emitted when a card in one of the selected lists is archived", }, }, methods: { ...common.methods, - getFilteredCards({ - boardId, ...args - } = {}) { - return this.app._makeRequest({ - path: `/boards/${boardId}/cards`, - ...args, - }); - }, - async getSampleEvents() { - const cards = await this.getFilteredCards({ + getSampleEvents() { + return this.app.getFilteredCards({ boardId: this.board, - params: { - filter: "closed", - }, + filter: "closed", }); - return { - sampleEvents: cards, - sortField: "dateLastActivity", - }; }, - isCorrectEventType(event) { - const eventTranslationKey = event.body?.action?.display?.translationKey; - return eventTranslationKey === "action_archived_card"; + getSortField() { + return "dateLastActivity"; + }, + isCorrectEventType({ display }) { + return display?.translationKey === "action_archived_card"; }, - async getResult(event) { - const cardId = event.body?.action?.data?.card?.id; + getResult({ data }) { return this.app.getCard({ - cardId, + cardId: data?.card?.id, }); }, isRelevant({ result: card }) { return ( (!this.board || this.board === card.idBoard) && - (!this.lists || - this.lists.length === 0 || + (!this.lists?.length || this.lists.includes(card.idList)) ); }, }, + sampleEmit, }; diff --git a/components/trello/sources/card-archived/test-event.mjs b/components/trello/sources/card-archived/test-event.mjs new file mode 100644 index 0000000000000..df2857886721c --- /dev/null +++ b/components/trello/sources/card-archived/test-event.mjs @@ -0,0 +1,64 @@ +export default { + "id": "5f4ee830046a92139596173a", + "badges": { + "attachmentsByType": { + "trello": { + "board": 0, + "card": 0 + } + }, + "externalSource": null, + "location": false, + "votes": 0, + "viewingMemberVoted": false, + "subscribed": false, + "fogbugz": "", + "checkItems": 0, + "checkItemsChecked": 0, + "checkItemsEarliestDue": null, + "comments": 0, + "attachments": 0, + "description": false, + "due": null, + "dueComplete": false, + "start": null, + "lastUpdatedByAi": false + }, + "checkItemStates": [], + "closed": true, + "dueComplete": false, + "dateLastActivity": "2020-09-02T00:34:22.602Z", + "desc": "", + "descData": null, + "due": null, + "dueReminder": null, + "email": null, + "idBoard": "5f4d7be6c45c22583f75fa02", + "idChecklists": [], + "idList": "5f4d7f78bdd7ce4d2d25fdda", + "idMembers": [], + "idMembersVoted": [], + "idShort": 10, + "idAttachmentCover": null, + "labels": [], + "idLabels": [], + "manualCoverAttachment": false, + "name": "a new card", + "pinned": false, + "pos": 65535, + "shortLink": "eBapV0gL", + "shortUrl": "https://trello.com/c/eBapV0gL", + "start": null, + "subscribed": false, + "url": "https://trello.com/c/eBapV0gL/10-a-new-card", + "cover": { + "idAttachment": null, + "color": null, + "idUploadedBackground": null, + "size": "normal", + "brightness": "light", + "idPlugin": null + }, + "isTemplate": false, + "cardRole": null +} \ No newline at end of file diff --git a/components/trello/sources/card-due-date-reminder/card-due-date-reminder.mjs b/components/trello/sources/card-due-date-reminder/card-due-date-reminder.mjs index 6e7638180213d..67dfa5eb90fb4 100644 --- a/components/trello/sources/card-due-date-reminder/card-due-date-reminder.mjs +++ b/components/trello/sources/card-due-date-reminder/card-due-date-reminder.mjs @@ -1,19 +1,24 @@ +import taskScheduler from "../../../pipedream/sources/new-scheduled-tasks/new-scheduled-tasks.mjs"; +import trello from "../../trello.app.mjs"; import ms from "ms"; -import common from "../common/common-polling.mjs"; +import constants from "../../common/constants.mjs"; +import sampleEmit from "./test-event.mjs"; export default { - ...common, key: "trello-card-due-date-reminder", - name: "Card Due Date Reminder", + name: "Card Due Date Reminder", /* eslint-disable-line pipedream/source-name */ description: "Emit new event at a specified time before a card is due.", - version: "0.1.0", + version: "0.1.1", type: "source", dedupe: "unique", props: { - ...common.props, + pipedream: taskScheduler.props.pipedream, + trello, + db: "$.service.db", + http: "$.interface.http", board: { propDefinition: [ - common.props.app, + trello, "board", ], }, @@ -22,25 +27,43 @@ export default { label: "Time Before", description: "How far before the due time the event should trigger. For example, `5 minutes`, `10 minutes`, `1 hour`.", default: "5 minutes", - options: [ - "5 minutes", - "10 minutes", - "15 minutes", - "30 minutes", - "1 hour", - "2 hours", - "3 hours", - "6 hours", - "12 hours", - "1 day", - "2 days", - "3 days", - "1 week", - ], + options: constants.NOTIFICATION_TIMES, + reloadProps: true, + }, + }, + async additionalProps() { + const props = {}; + if (this.timeBefore) { + props.timer = { + type: "$.interface.timer", + description: "Poll the API to schedule alerts for any newly created events", + default: { + intervalSeconds: ms(this.timeBefore) / 1000, + }, + }; + } + return props; + }, + hooks: { + async deactivate() { + const ids = this._getScheduledEventIds(); + if (!ids?.length) { + return; + } + for (const id of ids) { + if (await this.deleteEvent({ + body: { + id, + }, + })) { + console.log("Cancelled scheduled event"); + } + } + this._setScheduledEventIds(); }, }, methods: { - ...common.methods, + ...taskScheduler.methods, generateMeta({ id, name: summary, }, now) { @@ -50,32 +73,87 @@ export default { ts: now, }; }, + _getScheduledEventIds() { + return this.db.get("scheduledEventIds"); + }, + _setScheduledEventIds(ids) { + this.db.set("scheduledEventIds", ids); + }, + _getScheduledCardIds() { + return this.db.get("scheduledCardIds"); + }, + _setScheduledCardIds(ids) { + this.db.set("scheduledCardIds", ids); + }, + _hasDeployed() { + const result = this.db.get("hasDeployed"); + this.db.set("hasDeployed", true); + return result; + }, emitEvent(card, now) { const meta = this.generateMeta(card, now); this.$emit(card, meta); }, }, async run(event) { - const boardId = this.board; const now = event.timestamp * 1000; - const timeBeforeMs = ms(this.timeBefore); - if (!timeBeforeMs) { - throw new Error(`Invalid timeBefore value: ${this.timeBefore}`); + // self subscribe only on the first time + if (!this._hasDeployed()) { + await this.selfSubscribe(); + } + + let scheduledEventIds = this._getScheduledEventIds() || []; + + // incoming scheduled event + if (event.$channel === this.selfChannel()) { + const remainingScheduledEventIds = scheduledEventIds.filter((id) => id !== event["$id"]); + this._setScheduledEventIds(remainingScheduledEventIds); + this.emitEvent(event, now); + return; } - const cards = await this.app.getCards({ - boardId, + // schedule new events + const scheduledCardIds = this._getScheduledCardIds() || {}; + const cards = await this.trello.getCards({ + boardId: this.board, }); + for (const card of cards) { - if (!card.due) { + const dueDate = card.due + ? new Date(card.due) + : null; + if (!dueDate || dueDate.getTime() < Date.now()) { + delete scheduledCardIds[card.id]; continue; } - const due = Date.parse(card.due); - const notifyAt = due - timeBeforeMs; - if (notifyAt <= now) { - this.emitEvent(card, now); + + const later = new Date(dueDate.getTime() - ms(this.timeBefore)); + + if (scheduledCardIds[card.id]) { + // reschedule if card's due date has changed + if (card.due !== scheduledCardIds[card.id].dueDate) { + await this.deleteEvent({ + body: { + id: scheduledCardIds[card.id].eventId, + }, + }); + scheduledEventIds = scheduledEventIds + .filter((id) => id !== scheduledCardIds[card.id].eventId); + } else { + continue; + } } + + const scheduledEventId = this.emitScheduleEvent(card, later); + scheduledEventIds.push(scheduledEventId); + scheduledCardIds[card.id] = { + eventId: scheduledEventId, + dueDate: card.due, + }; } + this._setScheduledEventIds(scheduledEventIds); + this._setScheduledCardIds(scheduledCardIds); }, + sampleEmit, }; diff --git a/components/trello/sources/card-due-date-reminder/test-event.mjs b/components/trello/sources/card-due-date-reminder/test-event.mjs new file mode 100644 index 0000000000000..35b396b457bda --- /dev/null +++ b/components/trello/sources/card-due-date-reminder/test-event.mjs @@ -0,0 +1,75 @@ +export default { + "id": "61818a303e545129af23695d", + "badges": { + "attachmentsByType": { + "trello": { + "board": 0, + "card": 0 + } + }, + "externalSource": null, + "location": false, + "votes": 0, + "viewingMemberVoted": false, + "subscribed": true, + "fogbugz": "", + "checkItems": 1, + "checkItemsChecked": 1, + "checkItemsEarliestDue": null, + "comments": 2, + "attachments": 1, + "description": false, + "due": "2024-10-01T19:20:00.000Z", + "dueComplete": false, + "start": null, + "lastUpdatedByAi": false + }, + "checkItemStates": [ + { + "idCheckItem": "6181a5f18e239e6aff9799a4", + "state": "complete" + } + ], + "closed": false, + "dueComplete": false, + "dateLastActivity": "2024-10-01T19:08:51.312Z", + "desc": "", + "descData": { + "emoji": {} + }, + "due": "2024-10-01T19:20:00.000Z", + "dueReminder": -1, + "email": null, + "idBoard": "5f4d7be6c45c22583f75fa02", + "idChecklists": [ + "6181a5ef401ae66c357732b4" + ], + "idList": "5f4d7f78bdd7ce4d2d25fdda", + "idMembers": [], + "idMembersVoted": [], + "idShort": 68, + "idAttachmentCover": "62c884dce32d46579ecfd5f0", + "labels": [], + "idLabels": [], + "manualCoverAttachment": false, + "name": "test", + "pinned": false, + "pos": 131071, + "shortLink": "QVLahShU", + "shortUrl": "https://trello.com/c/QVLahShU", + "start": null, + "subscribed": true, + "url": "https://trello.com/c/QVLahShU/68-sfsfdsfd", + "cover": { + "idAttachment": "62c884dce32d46579ecfd5f0", + "color": null, + "idUploadedBackground": null, + "size": "normal", + "brightness": "dark", + "idPlugin": null + }, + "isTemplate": false, + "cardRole": null, + "$channel": "self", + "$id": "62377726-40b9-41a8-85c7-b01f3f5f8fbe" +} \ No newline at end of file diff --git a/components/trello/sources/card-moved/card-moved.mjs b/components/trello/sources/card-moved/card-moved.mjs index a6f03826eec10..39fa97d34d5e0 100644 --- a/components/trello/sources/card-moved/card-moved.mjs +++ b/components/trello/sources/card-moved/card-moved.mjs @@ -1,11 +1,12 @@ import common from "../common/common-webhook.mjs"; +import sampleEmit from "./test-event.mjs"; export default { ...common, key: "trello-card-moved", - name: "Card Moved (Instant)", + name: "Card Moved (Instant)", /* eslint-disable-line pipedream/source-name */ description: "Emit new event each time a card is moved to a list.", - version: "0.1.0", + version: "0.1.1", type: "source", props: { ...common.props, @@ -23,22 +24,23 @@ export default { board: c.board, }), ], + description: "If specified, events will only be emitted if a card is moved to or from one of the selected lists", }, }, methods: { ...common.methods, async getSampleEvents() { - const cards = this.lists && this.lists.length > 0 + const cards = this.lists?.length > 0 ? await this.app.getCardsInList({ listId: this.lists[0], }) : await this.app.getCards({ boardId: this.board, }); - return { - sampleEvents: cards, - sortFilter: "dateLastActivity", - }; + return cards; + }, + getSortField() { + return "dateLastActivity"; }, _getListAfter() { return this.db.get("listAfter"); @@ -46,37 +48,31 @@ export default { _setListAfter(listAfter) { this.db.set("listAfter", listAfter); }, - isCorrectEventType(event) { - const eventTranslationKey = event.body?.action?.display?.translationKey; - return eventTranslationKey === "action_move_card_from_list_to_list"; + isCorrectEventType({ display }) { + return display?.translationKey === "action_move_card_from_list_to_list"; }, - async getResult(event) { - const cardId = event.body?.action?.data?.card?.id; - const listAfter = event.body?.action?.data?.listAfter?.name; + getResult({ data }) { /** Record listAfter to use in generateMeta() */ - this._setListAfter(listAfter); + this._setListAfter(data?.listAfter?.name); return this.app.getCard({ - cardId, + cardId: data?.card?.id, }); }, isRelevant({ - result: card, event, + result: card, action, }) { - const listIdAfter = event.body?.action?.data?.listAfter?.id; - const listIdBefore = event.body?.action?.data?.listBefore?.id; - return ( (!this.board || this.board === card.idBoard) && - (!this.lists || - this.lists.length === 0 || - this.lists.includes(listIdAfter) || - this.lists.includes(listIdBefore)) + (!this.lists?.length || + this.lists.includes(action?.data?.listAfter?.id) || + this.lists.includes(action?.data?.listBefore?.id)) ); }, generateMeta({ id, name, }) { const listAfter = this._getListAfter(); + name = name || id; const summary = listAfter ? `${name} - moved to ${listAfter}` : name; @@ -87,4 +83,5 @@ export default { }; }, }, + sampleEmit, }; diff --git a/components/trello/sources/card-moved/test-event.mjs b/components/trello/sources/card-moved/test-event.mjs new file mode 100644 index 0000000000000..44bc71e5f5b79 --- /dev/null +++ b/components/trello/sources/card-moved/test-event.mjs @@ -0,0 +1,78 @@ +export default { + "id": "60836bac2ed2ef78f4cf850d", + "badges": { + "attachmentsByType": { + "trello": { + "board": 0, + "card": 0 + } + }, + "externalSource": null, + "location": false, + "votes": 0, + "viewingMemberVoted": false, + "subscribed": true, + "fogbugz": "", + "checkItems": 1, + "checkItemsChecked": 0, + "checkItemsEarliestDue": null, + "comments": 3, + "attachments": 1, + "description": false, + "due": "2021-05-10T21:50:00.000Z", + "dueComplete": false, + "start": null, + "lastUpdatedByAi": false + }, + "checkItemStates": [], + "closed": false, + "dueComplete": false, + "dateLastActivity": "2021-11-02T23:02:44.876Z", + "desc": "", + "descData": null, + "due": "2021-05-10T21:50:00.000Z", + "dueReminder": 1440, + "email": null, + "idBoard": "5f4d7be6c45c22583f75fa02", + "idChecklists": [ + "608b2037ea7ac07da59c17be" + ], + "idList": "5f4ec9f69028408fed04c0b1", + "idMembers": [], + "idMembersVoted": [], + "idShort": 54, + "idAttachmentCover": "6099aece406c0b7a97e71535", + "labels": [ + { + "id": "608b2273586147300cc73046", + "idBoard": "5f4d7be6c45c22583f75fa02", + "idOrganization": "6047c17c2f558003144e04d7", + "name": "orange", + "nodeId": "ari:cloud:trello::label/workspace/6047c17c2f558003144e04d7/608b2273586147300cc73046", + "color": "orange", + "uses": 4 + }, + ], + "idLabels": [ + "608b2273586147300cc73046", + ], + "manualCoverAttachment": false, + "name": "new card", + "pinned": false, + "pos": 655359, + "shortLink": "fo2GH2y2", + "shortUrl": "https://trello.com/c/fo2GH2y2", + "start": null, + "subscribed": true, + "url": "https://trello.com/c/fo2GH2y2/54-new-card", + "cover": { + "idAttachment": "6099aece406c0b7a97e71535", + "color": null, + "idUploadedBackground": null, + "size": "normal", + "brightness": "dark", + "idPlugin": null + }, + "isTemplate": false, + "cardRole": null +} \ No newline at end of file diff --git a/components/trello/sources/card-updates/card-updates.mjs b/components/trello/sources/card-updates/card-updates.mjs index 8dc0abdc27dea..f83712527f312 100644 --- a/components/trello/sources/card-updates/card-updates.mjs +++ b/components/trello/sources/card-updates/card-updates.mjs @@ -1,11 +1,12 @@ import common from "../common/common-webhook.mjs"; +import sampleEmit from "./test-event.mjs"; export default { ...common, key: "trello-card-updates", - name: "Card Updates (Instant)", + name: "Card Updated (Instant)", /* eslint-disable-line pipedream/source-name */ description: "Emit new event for each update to a Trello card.", - version: "0.1.0", + version: "0.1.1", type: "source", props: { ...common.props, @@ -24,58 +25,50 @@ export default { }), ], }, - customFieldItems: { - propDefinition: [ - common.props.app, - "customFieldItems", - ], - }, }, methods: { ...common.methods, async getSampleEvents() { let cards = []; - if (this.cards && this.cards.length > 0) { + const params = { + customFieldItems: true, + }; + if (this.cards?.length > 0) { for (const cardId of this.cards) { const card = await this.app.getCard({ cardId, - params: { - customFieldItems: this.customFieldItems, - }, + params, }); cards.push(card); } } else { cards = await this.app.getCards({ boardId: this.board, - params: { - customFieldItems: this.customFieldItems, - }, + params, }); } - return { - sampleEvents: cards, - sortField: "dateLastActivity", - }; + return cards; + }, + getSortField() { + return "dateLastActivity"; }, - isCorrectEventType(event) { - const eventType = event.body?.action?.type; - return eventType === "updateCard"; + isCorrectEventType({ type }) { + return type === "updateCard"; }, - async getResult(event) { - const cardId = event.body?.action?.data?.card?.id; + getResult({ data }) { return this.app.getCard({ - cardId, + cardId: data?.card?.id, params: { - customFieldItems: this.customFieldItems, + customFieldItems: true, }, }); }, isRelevant({ result: card }) { return ( (!this.board || this.board === card.idBoard) && - (!this.cards || this.cards.length === 0 || this.cards.includes(card.id)) + (!this.cards?.length || this.cards.includes(card.id)) ); }, }, + sampleEmit, }; diff --git a/components/trello/sources/card-updates/test-event.mjs b/components/trello/sources/card-updates/test-event.mjs new file mode 100644 index 0000000000000..e40f64d7737d3 --- /dev/null +++ b/components/trello/sources/card-updates/test-event.mjs @@ -0,0 +1,86 @@ +export default { + "id": "620eb14ebda9570d72fddead", + "badges": { + "attachmentsByType": { + "trello": { + "board": 0, + "card": 0 + } + }, + "externalSource": null, + "location": false, + "votes": 0, + "viewingMemberVoted": false, + "subscribed": false, + "fogbugz": "", + "checkItems": 1, + "checkItemsChecked": 1, + "checkItemsEarliestDue": null, + "comments": 3, + "attachments": 1, + "description": false, + "due": "2021-05-10T21:50:00.000Z", + "dueComplete": false, + "start": null, + "lastUpdatedByAi": false + }, + "checkItemStates": [ + { + "idCheckItem": "620eb14fbda9570d72fde031", + "state": "complete" + } + ], + "closed": false, + "dueComplete": false, + "dateLastActivity": "2024-09-30T16:31:35.215Z", + "desc": "", + "descData": { + "emoji": {} + }, + "due": "2021-05-10T21:50:00.000Z", + "dueReminder": null, + "email": null, + "idBoard": "5f4d7be6c45c22583f75fa02", + "idChecklists": [ + "620eb14fbda9570d72fde030" + ], + "idList": "5f4d7f78bdd7ce4d2d25fdda", + "idMembers": [], + "idMembersVoted": [], + "idShort": 85, + "idAttachmentCover": "620eb14ebda9570d72fdded7", + "labels": [ + { + "id": "5f4d7be6cdabcf46c027c792", + "idBoard": "5f4d7be6c45c22583f75fa02", + "idOrganization": "6047c17c2f558003144e04d7", + "name": "green label", + "nodeId": "ari:cloud:trello::label/workspace/6047c17c2f558003144e04d7/5f4d7be6cdabcf46c027c792", + "color": "green", + "uses": 9 + }, + ], + "idLabels": [ + "5f4d7be6cdabcf46c027c792", + ], + "manualCoverAttachment": false, + "name": "new card", + "pinned": false, + "pos": 360447, + "shortLink": "dho6bOdR", + "shortUrl": "https://trello.com/c/dho6bOdR", + "start": null, + "subscribed": false, + "url": "https://trello.com/c/dho6bOdR/85-new-card", + "cover": { + "idAttachment": "620eb14ebda9570d72fdded7", + "color": null, + "idUploadedBackground": null, + "size": "normal", + "brightness": "dark", + "idPlugin": null + }, + "isTemplate": false, + "cardRole": null, + "customFieldItems": [] +} \ No newline at end of file diff --git a/components/trello/sources/common/actions.mjs b/components/trello/sources/common/actions.mjs new file mode 100644 index 0000000000000..2f30e5e0d0950 --- /dev/null +++ b/components/trello/sources/common/actions.mjs @@ -0,0 +1,206 @@ +export default [ + { + label: "Accept Enterprise Join Request", + value: "acceptEnterpriseJoinRequest", + }, + { + label: "Add Attachment To Card", + value: "addAttachmentToCard", + }, + { + label: "Add Checklist To Card", + value: "addChecklistToCard", + }, + { + label: "Add Member To Board", + value: "addMemberToBoard", + }, + { + label: "Add Member To Card", + value: "addMemberToCard", + }, + { + label: "Add Member To Organization", + value: "addMemberToOrganization", + }, + { + label: "Add Organization To Enterprise", + value: "addOrganizationToEnterprise", + }, + { + label: "Add To Enterprise Plugin Whitelist", + value: "addToEnterprisePluginWhitelist", + }, + { + label: "Add To Organization Board", + value: "addToOrganizationBoard", + }, + { + label: "Comment Card", + value: "commentCard", + }, + { + label: "Convert To Card From Check Item", + value: "convertToCardFromCheckItem", + }, + { + label: "Copy Board", + value: "copyBoard", + }, + { + label: "Copy Card", + value: "copyCard", + }, + { + label: "Copy Comment Card", + value: "copyCommentCard", + }, + { + label: "Create Board", + value: "createBoard", + }, + { + label: "Create Card", + value: "createCard", + }, + { + label: "Create List", + value: "createList", + }, + { + label: "Create Organization", + value: "createOrganization", + }, + { + label: "Delete Board Invitation", + value: "deleteBoardInvitation", + }, + { + label: "Delete Card", + value: "deleteCard", + }, + { + label: "Delete Organization Invitation", + value: "deleteOrganizationInvitation", + }, + { + label: "Disable Enterprise Plugin Whitelist", + value: "disableEnterprisePluginWhitelist", + }, + { + label: "Disable Plugin", + value: "disablePlugin", + }, + { + label: "Disable Power Up", + value: "disablePowerUp", + }, + { + label: "Email Card", + value: "emailCard", + }, + { + label: "Enable Enterprise Plugin Whitelist", + value: "enableEnterprisePluginWhitelist", + }, + { + label: "Enable Plugin", + value: "enablePlugin", + }, + { + label: "Enable Power Up", + value: "enablePowerUp", + }, + { + label: "Make Admin Of Board", + value: "makeAdminOfBoard", + }, + { + label: "Make Normal Member Of Board", + value: "makeNormalMemberOfBoard", + }, + { + label: "Make Normal Member Of Organization", + value: "makeNormalMemberOfOrganization", + }, + { + label: "Make Observer Of Board", + value: "makeObserverOfBoard", + }, + { + label: "Member Joined Trello", + value: "memberJoinedTrello", + }, + { + label: "Move Card From Board", + value: "moveCardFromBoard", + }, + { + label: "Move Card To Board", + value: "moveCardToBoard", + }, + { + label: "Move List From Board", + value: "moveListFromBoard", + }, + { + label: "Move List To Board", + value: "moveListToBoard", + }, + { + label: "Remove Checklist From Card", + value: "removeChecklistFromCard", + }, + { + label: "Remove From Enterprise Plugin Whitelist", + value: "removeFromEnterprisePluginWhitelist", + }, + { + label: "Remove From Organization Board", + value: "removeFromOrganizationBoard", + }, + { + label: "Remove Member From Card", + value: "removeMemberFromCard", + }, + { + label: "Remove Organization From Enterprise", + value: "removeOrganizationFromEnterprise", + }, + { + label: "Unconfirmed Board Invitation", + value: "unconfirmedBoardInvitation", + }, + { + label: "Unconfirmed Organization Invitation", + value: "unconfirmedOrganizationInvitation", + }, + { + label: "Update Board", + value: "updateBoard", + }, + { + label: "Update Card", + value: "updateCard", + }, + { + label: "Update Check Item State On Card", + value: "updateCheckItemStateOnCard", + }, + { + label: "Update Checklist", + value: "updateChecklist", + }, + { + label: "Update List", + value: "updateList", + }, + { + label: "Update Member", + value: "updateMember", + }, + { + label: "Update Organization", + value: "updateOrganization", + }, +]; diff --git a/components/trello/sources/common/common-board-based.mjs b/components/trello/sources/common/common-board-based.mjs index f200f0e3216ab..a2b4de682973b 100644 --- a/components/trello/sources/common/common-board-based.mjs +++ b/components/trello/sources/common/common-board-based.mjs @@ -14,7 +14,7 @@ export default { ], }, onlyEventsRelatedWithAuthenticatedUser: { - label: "Only Events Related With Me", + label: "Only Events Related To Me", description: "Only will emit events from the cards related with the authenticated user", type: "boolean", default: false, @@ -32,19 +32,24 @@ export default { return false; } + if (this.lists?.length) { + const list = await this.app.getCardList({ + cardId: result.idCard, + }); + if (!this.lists.includes(list.id)) { + return false; + } + } + const member = await this.app.getMember({ memberId: "me", }); - if ( + return !( this.onlyEventsRelatedWithAuthenticatedUser && result?.idMembers?.length && !result.idMembers.includes(member.id) - ) { - return false; - } - - return true; + ); }, }, }; diff --git a/components/trello/sources/common/common-webhook.mjs b/components/trello/sources/common/common-webhook.mjs index 955f74f169070..a209c1aaf8baf 100644 --- a/components/trello/sources/common/common-webhook.mjs +++ b/components/trello/sources/common/common-webhook.mjs @@ -9,12 +9,9 @@ export default { }, hooks: { async deploy() { - const { - sampleEvents, sortField, - } = await this.getSampleEvents(); - sampleEvents.sort((a, b) => (Date.parse(a[sortField]) > Date.parse(b[sortField])) - ? 1 - : -1); + let sampleEvents = await this.getSampleEvents(); + const sortField = this.getSortField(); + sampleEvents = this.sortItemsByDate(sampleEvents, sortField); for (const event of sampleEvents.slice(-25)) { this.emitEvent(event); } @@ -28,17 +25,25 @@ export default { callbackURL: this.http.endpoint, }, }); - this.db.set("hookId", id); + this._setHookId(id); }, async deactivate() { - const hookId = this.db.get("hookId"); - await this.deleteHook({ - hookId, - }); + const hookId = this._getHookId(); + if (hookId) { + await this.deleteHook({ + hookId, + }); + } }, }, methods: { ...common.methods, + _getHookId() { + return this.db.get("hookId"); + }, + _setHookId(hookId) { + this.db.set("hookId", hookId); + }, getBase64Digest(data) { const { secret } = this.app.getToken(); return createHmac("sha1", secret) @@ -57,7 +62,6 @@ export default { createHook(args = {}) { return this.app.post({ ...args, - debug: true, path: "/webhooks/", }); }, @@ -66,7 +70,6 @@ export default { } = {}) { return this.app.delete({ ...args, - debug: true, path: `/webhooks/${hookId}`, }); }, @@ -97,9 +100,15 @@ export default { isRelevant() { return true; }, + getResult(action) { + return action; + }, getSampleEvents() { throw new Error("getSampleEvents not implemented"); }, + getSortField() { + throw new Error("getSortField is not implemented"); + }, }, async run(event) { if (event.body === undefined) { @@ -112,15 +121,17 @@ export default { return; } - if (!this.isCorrectEventType(event)) { + const { action } = event.body; + + if (!this.isCorrectEventType(action)) { console.log("The event is not of the correct type. Skipping..."); return; } - const result = await this.getResult(event); + const result = await this.getResult(action); const isRelevant = await this.isRelevant({ result, - event, + action, }); if (!isRelevant) { diff --git a/components/trello/sources/common/common.mjs b/components/trello/sources/common/common.mjs index 4beadb003d495..60cb5533fe07c 100644 --- a/components/trello/sources/common/common.mjs +++ b/components/trello/sources/common/common.mjs @@ -13,11 +13,11 @@ export default { * @param {string} name - The name of the item of the book. */ generateMeta({ - id, name: summary, + id, name, }) { return { id, - summary, + summary: name || `${id}`, ts: Date.now(), }; }, @@ -30,5 +30,8 @@ export default { const meta = this.generateMeta(result); this.$emit(result, meta); }, + sortItemsByDate(items, sortField) { + return items.sort((a, b) => (Date.parse(a[sortField]) > Date.parse(b[sortField]))); + }, }, }; diff --git a/components/trello/sources/custom-webhook-events/custom-webhook-events.mjs b/components/trello/sources/custom-webhook-events/custom-webhook-events.mjs index 7270389de9a46..1ac3ca59b941e 100644 --- a/components/trello/sources/custom-webhook-events/custom-webhook-events.mjs +++ b/components/trello/sources/custom-webhook-events/custom-webhook-events.mjs @@ -4,9 +4,9 @@ import events from "../common/events.mjs"; export default { ...common, key: "trello-custom-webhook-events", - name: "Custom Webhook Events (Instant)", + name: "Custom Webhook Events (Instant)", /* eslint-disable-line pipedream/source-name */ description: "Emit new events for activity matching a board, event types, lists and/or cards.", - version: "0.1.0", + version: "0.1.1", type: "source", props: { ...common.props, @@ -42,59 +42,29 @@ export default { ], }, }, - hooks: { - ...common.hooks, - async deploy() { - const { - sampleEvents, sortField, - } = await this.getSampleEvents(); - sampleEvents.sort((a, b) => (Date.parse(a[sortField]) > Date.parse(b[sortField])) - ? 1 - : -1); - for (const action of sampleEvents.slice(-25)) { - this.emitEvent({ - action, - }); - } - }, - }, methods: { ...common.methods, - getCardList({ - cardId, ...args - } = {}) { - return this.app._makeRequest({ - path: `/cards/${cardId}/list`, - ...args, - }); - }, - async getSampleEvents() { - const eventTypes = this.eventTypes && this.eventTypes.length > 0 + getSampleEvents() { + const eventTypes = this.eventTypes?.length ? this.eventTypes.join(",") : null; - const actions = await this.app.getBoardActivity({ + return this.app.getBoardActivity({ boardId: this.board, params: { filter: eventTypes, }, }); - return { - sampleEvents: actions, - sortField: "date", - }; }, - isCorrectEventType(event) { - const eventType = event.body?.action?.type; + getSortField() { + return "date"; + }, + isCorrectEventType({ type }) { return ( - (eventType) && - (!this.eventTypes || - this.eventTypes.length === 0 || - this.eventTypes.includes(eventType)) + (type) && + (!this.eventTypes?.length || + this.eventTypes.includes(type)) ); }, - async getResult(event) { - return event.body; - }, async isRelevant({ result: body }) { let listId = body.action?.data?.list?.id; const cardId = body.action?.data?.card?.id; @@ -106,22 +76,21 @@ export default { listId = res.id; } return ( - (!this.lists || - this.lists.length === 0 || + (!this.lists?.length || !listId || this.lists.includes(listId)) && - (!this.cards || this.cards.length === 0 || !cardId || this.cards.includes(cardId)) + (!this.cards?.length || !cardId || this.cards.includes(cardId)) ); }, - generateMeta({ action }) { + generateMeta(action) { const { id, - type: summary, + type, date, } = action; return { id, - summary, + summary: `New ${type} event`, ts: Date.parse(date), }; }, diff --git a/components/trello/sources/new-activity/new-activity.mjs b/components/trello/sources/new-activity/new-activity.mjs index 379178942976d..194c848dffdfe 100644 --- a/components/trello/sources/new-activity/new-activity.mjs +++ b/components/trello/sources/new-activity/new-activity.mjs @@ -1,11 +1,12 @@ import common from "../common/common-webhook.mjs"; +import actions from "../common/actions.mjs"; export default { ...common, key: "trello-new-activity", - name: "New Activity (Instant)", + name: "New Board Activity (Instant)", description: "Emit new event for new activity on a board.", - version: "0.1.0", + version: "0.1.1", type: "source", props: { ...common.props, @@ -15,50 +16,40 @@ export default { "board", ], }, - }, - hooks: { - ...common.hooks, - async deploy() { - const { - sampleEvents, sortField, - } = await this.getSampleEvents(); - sampleEvents.sort((a, b) => (Date.parse(a[sortField]) > Date.parse(b[sortField])) - ? 1 - : -1); - for (const action of sampleEvents.slice(-25)) { - this.emitEvent({ - action, - }); - } + activityTypes: { + type: "string[]", + label: "Activity Types", + description: "Filter incoming events by the activity type", + options: actions, + optional: true, }, }, methods: { ...common.methods, - async getSampleEvents() { - const actions = await this.app.getBoardActivity({ + getSampleEvents() { + return this.app.getBoardActivity({ boardId: this.board, }); - return { - sampleEvents: actions, - sortField: "date", - }; }, - async getResult(event) { - return event.body; + getSortField() { + return "date"; }, - isRelevant({ event }) { - const boardId = event.body?.action?.data?.board?.id; - return !this.board || this.board === boardId; + isRelevant({ action }) { + const { + data, type, + } = action; + return ((!this.board || this.board === data?.board?.id) + && (!this.activityTypes?.length || this.activityTypes.includes(type))); }, - generateMeta({ action }) { + generateMeta(action) { const { id, - type: summary, + type, date, } = action; return { id, - summary, + summary: `New ${type} activity`, ts: Date.parse(date), }; }, diff --git a/components/trello/sources/new-attachment/new-attachment.mjs b/components/trello/sources/new-attachment/new-attachment.mjs index b20c4432d97da..ba77abdfe961c 100644 --- a/components/trello/sources/new-attachment/new-attachment.mjs +++ b/components/trello/sources/new-attachment/new-attachment.mjs @@ -1,11 +1,12 @@ import common from "../common/common-webhook.mjs"; +import sampleEmit from "./test-event.mjs"; export default { ...common, key: "trello-new-attachment", name: "New Attachment (Instant)", - description: "Emit new event for new attachment on a board.", - version: "0.1.0", + description: "Emit new event when a new attachment is added on a board.", + version: "0.1.1", type: "source", props: { ...common.props, @@ -15,62 +16,52 @@ export default { "board", ], }, - }, - hooks: { - ...common.hooks, - async deploy() { - const { - sampleEvents, sortField, - } = await this.getSampleEvents(); - sampleEvents.sort((a, b) => (Date.parse(a[sortField]) > Date.parse(b[sortField])) - ? 1 - : -1); - for (const action of sampleEvents.slice(-25)) { - this.$emit(action, { - id: action.id, - summary: action?.data?.attachment?.name, - ts: Date.parse(action.date), - }); - } + lists: { + propDefinition: [ + common.props.app, + "lists", + (c) => ({ + board: c.board, + }), + ], + description: "If specified, events will only be emitted when an attachment is added to a card in one of the specified lists", }, }, methods: { ...common.methods, - getAttachment({ - cardId, attachmentId, ...args - } = {}) { - return this.app._makeRequest({ - path: `/cards/${cardId}/attachments/${attachmentId}`, - ...args, - }); - }, async getSampleEvents() { - const actions = await this.app.getBoardActivity({ - boardId: this.board, - params: { - filter: "addAttachmentToCard", - }, - }); - return { - sampleEvents: actions, - sortField: "date", - }; + const cards = this.lists?.length + ? await this.app.getCardsInList({ + listId: this.lists[0], + }) + : await this.app.getCards({ + boardId: this.board, + }); + const attachments = []; + for (const card of cards) { + const cardAttachments = await this.app.listCardAttachments({ + cardId: card.id, + }); + attachments.push(...cardAttachments); + } + return attachments; + }, + getSortField() { + return "date"; }, - isCorrectEventType(event) { - const eventType = event.body?.action?.type; - return eventType === "addAttachmentToCard"; + isCorrectEventType({ type }) { + return type === "addAttachmentToCard"; }, - async getResult(event) { - const cardId = event.body?.action?.data?.card?.id; - const attachmentId = event.body?.action?.data?.attachment?.id; - return this.getAttachment({ - cardId, - attachmentId, + getResult({ data }) { + return this.app.getAttachment({ + cardId: data?.card?.id, + attachmentId: data?.attachment?.id, }); }, - isRelevant({ event }) { - const boardId = event.body?.action?.data?.board?.id; - return !this.board || this.board === boardId; + isRelevant({ action }) { + return (!this.board || this.board === action?.data?.board?.id) + && (!this.lists?.length || this.lists.includes(action?.data?.list?.id)); }, }, + sampleEmit, }; diff --git a/components/trello/sources/new-attachment/test-event.mjs b/components/trello/sources/new-attachment/test-event.mjs new file mode 100644 index 0000000000000..c513590937437 --- /dev/null +++ b/components/trello/sources/new-attachment/test-event.mjs @@ -0,0 +1,69 @@ +export default { + "id": "608b1310a52eed3b040d98ca", + "bytes": 18820, + "date": "2021-04-29T20:12:00.760Z", + "edgeColor": "#bbac9c", + "idMember": "5df149d4fa80be39e64c9a43", + "isUpload": true, + "mimeType": "image/jpeg", + "name": "meowsalot.jpg", + "previews": [ + { + "id": "608b1311a52eed3b040d98d6", + "_id": "608b1311a52eed3b040d98d6", + "scaled": false, + "url": "", + "bytes": 1649, + "height": 50, + "width": 70 + }, + { + "id": "608b1311a52eed3b040d98d7", + "_id": "608b1311a52eed3b040d98d7", + "scaled": false, + "url": "", + "bytes": 9598, + "height": 150, + "width": 250 + }, + { + "id": "608b1311a52eed3b040d98d8", + "_id": "608b1311a52eed3b040d98d8", + "scaled": true, + "url": "", + "bytes": 4508, + "height": 98, + "width": 150 + }, + { + "id": "608b1311a52eed3b040d98d9", + "_id": "608b1311a52eed3b040d98d9", + "scaled": true, + "url": "", + "bytes": 13736, + "height": 195, + "width": 300 + }, + { + "id": "608b1311a52eed3b040d98da", + "_id": "608b1311a52eed3b040d98da", + "scaled": true, + "url": "", + "bytes": 20289, + "height": 260, + "width": 400 + }, + { + "id": "608b1311a52eed3b040d98db", + "_id": "608b1311a52eed3b040d98db", + "scaled": false, + "url": "", + "bytes": 18820, + "height": 260, + "width": 400 + } + ], + "url": "", + "pos": 16384, + "fileName": "meowsalot.jpg" +} \ No newline at end of file diff --git a/components/trello/sources/new-board/new-board.mjs b/components/trello/sources/new-board/new-board.mjs index 30142c1740e33..147da5547d22d 100644 --- a/components/trello/sources/new-board/new-board.mjs +++ b/components/trello/sources/new-board/new-board.mjs @@ -1,31 +1,38 @@ import common from "../common/common-webhook.mjs"; +import sampleEmit from "./test-event.mjs"; export default { ...common, key: "trello-new-board", name: "New Board (Instant)", description: "Emit new event for each new board added.", - version: "0.1.0", + version: "0.1.1", type: "source", dedupe: "unique", methods: { ...common.methods, async getSampleEvents() { const boards = await this.app.getBoards(); - return { - sampleEvents: boards, - sortField: "dateLastView", - }; + const allBoards = []; + for (const board of boards) { + const b = await this.app.getBoard({ + boardId: board.id, + }); + allBoards.push(b); + } + return allBoards; }, - isCorrectEventType(event) { - const eventType = event.body?.action?.type; - return eventType === "createBoard"; + getSortField() { + return "dateLastView"; }, - async getResult(event) { - const boardId = event.body?.action?.data?.board?.id; + isCorrectEventType({ type }) { + return type === "createBoard"; + }, + getResult({ data }) { return this.app.getBoard({ - boardId, + boardId: data?.board?.id, }); }, }, + sampleEmit, }; diff --git a/components/trello/sources/new-board/test-event.mjs b/components/trello/sources/new-board/test-event.mjs new file mode 100644 index 0000000000000..8ba2d6bd2397d --- /dev/null +++ b/components/trello/sources/new-board/test-event.mjs @@ -0,0 +1,100 @@ +export default { + "id": "608b147275ba1f27e956a696", + "name": "New Board", + "desc": "", + "descData": null, + "closed": true, + "idOrganization": "6047c17c2f558003144e04d7", + "idEnterprise": null, + "pinned": false, + "url": "https://trello.com/b/RoxOjLDb/new-board", + "shortUrl": "https://trello.com/b/RoxOjLDb", + "prefs": { + "permissionLevel": "org", + "hideVotes": false, + "voting": "disabled", + "comments": "members", + "invitations": "members", + "selfJoin": true, + "cardCovers": true, + "cardCounts": false, + "isTemplate": false, + "cardAging": "regular", + "calendarFeedEnabled": false, + "hiddenPluginBoardButtons": [], + "switcherViews": [ + { + "viewType": "Board", + "enabled": true + }, + ], + "background": "608af97d7a474e8d98c2eef2", + "backgroundColor": null, + "backgroundImage": "", + "backgroundTile": false, + "backgroundBrightness": "dark", + "sharedSourceUrl": "", + "backgroundImageScaled": [ + { + "width": 140, + "height": 79, + "url": "" + }, + { + "width": 256, + "height": 144, + "url": "" + }, + { + "width": 480, + "height": 270, + "url": "" + }, + { + "width": 960, + "height": 540, + "url": "" + }, + { + "width": 1024, + "height": 576, + "url": "" + }, + { + "width": 1280, + "height": 720, + "url": "" + }, + { + "width": 1920, + "height": 1080, + "url": "" + }, + { + "width": 2048, + "height": 1152, + "url": "" + }, + { + "width": 2560, + "height": 1440, + "url": "" + } + ], + "backgroundBottomColor": "#231a15", + "backgroundTopColor": "#626667", + "canBePublic": true, + "canBeEnterprise": true, + "canBeOrg": true, + "canBePrivate": true, + "canInvite": true + }, + "labelNames": { + "green": "", + "yellow": "", + "orange": "", + "red": "", + "purple": "", + "blue": "", + } +} \ No newline at end of file diff --git a/components/trello/sources/new-card/new-card.mjs b/components/trello/sources/new-card/new-card.mjs index 6abce3a370d09..5da07a2005014 100644 --- a/components/trello/sources/new-card/new-card.mjs +++ b/components/trello/sources/new-card/new-card.mjs @@ -1,11 +1,12 @@ import common from "../common/common-webhook.mjs"; +import sampleEmit from "./test-event.mjs"; export default { ...common, key: "trello-new-card", name: "New Card (Instant)", description: "Emit new event for each new Trello card on a board.", - version: "0.1.0", + version: "0.1.1", type: "source", dedupe: "unique", props: { @@ -24,45 +25,37 @@ export default { board: c.board, }), ], - }, - customFieldItems: { - propDefinition: [ - common.props.app, - "customFieldItems", - ], + description: "If specified, events will only be emitted when a card is created in one of the specified lists", }, }, methods: { ...common.methods, async getSampleEvents() { - const cards = this.lists && this.lists.length > 0 + const params = { + customFieldItems: true, + }; + const cards = this.lists?.length ? await this.app.getCardsInList({ listId: this.lists[0], - params: { - customFieldItems: this.customFieldItems, - }, + params, }) : await this.app.getCards({ boardId: this.board, - params: { - customFieldItems: this.customFieldItems, - }, + params, }); - return { - sampleEvents: cards, - sortField: "dateLastActivity", - }; + return cards; + }, + getSortField() { + return "dateLastActivity"; }, - isCorrectEventType(event) { - const eventType = event.body?.action?.type; - return eventType === "createCard"; + isCorrectEventType({ type }) { + return type === "createCard"; }, - async getResult(event) { - const cardId = event.body?.action?.data?.card?.id; + getResult({ data }) { return this.app.getCard({ - cardId, + cardId: data?.card?.id, params: { - customFieldItems: this.customFieldItems, + customFieldItems: true, }, }); }, @@ -70,10 +63,10 @@ export default { if (this.board && this.board !== card.idBoard) return false; return ( (!this.board || this.board === card.idBoard) && - (!this.lists || - this.lists.length === 0 || + (!this.lists?.length || this.lists.includes(card.idList)) ); }, }, + sampleEmit, }; diff --git a/components/trello/sources/new-card/test-event.mjs b/components/trello/sources/new-card/test-event.mjs new file mode 100644 index 0000000000000..7be076b9b8709 --- /dev/null +++ b/components/trello/sources/new-card/test-event.mjs @@ -0,0 +1,79 @@ +export default { + "id": "60836bac2ed2ef78f4cf850d", + "badges": { + "attachmentsByType": { + "trello": { + "board": 0, + "card": 0 + } + }, + "externalSource": null, + "location": false, + "votes": 0, + "viewingMemberVoted": false, + "subscribed": true, + "fogbugz": "", + "checkItems": 1, + "checkItemsChecked": 0, + "checkItemsEarliestDue": null, + "comments": 3, + "attachments": 1, + "description": false, + "due": "2021-05-10T21:50:00.000Z", + "dueComplete": false, + "start": null, + "lastUpdatedByAi": false + }, + "checkItemStates": [], + "closed": false, + "dueComplete": false, + "dateLastActivity": "2021-11-02T23:02:44.876Z", + "desc": "", + "descData": null, + "due": "2021-05-10T21:50:00.000Z", + "dueReminder": 1440, + "email": null, + "idBoard": "5f4d7be6c45c22583f75fa02", + "idChecklists": [ + "608b2037ea7ac07da59c17be" + ], + "idList": "5f4ec9f69028408fed04c0b1", + "idMembers": [], + "idMembersVoted": [], + "idShort": 54, + "idAttachmentCover": "6099aece406c0b7a97e71535", + "labels": [ + { + "id": "608b2273586147300cc73046", + "idBoard": "5f4d7be6c45c22583f75fa02", + "idOrganization": "6047c17c2f558003144e04d7", + "name": "orange", + "nodeId": "ari:cloud:trello::label/workspace/6047c17c2f558003144e04d7/608b2273586147300cc73046", + "color": "orange", + "uses": 4 + }, + ], + "idLabels": [ + "608b2273586147300cc73046", + ], + "manualCoverAttachment": false, + "name": "new card", + "pinned": false, + "pos": 655359, + "shortLink": "fo2GH2y2", + "shortUrl": "https://trello.com/c/fo2GH2y2", + "start": null, + "subscribed": true, + "url": "https://trello.com/c/fo2GH2y2/54-new-card", + "cover": { + "idAttachment": "6099aece406c0b7a97e71535", + "color": null, + "idUploadedBackground": null, + "size": "normal", + "brightness": "dark", + "idPlugin": null + }, + "isTemplate": false, + "cardRole": null, + "customFieldItems": [] +} \ No newline at end of file diff --git a/components/trello/sources/new-checklist/new-checklist.mjs b/components/trello/sources/new-checklist/new-checklist.mjs index d30169a264b33..afc6291eac325 100644 --- a/components/trello/sources/new-checklist/new-checklist.mjs +++ b/components/trello/sources/new-checklist/new-checklist.mjs @@ -1,41 +1,58 @@ import common from "../common/common-board-based.mjs"; +import sampleEmit from "./test-event.mjs"; export default { ...common, key: "trello-new-checklist", name: "New Checklist (Instant)", description: "Emit new event for each new checklist added to a board.", - version: "0.1.0", + version: "0.1.1", type: "source", dedupe: "unique", + props: { + ...common.props, + board: { + propDefinition: [ + common.props.app, + "board", + ], + }, + lists: { + propDefinition: [ + common.props.app, + "lists", + (c) => ({ + board: c.board, + }), + ], + description: "If specified, events will only be emitted when a checklist is added to a card in one of the specified lists", + }, + onlyEventsRelatedWithAuthenticatedUser: { + label: "Only Events Related To Me", + description: "Only will emit events from the cards related with the authenticated user", + type: "boolean", + default: false, + optional: true, + }, + }, methods: { ...common.methods, - getChecklist({ - checklistId, ...args - } = {}) { - return this.app._makeRequest({ - path: `/checklists/${checklistId}`, - ...args, - }); - }, - async getSampleEvents() { - const checklists = await this.app.listBoardChecklists({ + getSampleEvents() { + return this.app.listBoardChecklists({ boardId: this.board, }); - return { - sampleEvents: checklists, - sortField: "id", - }; }, - isCorrectEventType(event) { - const eventType = event.body?.action?.type; - return eventType === "addChecklistToCard"; + getSortField() { + return "id"; + }, + isCorrectEventType({ type }) { + return type === "addChecklistToCard"; }, - async getResult(event) { - const checklistId = event.body?.action?.data?.checklist?.id; - return this.getChecklist({ - checklistId, + getResult({ data }) { + return this.app.getChecklist({ + checklistId: data?.checklist?.id, }); }, }, + sampleEmit, }; diff --git a/components/trello/sources/new-checklist/test-event.mjs b/components/trello/sources/new-checklist/test-event.mjs new file mode 100644 index 0000000000000..65dee447bd69c --- /dev/null +++ b/components/trello/sources/new-checklist/test-event.mjs @@ -0,0 +1,22 @@ +export default { + "id": "6181a5c4b843ed8eb8fc1482", + "name": "Checklist", + "idBoard": "5f4d7be6c45c22583f75fa02", + "idCard": "6099aff7ab0cc929f640e06e", + "pos": 16384, + "checkItems": [ + { + "id": "6181a5c685e54137db6951f5", + "name": "item", + "nameData": { + "emoji": {} + }, + "pos": 17027, + "state": "complete", + "due": null, + "dueReminder": null, + "idMember": null, + "idChecklist": "6181a5c4b843ed8eb8fc1482" + } + ] +} \ No newline at end of file diff --git a/components/trello/sources/new-comment-added-to-card/new-comment-added-to-card.mjs b/components/trello/sources/new-comment-added-to-card/new-comment-added-to-card.mjs index eee422e1af23b..2debee96fde93 100644 --- a/components/trello/sources/new-comment-added-to-card/new-comment-added-to-card.mjs +++ b/components/trello/sources/new-comment-added-to-card/new-comment-added-to-card.mjs @@ -1,11 +1,12 @@ import common from "../common/common-webhook.mjs"; +import sampleEmit from "./test-event.mjs"; export default { ...common, key: "trello-new-comment-added-to-card", name: "New Comment Added to Card (Instant)", description: "Emit new event for each new comment added to a card.", - version: "0.2.0", + version: "0.2.1", type: "source", dedupe: "unique", props: { @@ -16,49 +17,45 @@ export default { "board", ], }, + list: { + propDefinition: [ + common.props.app, + "lists", + (c) => ({ + board: c.board, + }), + ], + type: "string", + label: "List", + description: "If specified, events will only be emitted when a comment is added to a card in the specified list", + }, cards: { propDefinition: [ common.props.app, "cards", (c) => ({ board: c.board, + list: c.list, }), ], - }, - }, - hooks: { - ...common.hooks, - async deploy() { - const { - sampleEvents, sortField, - } = await this.getSampleEvents(); - sampleEvents.sort((a, b) => (Date.parse(a[sortField]) > Date.parse(b[sortField])) - ? 1 - : -1); - for (const action of sampleEvents.slice(-25)) { - this.emitEvent(action); - } + description: "If specified, events will only be emitted when a comment is added to one of the specified cards", }, }, methods: { ...common.methods, - getCardActivity({ - cardId, ...args - } = {}) { - return this.app._makeRequest({ - path: `/cards/${cardId}/actions`, - ...args, - }); - }, async getSampleEvents() { - const cards = this.cards && this.cards.length > 0 + const cards = this.cards?.length ? this.cards - : (await this.app.getCards({ - boardId: this.board, - })).map((card) => card.id); + : this.list + ? (await this.app.getCardsInList({ + listId: this.list, + })).map((card) => card.id) + : (await this.app.getCards({ + boardId: this.board, + })).map((card) => card.id); const actions = []; for (const card of cards) { - const activities = await this.getCardActivity({ + const activities = await this.app.getCardActivity({ cardId: card, params: { filter: "commentCard", @@ -69,37 +66,33 @@ export default { actions.push(await this.getResult(activity)); } } - return { - sampleEvents: actions, - sortField: "date", - }; + return actions; + }, + getSortField() { + return "date"; }, - isCorrectEventType(event) { - const eventType = event.body?.action?.type; - return eventType === "commentCard"; + isCorrectEventType({ type }) { + return type === "commentCard"; }, - async getResult(event) { - const cardId = event?.body?.action?.data?.card?.id ?? - event?.data?.card?.id; + async getResult(action) { const card = await this.app.getCard({ - cardId, + cardId: action?.data?.card?.id, }); - const memberId = event?.body?.action?.idMemberCreator ?? - event.idMemberCreator; const member = await this.app.getMember({ - memberId, + memberId: action?.idMemberCreator, }); return { member, card, - event: event?.body ?? event, + event: action, }; }, isRelevant({ result: { card } }) { return ( (!this.board || this.board === card.idBoard) && - (!this.cards || this.cards.length === 0 || this.cards.includes(card.id)) + (!this.lists || this.list === card.idList) && + (!this.cards?.length || this.cards.includes(card.id)) ); }, generateMeta({ event }) { @@ -110,4 +103,5 @@ export default { }; }, }, + sampleEmit, }; diff --git a/components/trello/sources/new-comment-added-to-card/test-event.mjs b/components/trello/sources/new-comment-added-to-card/test-event.mjs new file mode 100644 index 0000000000000..9e2c2398e2582 --- /dev/null +++ b/components/trello/sources/new-comment-added-to-card/test-event.mjs @@ -0,0 +1,298 @@ +export default { + "member": { + "id": "5df149d4fa80be39e64c9a43", + "aaId": "5df149cf8998970e5b435642", + "activityBlocked": false, + "avatarHash": "5590d4f06fc7d09fc98b242248c9003e", + "avatarUrl": "https://trello-members.s3.amazonaws.com/5df149d4fa80be39e64c9a43/5590d4f06fc7d09fc98b242248c9003e", + "bio": "", + "bioData": null, + "confirmed": true, + "fullName": "Michelle Bergeron", + "idEnterprise": null, + "idEnterprisesDeactivated": [], + "idMemberReferrer": null, + "idPremOrgsAdmin": [], + "initials": "MB", + "memberType": "normal", + "nonPublic": {}, + "nonPublicAvailable": true, + "products": [], + "url": "https://trello.com/michellebergeron6", + "username": "michellebergeron6", + "status": "disconnected", + "aaBlockSyncUntil": null, + "aaEmail": null, + "aaEnrolledDate": null, + "avatarSource": "none", + "credentialsRemovedCount": 0, + "dateLastImpression": "2024-10-01T19:54:58.087Z", + "dateLastActive": "2024-10-01T19:55:05.070Z", + "domainClaimed": null, + "email": null, + "gravatarHash": "010b11df3bb34c405912830655ee130c", + "idBoards": [ + "5df14a131c0e51155e68ea62", + ], + "idOrganizations": [ + "6047c17c2f558003144e04d7" + ], + "idEnterprisesAdmin": [], + "limits": { + "boards": { + "totalPerMember": { + "status": "ok", + "disableAt": 4500, + "warnAt": 3600 + } + }, + "orgs": { + "totalPerMember": { + "status": "ok", + "disableAt": 850, + "warnAt": 680 + } + } + }, + "loginTypes": null, + "marketingOptIn": { + "optedIn": true, + "date": "2019-12-11T19:56:05.741Z" + }, + "messagesDismissed": [ + { + "_id": "6082199aab18525bdcbe18f5", + "name": "team-join-cta-banner-6047c17c2f558003144e04d7", + "count": 5, + "lastDismissed": "2021-04-23T00:49:31.975Z" + }, + { + "_id": "6082199a190169402dc6130f", + "name": "team-join-cta-banner-6047c17c2f558003144e04d7", + "count": 1, + "lastDismissed": "2021-04-23T00:49:30.689Z" + } + ], + "nodeId": "ari:cloud:trello::user/5df149d4fa80be39e64c9a43", + "oneTimeMessagesDismissed": [ + "create-first-board", + "close-menu-of-first-board", + "nusku.views-switcher-upsell-default-open", + "teamify-post-migration", + "ack-new-feature-ButlerOnBoardsV2-1619852400000", + "workspace-nav-enabled", + "workspace-nav-spotlight", + "team-template-picker-6047c17c2f558003144e04d7", + "free-trial-banner-confetti-6047c17c2f558003144e04d7", + "team-table-views-switcher-new-pill", + "timeline-view-suggestion-6047c17c2f558003144e04d7", + "calendar-view-suggestion-6047c17c2f558003144e04d7", + "free-trial-banner-6047c17c2f558003144e04d7", + "workspace-user-limit-banner", + "atlassian-intelligence-admin-6047c17c2f558003144e04d7", + "your-items-on-home" + ], + "sessionType": null, + "prefs": { + "sendSummaries": true, + "minutesBetweenSummaries": 60, + "minutesBeforeDeadlineToNotify": 60, + "colorBlind": false, + "locale": "en-US", + "privacy": { + "fullName": "public", + "avatar": "public" + } + }, + "trophies": [], + "uploadedAvatarHash": null, + "uploadedAvatarUrl": null, + "premiumFeatures": [], + "isAaMastered": true, + "ixUpdate": "151" + }, + "card": { + "id": "61818a303e545129af23695d", + "badges": { + "attachmentsByType": { + "trello": { + "board": 0, + "card": 2 + } + }, + "externalSource": null, + "location": false, + "votes": 0, + "viewingMemberVoted": false, + "subscribed": true, + "fogbugz": "", + "checkItems": 1, + "checkItemsChecked": 1, + "checkItemsEarliestDue": null, + "comments": 2, + "attachments": 3, + "description": false, + "due": "2024-10-01T19:20:00.000Z", + "dueComplete": false, + "start": null, + "lastUpdatedByAi": false + }, + "checkItemStates": [ + { + "idCheckItem": "6181a5f18e239e6aff9799a4", + "state": "complete" + } + ], + "closed": false, + "dueComplete": false, + "dateLastActivity": "2024-10-01T20:12:35.627Z", + "desc": "", + "descData": { + "emoji": {} + }, + "due": "2024-10-01T19:20:00.000Z", + "dueReminder": -1, + "email": null, + "idBoard": "5f4d7be6c45c22583f75fa02", + "idChecklists": [ + "6181a5ef401ae66c357732b4" + ], + "idList": "5f4d7f78bdd7ce4d2d25fdda", + "idMembers": [], + "idMembersVoted": [], + "idShort": 68, + "idAttachmentCover": "62c884dce32d46579ecfd5f0", + "labels": [], + "idLabels": [], + "manualCoverAttachment": false, + "name": "sfsfdsfd", + "pinned": false, + "pos": 131071, + "shortLink": "QVLahShU", + "shortUrl": "https://trello.com/c/QVLahShU", + "start": null, + "subscribed": true, + "url": "https://trello.com/c/QVLahShU/68-sfsfdsfd", + "cover": { + "idAttachment": "62c884dce32d46579ecfd5f0", + "color": null, + "idUploadedBackground": null, + "size": "normal", + "brightness": "dark", + "scaled": [ + { + "id": "62c884dde32d46579ecfd5ff", + "_id": "62c884dde32d46579ecfd5ff", + "scaled": false, + "url": "", + "bytes": 1649, + "height": 50, + "width": 70 + }, + { + "id": "62c884dde32d46579ecfd601", + "_id": "62c884dde32d46579ecfd601", + "scaled": true, + "url": "", + "bytes": 4508, + "height": 98, + "width": 150 + }, + { + "id": "62c884dde32d46579ecfd600", + "_id": "62c884dde32d46579ecfd600", + "scaled": false, + "url": "", + "bytes": 9598, + "height": 150, + "width": 250 + }, + { + "id": "62c884dde32d46579ecfd602", + "_id": "62c884dde32d46579ecfd602", + "scaled": true, + "url": "", + "bytes": 13736, + "height": 195, + "width": 300 + }, + { + "id": "62c884dde32d46579ecfd603", + "_id": "62c884dde32d46579ecfd603", + "scaled": true, + "url": "", + "bytes": 20289, + "height": 260, + "width": 400 + }, + { + "id": "62c884dde32d46579ecfd604", + "_id": "62c884dde32d46579ecfd604", + "scaled": false, + "url": "", + "bytes": 18820, + "height": 260, + "width": 400 + } + ], + "edgeColor": "#bbac9c", + "idPlugin": null + }, + "isTemplate": false, + "cardRole": null + }, + "event": { + "id": "66fc17543e3458edb8b3070d", + "idMemberCreator": "5df149d4fa80be39e64c9a43", + "data": { + "text": "hello world", + "textData": { + "emoji": {} + }, + "card": { + "id": "61818a303e545129af23695d", + "name": "card", + "idShort": 68, + "shortLink": "QVLahShU" + }, + "board": { + "id": "5f4d7be6c45c22583f75fa02", + "name": "Board", + "shortLink": "tiA9sOeK" + }, + "list": { + "id": "5f4d7f78bdd7ce4d2d25fdda", + "name": "List" + } + }, + "appCreator": null, + "type": "commentCard", + "date": "2024-10-01T15:37:56.522Z", + "limits": { + "reactions": { + "perAction": { + "status": "ok", + "disableAt": 900, + "warnAt": 720 + }, + "uniquePerAction": { + "status": "ok", + "disableAt": 17, + "warnAt": 14 + } + } + }, + "memberCreator": { + "id": "5df149d4fa80be39e64c9a43", + "activityBlocked": false, + "avatarHash": "5590d4f06fc7d09fc98b242248c9003e", + "avatarUrl": "", + "fullName": "", + "idMemberReferrer": null, + "initials": "", + "nonPublic": {}, + "nonPublicAvailable": true, + "username": "" + } + } +} \ No newline at end of file diff --git a/components/trello/sources/new-label-added-to-card/new-label-added-to-card.mjs b/components/trello/sources/new-label-added-to-card/new-label-added-to-card.mjs index 9873325e372f4..8b8bebb76810d 100644 --- a/components/trello/sources/new-label-added-to-card/new-label-added-to-card.mjs +++ b/components/trello/sources/new-label-added-to-card/new-label-added-to-card.mjs @@ -1,11 +1,12 @@ import common from "../common/common-webhook.mjs"; +import sampleEmit from "./test-event.mjs"; export default { ...common, key: "trello-new-label-added-to-card", name: "New Label Added To Card (Instant)", description: "Emit new event for each label added to a card.", - version: "0.1.0", + version: "0.1.1", type: "source", props: { ...common.props, @@ -15,7 +16,7 @@ export default { "board", ], }, - lists: { + list: { propDefinition: [ common.props.app, "lists", @@ -23,6 +24,9 @@ export default { board: c.board, }), ], + type: "string", + label: "List", + description: "If specified, events will only be emitted when a label is added to a card in the specified lists", }, cards: { propDefinition: [ @@ -30,24 +34,24 @@ export default { "cards", (c) => ({ board: c.board, + list: c.list, }), ], + description: "If specified, events will only be emitted when a label is added to one of the specified cards", }, }, hooks: { ...common.hooks, async deploy() { - if (this.cards && this.cards.length > 0) { + if (this.cards?.length) { await this.emitLabelsFromCardIds(this.cards); return; } - if (this.lists && this.lists.length > 0) { - for (const listId of this.lists) { - const cards = await this.app.getCardsInList({ - listId, - }); - await this.emitLabelsFromCards(cards); - } + if (this.list) { + const cards = await this.app.getCardsInList({ + listId: this.list, + }); + await this.emitLabelsFromCards(cards); return; } const cards = await this.app.getCards({ @@ -100,28 +104,22 @@ export default { _setLabelColor(labelColor) { this.db.set("labelColor", labelColor); }, - isCorrectEventType(event) { - const eventType = event.body?.action?.type; - return eventType === "addLabelToCard"; + isCorrectEventType({ type }) { + return type === "addLabelToCard"; }, - async getResult(event) { - const cardId = event.body?.action?.data?.card?.id; - const labelName = event.body?.action?.data?.label?.name; - const labelColor = event.body?.action?.data?.label?.color; + getResult({ data }) { /** Record labelName & labelColor to use in generateMeta() */ - this._setLabelName(labelName); - this._setLabelColor(labelColor); + this._setLabelName(data?.label?.name); + this._setLabelColor(data?.label?.color); return this.app.getCard({ - cardId, + cardId: data?.card?.id, }); }, isRelevant({ result: card }) { return ( (!this.board || this.board === card.idBoard) && - (!this.lists || - this.lists.length === 0 || - this.lists.includes(card.idList)) && - (!this.cards || this.cards.length === 0 || this.cards.includes(card.id)) + (!this.list || this.list === card.idList) && + (!this.cards?.length || this.cards.includes(card.id)) ); }, generateMeta({ @@ -145,4 +143,5 @@ export default { this.$emit(card, meta); }, }, + sampleEmit, }; diff --git a/components/trello/sources/new-label-added-to-card/test-event.mjs b/components/trello/sources/new-label-added-to-card/test-event.mjs new file mode 100644 index 0000000000000..0c03bce6bf924 --- /dev/null +++ b/components/trello/sources/new-label-added-to-card/test-event.mjs @@ -0,0 +1,85 @@ +export default { + "id": "620eb14ebda9570d72fddead", + "badges": { + "attachmentsByType": { + "trello": { + "board": 0, + "card": 0 + } + }, + "externalSource": null, + "location": false, + "votes": 0, + "viewingMemberVoted": false, + "subscribed": false, + "fogbugz": "", + "checkItems": 1, + "checkItemsChecked": 1, + "checkItemsEarliestDue": null, + "comments": 3, + "attachments": 1, + "description": false, + "due": "2021-05-10T21:50:00.000Z", + "dueComplete": false, + "start": null, + "lastUpdatedByAi": false + }, + "checkItemStates": [ + { + "idCheckItem": "620eb14fbda9570d72fde031", + "state": "complete" + } + ], + "closed": false, + "dueComplete": false, + "dateLastActivity": "2024-09-30T16:31:35.215Z", + "desc": "", + "descData": { + "emoji": {} + }, + "due": "2021-05-10T21:50:00.000Z", + "dueReminder": null, + "email": null, + "idBoard": "5f4d7be6c45c22583f75fa02", + "idChecklists": [ + "620eb14fbda9570d72fde030" + ], + "idList": "5f4d7f78bdd7ce4d2d25fdda", + "idMembers": [], + "idMembersVoted": [], + "idShort": 85, + "idAttachmentCover": "620eb14ebda9570d72fdded7", + "labels": [ + { + "id": "5f4d7be6cdabcf46c027c792", + "idBoard": "5f4d7be6c45c22583f75fa02", + "idOrganization": "6047c17c2f558003144e04d7", + "name": "green label", + "nodeId": "ari:cloud:trello::label/workspace/6047c17c2f558003144e04d7/5f4d7be6cdabcf46c027c792", + "color": "green", + "uses": 9 + }, + ], + "idLabels": [ + "5f4d7be6cdabcf46c027c792", + ], + "manualCoverAttachment": false, + "name": "new card", + "pinned": false, + "pos": 360447, + "shortLink": "dho6bOdR", + "shortUrl": "https://trello.com/c/dho6bOdR", + "start": null, + "subscribed": false, + "url": "https://trello.com/c/dho6bOdR/85-new-card", + "cover": { + "idAttachment": "620eb14ebda9570d72fdded7", + "color": null, + "idUploadedBackground": null, + "size": "normal", + "brightness": "dark", + "idPlugin": null + }, + "isTemplate": false, + "cardRole": null +} \ No newline at end of file diff --git a/components/trello/sources/new-label/new-label.mjs b/components/trello/sources/new-label/new-label.mjs index 852949cdfa153..6ce68168b1547 100644 --- a/components/trello/sources/new-label/new-label.mjs +++ b/components/trello/sources/new-label/new-label.mjs @@ -1,32 +1,30 @@ import common from "../common/common-board-based.mjs"; +import sampleEmit from "./test-event.mjs"; export default { ...common, key: "trello-new-label", - name: "New Label (Instant)", + name: "New Label Created (Instant)", description: "Emit new event for each new label added to a board.", - version: "0.1.0", + version: "0.1.1", type: "source", dedupe: "unique", methods: { ...common.methods, - async getSampleEvents() { - const labels = await this.app.findLabel({ + getSampleEvents() { + return this.app.findLabel({ boardId: this.board, }); - return { - sampleEvents: labels, - sortField: "id", - }; }, - isCorrectEventType(event) { - const eventType = event.body?.action?.type; - return eventType === "createLabel"; + getSortField() { + return "id"; + }, + isCorrectEventType({ type }) { + return type === "createLabel"; }, - async getResult(event) { - const labelId = event.body?.action?.data?.label?.id; + getResult({ data }) { return this.app.getLabel({ - labelId, + labelId: data?.label?.id, }); }, generateMeta({ @@ -42,4 +40,5 @@ export default { }; }, }, + sampleEmit, }; diff --git a/components/trello/sources/new-label/test-event.mjs b/components/trello/sources/new-label/test-event.mjs new file mode 100644 index 0000000000000..d4c67a99019de --- /dev/null +++ b/components/trello/sources/new-label/test-event.mjs @@ -0,0 +1,7 @@ +export default { + "id": "5f4d7be6cdabcf46c027c794", + "idBoard": "5f4d7be6c45c22583f75fa02", + "name": "red label", + "color": "red", + "uses": 1 +} \ No newline at end of file diff --git a/components/trello/sources/new-list/new-list.mjs b/components/trello/sources/new-list/new-list.mjs deleted file mode 100644 index ad621793bcda1..0000000000000 --- a/components/trello/sources/new-list/new-list.mjs +++ /dev/null @@ -1,33 +0,0 @@ -import common from "../common/common-board-based.mjs"; - -export default { - ...common, - key: "trello-new-list", - name: "New List (Instant)", - description: "Emit new event for each new list added to a board.", - version: "0.1.0", - type: "source", - dedupe: "unique", - methods: { - ...common.methods, - async getSampleEvents() { - const lists = await this.app.getLists({ - boardId: this.board, - }); - return { - sampleEvents: lists, - sortField: "id", - }; - }, - isCorrectEventType(event) { - const eventType = event.body?.action?.type; - return eventType === "createList"; - }, - async getResult(event) { - const listId = event.body?.action?.data?.list?.id; - return await this.app.getList({ - listId, - }); - }, - }, -}; diff --git a/components/trello/sources/new-member-on-card/new-member-on-card.mjs b/components/trello/sources/new-member-on-card/new-member-on-card.mjs index a827c9beed7cf..bd68eea59f5e8 100644 --- a/components/trello/sources/new-member-on-card/new-member-on-card.mjs +++ b/components/trello/sources/new-member-on-card/new-member-on-card.mjs @@ -1,52 +1,43 @@ import common from "../common/common-board-based.mjs"; +import sampleEmit from "./test-event.mjs"; export default { ...common, key: "trello-new-member-on-card", name: "New Member on Card (Instant)", description: "Emit new event for each member that join in a card.", - version: "0.1.0", + version: "0.1.1", type: "source", dedupe: "unique", methods: { ...common.methods, - getMemberCards({ - userId, ...args - } = {}) { - return this.app._makeRequest({ - path: `/members/${userId}/cards`, - ...args, - }); - }, - async getSampleEvents() { - const cards = await this.getMemberCards({ + getSampleEvents() { + return this.app.getMemberCards({ userId: "me", }); - return { - sampleEvents: cards, - sortField: "dateLastActivity", - }; }, - isCorrectEventType(event) { - const eventType = event.body?.action?.type; - return eventType === "addMemberToCard"; + getSortField() { + return "dateLastActivity"; + }, + isCorrectEventType({ type }) { + return type === "addMemberToCard"; }, - async getResult(event) { - const cardId = event.body?.action?.data?.card?.id; + getResult({ data }) { return this.app.getCard({ - cardId, + cardId: data?.card?.id, }); }, generateMeta({ - id, name: summary, dateLastActivity, + id, name, dateLastActivity, }) { return { - id: this.onlyEventsRelatedWithAuthenticatedUser ? - id : - `${id}${dateLastActivity}`, - summary, + id: this.onlyEventsRelatedWithAuthenticatedUser + ? id + : `${id}${dateLastActivity}`, + summary: name || id, ts: Date.now(), }; }, }, + sampleEmit, }; diff --git a/components/trello/sources/new-member-on-card/test-event.mjs b/components/trello/sources/new-member-on-card/test-event.mjs new file mode 100644 index 0000000000000..b07248ed2bb8c --- /dev/null +++ b/components/trello/sources/new-member-on-card/test-event.mjs @@ -0,0 +1,83 @@ +export default { + "id": "66f5aef006f1cca76bb3250f", + "badges": { + "attachmentsByType": { + "trello": { + "board": 0, + "card": 0 + } + }, + "externalSource": null, + "location": false, + "votes": 0, + "viewingMemberVoted": false, + "subscribed": true, + "attachments": 0, + "fogbugz": "", + "checkItems": 0, + "checkItemsChecked": 0, + "checkItemsEarliestDue": null, + "comments": 2, + "description": false, + "due": null, + "dueComplete": false, + "lastUpdatedByAi": false, + "start": null + }, + "checkItemStates": [], + "closed": false, + "dueComplete": false, + "dateLastActivity": "2024-09-30T16:22:46.307Z", + "desc": "", + "descData": { + "emoji": {} + }, + "due": null, + "dueReminder": null, + "email": null, + "idBoard": "5f4d7be6c45c22583f75fa02", + "idChecklists": [ + "66f5b2296cb1ec0c66c5a119", + "66f6f798f4c23c2020f2bbad" + ], + "idList": "5f4d7f78bdd7ce4d2d25fdda", + "idMembers": [ + "5df149d4fa80be39e64c9a43" + ], + "idMembersVoted": [], + "idShort": 98, + "idAttachmentCover": null, + "labels": [ + { + "id": "66f5c1fd51d74d4e66aa26e0", + "idBoard": "5f4d7be6c45c22583f75fa02", + "idOrganization": "6047c17c2f558003144e04d7", + "name": "subtle sky label", + "nodeId": "ari:cloud:trello::label/workspace/6047c17c2f558003144e04d7/66f5c1fd51d74d4e66aa26e0", + "color": "sky_light", + "uses": 1 + }, + ], + "idLabels": [ + "66f5c1fd51d74d4e66aa26e0", + ], + "manualCoverAttachment": false, + "name": "hello world", + "pinned": false, + "pos": 393215, + "shortLink": "bRoOO9Bh", + "shortUrl": "https://trello.com/c/bRoOO9Bh", + "start": null, + "subscribed": true, + "url": "https://trello.com/c/bRoOO9Bh/98-hello-world", + "cover": { + "idAttachment": null, + "color": null, + "idUploadedBackground": null, + "size": "normal", + "brightness": "dark", + "idPlugin": null + }, + "isTemplate": false, + "cardRole": null +} \ No newline at end of file diff --git a/components/trello/sources/new-notification/new-notification.mjs b/components/trello/sources/new-notification/new-notification.mjs index ed1b48046b627..2d988e128fa71 100644 --- a/components/trello/sources/new-notification/new-notification.mjs +++ b/components/trello/sources/new-notification/new-notification.mjs @@ -4,21 +4,12 @@ export default { ...common, key: "trello-new-notification", name: "New Notification", - description: - "Emit new event for each new Trello notification for the authenticated user.", - version: "0.1.0", + description: "Emit new event for each new Trello notification for the authenticated user.", + version: "0.1.1", type: "source", dedupe: "unique", methods: { ...common.methods, - getNotifications({ - notificationId, ...args - } = {}) { - return this.app._makeRequest({ - path: `/members/${notificationId}/notifications`, - ...args, - }); - }, _getLastNotificationId() { return this.db.get("lastNotificationId") || null; }, @@ -38,7 +29,7 @@ export default { async run() { const since = this._getLastNotificationId(); - const notifications = await this.getNotifications({ + const notifications = await this.app.getNotifications({ notificationId: "me", params: { since, diff --git a/components/trello/trello.app.mjs b/components/trello/trello.app.mjs index bada2c9547882..5be4e8d1edf2e 100644 --- a/components/trello/trello.app.mjs +++ b/components/trello/trello.app.mjs @@ -1,5 +1,7 @@ import { axios } from "@pipedream/platform"; import fields from "./common/fields.mjs"; +import constants from "./common/constants.mjs"; +import mime from "mime/types/standard.js"; export default { type: "app", @@ -26,10 +28,18 @@ export default { label: "Cards", description: "The Trello cards you wish to select", optional: true, - async options({ board }) { - const cards = await this.getCards({ + async options({ + board, list, checklistCardsOnly, + }) { + let cards = await this.getCards({ boardId: board, }); + if (list) { + cards = cards.filter(({ idList }) => idList === list); + } + if (checklistCardsOnly) { + cards = cards.filter(({ idChecklists }) => idChecklists?.length); + } return cards.map(({ id: value, name: label, }) => ({ @@ -41,7 +51,7 @@ export default { boardFields: { type: "string[]", label: "Boards Fields", - description: "`all` or a list of board [fields](https://developer.atlassian.com/cloud/trello/guides/rest-api/object-definitions/#board-object)", + description: "`all` or a list of board [fields](https://developer.atlassian.com/cloud/trello/guides/rest-api/object-definitions/#board-object) to be returned in the results", options: fields.board, default: [ "name", @@ -51,7 +61,7 @@ export default { cardFields: { type: "string[]", label: "Cards Fields", - description: "`all` or a list of card [fields](https://developer.atlassian.com/cloud/trello/guides/rest-api/object-definitions/#card-object)", + description: "`all` or a list of card [fields](https://developer.atlassian.com/cloud/trello/guides/rest-api/object-definitions/#card-object) to be returned in the results", options: fields.card, default: [ "all", @@ -111,10 +121,23 @@ export default { type: "string", label: "Label", description: "The ID of the Label to be added to the card", - async options({ board }) { - const labels = await this.findLabel({ + async options({ + board, card, excludeCardLabels, cardLabelsOnly, + }) { + let labels = await this.findLabel({ boardId: board, }); + if (card) { + const { idLabels } = await this.getCard({ + cardId: card, + }); + if (excludeCardLabels) { + labels = labels.filter(({ id }) => !idLabels.includes(id)); + } + if (cardLabelsOnly) { + labels = labels.filter(({ id }) => idLabels.includes(id)); + } + } return labels.map(({ name, color, id: value, }) => ({ @@ -127,10 +150,18 @@ export default { type: "string", label: "Member", description: "The ID of the Member to be added to the card", - async options(opts) { - const members = await this.listMembers({ - boardId: opts.board, + async options({ + board, card, excludeCardMembers, + }) { + let members = await this.listMembers({ + boardId: board, }); + if (card && excludeCardMembers) { + const { idMembers } = await this.getCard({ + cardId: card, + }); + members = members.filter(({ id }) => !idMembers.includes(id)); + } return members.map((member) => ({ label: member.fullName, value: member.id, @@ -184,19 +215,19 @@ export default { type: "string", label: "File Attachment URL", description: "URL must start with `http://` or `https://`", - optional: true, }, mimeType: { type: "string", - label: "File Attachment Type", - description: "Not required for **File Attachment URL** property. Eg. `application/pdf`", - optional: true, + label: "Mime Type", + description: "Mime type of the attached file. Eg. `application/pdf`", + options() { + return Object.keys(mime); + }, }, file: { type: "string", label: "File Attachment Path", - description: "The path to the file saved to the `/tmp` directory (e.g. `/tmp/example.pdf`). [See the documentation](https://pipedream.com/docs/workflows/steps/code/nodejs/working-with-files/#the-tmp-directory). If you provide a file path, the **File Attachment URL** field will be ignored.", - optional: true, + description: "The path to the file saved to the `/tmp` directory (e.g. `/tmp/example.pdf`). [See the documentation](https://pipedream.com/docs/workflows/steps/code/nodejs/working-with-files/#the-tmp-directory)", }, desc: { type: "string", @@ -207,11 +238,8 @@ export default { pos: { type: "string", label: "Position", - description: "The position of the new card, can be `top`, `bottom`, or a positive number", - options: [ - "top", - "bottom", - ], + description: "The position of the checklist on the card. One of: top, bottom, or a positive number.", + options: constants.POSITIONS, optional: true, }, due: { @@ -248,25 +276,14 @@ export default { type: "string", label: "Card Filter", description: "Filter to apply to Cards. Valid values: `all`, `closed`, `none`, `open`, `visible`", - options: [ - "all", - "closed", - "none", - "open", - "visible", - ], + options: constants.CARD_FILTERS, default: "all", }, listFilter: { type: "string", label: "List Filter", description: "Type of list to search for", - options: [ - "all", - "closed", - "none", - "open", - ], + options: constants.LIST_FILTERS, default: "all", }, customFieldItems: { @@ -312,6 +329,15 @@ export default { })); }, }, + fileType: { + type: "string", + label: "File Attachment Type", + description: "Select whether to attach file from a path or URL", + options: [ + "path", + "url", + ], + }, }, methods: { getSignerUri() { @@ -377,6 +403,12 @@ export default { ...args, }); }, + createCard(args = {}) { + return this.post({ + path: "/cards", + ...args, + }); + }, updateCard({ cardId, ...args } = {}) { @@ -393,6 +425,14 @@ export default { ...args, }); }, + getCardActivity({ + cardId, ...args + } = {}) { + return this._makeRequest({ + path: `/cards/${cardId}/actions`, + ...args, + }); + }, getBoardActivity({ boardId, ...args } = {}) { @@ -433,6 +473,30 @@ export default { ...args, }); }, + getChecklist({ + checklistId, ...args + } = {}) { + return this._makeRequest({ + path: `/checklists/${checklistId}`, + ...args, + }); + }, + getFilteredCards({ + boardId, filter, ...args + } = {}) { + return this._makeRequest({ + path: `/boards/${boardId}/cards/${filter}`, + ...args, + }); + }, + getCardList({ + cardId, ...args + } = {}) { + return this._makeRequest({ + path: `/cards/${cardId}/list`, + ...args, + }); + }, getCardsInList({ listId, ...args } = {}) { @@ -473,6 +537,30 @@ export default { ...args, }); }, + getMemberCards({ + userId, ...args + } = {}) { + return this._makeRequest({ + path: `/members/${userId}/cards`, + ...args, + }); + }, + getAttachment({ + cardId, attachmentId, ...args + } = {}) { + return this._makeRequest({ + path: `/cards/${cardId}/attachments/${attachmentId}`, + ...args, + }); + }, + getNotifications({ + notificationId, ...args + } = {}) { + return this._makeRequest({ + path: `/members/${notificationId}/notifications`, + ...args, + }); + }, /** * Searches for members, cards, boards, and/or organizations matching the specified query. * @@ -560,5 +648,95 @@ export default { ...args, }); }, + addAttachmentToCard({ + cardId, ...args + } = {}) { + return this.post({ + path: `/cards/${cardId}/attachments`, + ...args, + }); + }, + addChecklist({ + cardId, ...args + } = {}) { + return this.post({ + path: `/cards/${cardId}/checklists`, + ...args, + }); + }, + addComment({ + cardId, ...args + } = {}) { + return this.post({ + path: `/cards/${cardId}/actions/comments`, + ...args, + }); + }, + addExistingLabelToCard({ + cardId, ...args + } = {}) { + return this.post({ + path: `/cards/${cardId}/idLabels`, + ...args, + }); + }, + removeLabelFromCard({ + cardId, labelId, ...args + } = {}) { + return this.delete({ + path: `/cards/${cardId}/idLabels/${labelId}`, + ...args, + }); + }, + addMemberToCard({ + cardId, ...args + } = {}) { + return this.post({ + path: `/cards/${cardId}/idMembers`, + ...args, + }); + }, + completeChecklistItem({ + cardId, checklistItemId, ...args + } = {}) { + return this.put({ + path: `/cards/${cardId}/checkItem/${checklistItemId}`, + ...args, + }); + }, + createChecklistItem({ + checklistId, ...args + } = {}) { + return this.post({ + path: `/checklists/${checklistId}/checkItems`, + ...args, + }); + }, + createLabel(args = {}) { + return this.post({ + path: "/labels", + ...args, + }); + }, + createList(args = {}) { + return this.post({ + path: "/lists", + ...args, + }); + }, + deleteChecklist({ + checklistId, ...args + } = {}) { + return this.delete({ + path: `/checklists/${checklistId}`, + ...args, + }); + }, + searchMembers(args = {}) { + return this._makeRequest({ + path: "/search/members", + ...args, + }); + }, }, }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6f7260f345fb4..d4fb6e6a57f00 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10155,12 +10155,14 @@ importers: crypto: ^1.0.1 form-data: ^4.0.0 lodash-es: ^4.17.21 + mime: ^4.0.4 ms: ^2.1.3 dependencies: '@pipedream/platform': 3.0.1 crypto: 1.0.1 form-data: 4.0.0 lodash-es: 4.17.21 + mime: 4.0.4 ms: 2.1.3 components/trengo: @@ -12815,6 +12817,55 @@ packages: - aws-crt dev: false + /@aws-sdk/client-sso-oidc/3.600.0_tdq3komn4zwyd65w7klbptsu34: + resolution: {integrity: sha512-7+I8RWURGfzvChyNQSyj5/tKrqRbzRl7H+BnTOf/4Vsw1nFOi5ROhlhD4X/Y0QCTacxnaoNcIrqnY7uGGvVRzw==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sts': 3.600.0 + '@aws-sdk/core': 3.598.0 + '@aws-sdk/credential-provider-node': 3.600.0_f7n47caigsrjd2lr2szmwfuee4 + '@aws-sdk/middleware-host-header': 3.598.0 + '@aws-sdk/middleware-logger': 3.598.0 + '@aws-sdk/middleware-recursion-detection': 3.598.0 + '@aws-sdk/middleware-user-agent': 3.598.0 + '@aws-sdk/region-config-resolver': 3.598.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-endpoints': 3.598.0 + '@aws-sdk/util-user-agent-browser': 3.598.0 + '@aws-sdk/util-user-agent-node': 3.598.0 + '@smithy/config-resolver': 3.0.3 + '@smithy/core': 2.2.3 + '@smithy/fetch-http-handler': 3.2.1 + '@smithy/hash-node': 3.0.2 + '@smithy/invalid-dependency': 3.0.2 + '@smithy/middleware-content-length': 3.0.2 + '@smithy/middleware-endpoint': 3.0.4 + '@smithy/middleware-retry': 3.0.6 + '@smithy/middleware-serde': 3.0.3 + '@smithy/middleware-stack': 3.0.3 + '@smithy/node-config-provider': 3.1.3 + '@smithy/node-http-handler': 3.1.2 + '@smithy/protocol-http': 4.0.3 + '@smithy/smithy-client': 3.1.6 + '@smithy/types': 3.3.0 + '@smithy/url-parser': 3.0.3 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.6 + '@smithy/util-defaults-mode-node': 3.0.6 + '@smithy/util-endpoints': 2.0.3 + '@smithy/util-middleware': 3.0.3 + '@smithy/util-retry': 3.0.2 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.3 + transitivePeerDependencies: + - '@aws-sdk/client-sts' + - aws-crt + dev: false + /@aws-sdk/client-sso/3.423.0: resolution: {integrity: sha512-znIufHkwhCIePgaYciIs3x/+BpzR57CZzbCKHR9+oOvGyufEPPpUT5bFLvbwTgfiVkTjuk6sG/ES3U5Bc+xtrA==} engines: {node: '>=14.0.0'} @@ -13050,55 +13101,7 @@ packages: dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.600.0 - '@aws-sdk/core': 3.598.0 - '@aws-sdk/credential-provider-node': 3.600.0_f7n47caigsrjd2lr2szmwfuee4 - '@aws-sdk/middleware-host-header': 3.598.0 - '@aws-sdk/middleware-logger': 3.598.0 - '@aws-sdk/middleware-recursion-detection': 3.598.0 - '@aws-sdk/middleware-user-agent': 3.598.0 - '@aws-sdk/region-config-resolver': 3.598.0 - '@aws-sdk/types': 3.598.0 - '@aws-sdk/util-endpoints': 3.598.0 - '@aws-sdk/util-user-agent-browser': 3.598.0 - '@aws-sdk/util-user-agent-node': 3.598.0 - '@smithy/config-resolver': 3.0.3 - '@smithy/core': 2.2.3 - '@smithy/fetch-http-handler': 3.2.1 - '@smithy/hash-node': 3.0.2 - '@smithy/invalid-dependency': 3.0.2 - '@smithy/middleware-content-length': 3.0.2 - '@smithy/middleware-endpoint': 3.0.4 - '@smithy/middleware-retry': 3.0.6 - '@smithy/middleware-serde': 3.0.3 - '@smithy/middleware-stack': 3.0.3 - '@smithy/node-config-provider': 3.1.3 - '@smithy/node-http-handler': 3.1.2 - '@smithy/protocol-http': 4.0.3 - '@smithy/smithy-client': 3.1.6 - '@smithy/types': 3.3.0 - '@smithy/url-parser': 3.0.3 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.6 - '@smithy/util-defaults-mode-node': 3.0.6 - '@smithy/util-endpoints': 2.0.3 - '@smithy/util-middleware': 3.0.3 - '@smithy/util-retry': 3.0.2 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.3 - transitivePeerDependencies: - - aws-crt - dev: false - - /@aws-sdk/client-sts/3.600.0_dseaa2p5u2yk67qiepewcq3hkq: - resolution: {integrity: sha512-KQG97B7LvTtTiGmjlrG1LRAY8wUvCQzrmZVV5bjrJ/1oXAU7DITYwVbSJeX9NWg6hDuSk0VE3MFwIXS2SvfLIA==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.600.0 + '@aws-sdk/client-sso-oidc': 3.600.0_tdq3komn4zwyd65w7klbptsu34 '@aws-sdk/core': 3.598.0 '@aws-sdk/credential-provider-node': 3.600.0_f7n47caigsrjd2lr2szmwfuee4 '@aws-sdk/middleware-host-header': 3.598.0 @@ -13137,7 +13140,6 @@ packages: '@smithy/util-utf8': 3.0.0 tslib: 2.6.3 transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - aws-crt dev: false @@ -17467,7 +17469,7 @@ packages: '@aws-sdk/client-sns': 3.423.0 '@aws-sdk/client-sqs': 3.423.0 '@aws-sdk/client-ssm': 3.423.0 - '@aws-sdk/client-sts': 3.600.0_dseaa2p5u2yk67qiepewcq3hkq + '@aws-sdk/client-sts': 3.600.0 '@aws-sdk/s3-request-presigner': 3.609.0 '@pipedream/helper_functions': 0.3.12 '@pipedream/platform': 1.6.6