diff --git a/components/taskade/actions/create-task/create-task.mjs b/components/taskade/actions/create-task/create-task.mjs new file mode 100644 index 0000000000000..8503d903a0609 --- /dev/null +++ b/components/taskade/actions/create-task/create-task.mjs @@ -0,0 +1,75 @@ +import taskade from "../../taskade.app.mjs"; + +export default { + key: "taskade-create-task", + name: "Create Task", + description: "Creates a new task in Taskade. [See the documentation](https://developers.taskade.com/docs/api/tasks/create)", + version: "0.0.1", + type: "action", + props: { + taskade, + projectId: { + propDefinition: [ + taskade, + "projectId", + ], + }, + content: { + type: "string", + label: "Content", + description: "Content of the task", + }, + contentType: { + type: "string", + label: "Content Type", + description: "The type of content", + options: [ + "text/markdown", + "text/plain", + ], + }, + placement: { + type: "string", + label: "Placement", + description: "Placement of the task", + options: [ + "afterbegin", + "beforeend", + ], + }, + assignees: { + type: "string[]", + label: "Assignees", + description: "An array of user handles to assign to the task", + optional: true, + }, + }, + async run({ $ }) { + const task = await this.taskade.createTask({ + $, + projectId: this.projectId, + data: { + tasks: [ + { + content: this.content, + contentType: this.contentType, + placement: this.placement, + }, + ], + }, + }); + const taskId = task.item[0].id; + if (this.assignees?.length) { + await this.taskade.assignTask({ + $, + projectId: this.projectId, + taskId, + data: { + handles: this.assignees, + }, + }); + } + $.export("$summary", `Successfully created task with ID ${taskId}`); + return task; + }, +}; diff --git a/components/taskade/package.json b/components/taskade/package.json index 0d73684f741a9..853933b0fd7c4 100644 --- a/components/taskade/package.json +++ b/components/taskade/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/taskade", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Taskade Components", "main": "taskade.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.0" } -} \ No newline at end of file +} diff --git a/components/taskade/sources/new-task-created/new-task-created.mjs b/components/taskade/sources/new-task-created/new-task-created.mjs new file mode 100644 index 0000000000000..df0961d45fa6d --- /dev/null +++ b/components/taskade/sources/new-task-created/new-task-created.mjs @@ -0,0 +1,77 @@ +import taskade from "../../taskade.app.mjs"; +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; +import sampleEmit from "./test-event.mjs"; + +export default { + key: "taskade-new-task-created", + name: "New Task Created", + description: "Emit new event when a new task is created in Taskade", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + taskade, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + projectId: { + propDefinition: [ + taskade, + "projectId", + ], + }, + }, + hooks: { + async deploy() { + await this.processEvent(25); + }, + }, + methods: { + _getPreviousIds() { + return this.db.get("previousIds") || {}; + }, + _setPreviousIds(previousIds) { + this.db.set("previousIds", previousIds); + }, + emitEvent(task) { + const meta = this.generateMeta(task); + this.$emit(task, meta); + }, + generateMeta(task) { + return { + id: task.id, + summary: `New Task ID: ${task.id}`, + ts: Date.now(), + }; + }, + async processEvent(max) { + const tasks = []; + const items = this.taskade.paginate({ + resourceFn: this.taskade.listTasks, + args: { + projectId: this.projectId, + }, + resourceType: "items", + }); + for await (const item of items) { + tasks.push(item); + } + let previousIds = this._getPreviousIds(); + let newTasks = tasks.filter(({ id }) => !previousIds[id]); + newTasks.forEach(({ id }) => previousIds[id] = true); + this._setPreviousIds(previousIds); + newTasks = max + ? newTasks.slice(0, max) + : newTasks; + newTasks.forEach((task) => this.emitEvent(task)); + }, + }, + async run() { + await this.processEvent(); + }, + sampleEmit, +}; diff --git a/components/taskade/sources/new-task-created/test-event.mjs b/components/taskade/sources/new-task-created/test-event.mjs new file mode 100644 index 0000000000000..fa8da75002090 --- /dev/null +++ b/components/taskade/sources/new-task-created/test-event.mjs @@ -0,0 +1,5 @@ +export default { + "id": "85e89694-3ca9-49ac-8393-4595543d4643", + "text": "Getting Started", + "completed": false +} \ No newline at end of file diff --git a/components/taskade/taskade.app.mjs b/components/taskade/taskade.app.mjs index 44d2adaa8699f..5fda3702c4a67 100644 --- a/components/taskade/taskade.app.mjs +++ b/components/taskade/taskade.app.mjs @@ -1,11 +1,118 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "taskade", - propDefinitions: {}, + propDefinitions: { + projectId: { + type: "string", + label: "Project ID", + description: "The identifier of a project", + async options({ page }) { + const { items } = await this.listProjects({ + params: { + page: page + 1, + }, + }); + return items?.map(({ + id: value, name: label, + }) => ({ + value, + label, + })) || []; + }, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return "https://www.taskade.com/api/v1"; + }, + _makeRequest(opts = {}) { + const { + $ = this, + path, + ...otherOpts + } = opts; + return axios($, { + ...otherOpts, + url: `${this._baseUrl()}${path}`, + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${this.$auth.oauth_access_token}`, + }, + }); + }, + listProjects(opts = {}) { + return this._makeRequest({ + path: "/me/projects", + ...opts, + }); + }, + listTasks({ + projectId, ...opts + }) { + return this._makeRequest({ + path: `/projects/${projectId}/tasks`, + ...opts, + }); + }, + createTask({ + projectId, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: `/projects/${projectId}/tasks`, + ...opts, + }); + }, + assignTask({ + projectId, taskId, ...opts + }) { + return this._makeRequest({ + method: "PUT", + path: `/projects/${projectId}/tasks/${taskId}/assignees`, + ...opts, + }); + }, + createOrUpdateDueDate({ + projectId, taskId, ...opts + }) { + return this._makeRequest({ + method: "PUT", + path: `/projects/${projectId}/tasks/${taskId}/date`, + ...opts, + }); + }, + async *paginate({ + resourceFn, + args, + resourceType, + max, + }) { + args = { + ...args, + params: { + ...args.params, + }, + }; + let count = 0; + do { + const results = await resourceFn(args); + const items = resourceType + ? results[resourceType] + : results; + if (!items?.length) { + return; + } + for (const item of items) { + yield item; + count++; + if (max && max >= count) { + return; + } + } + args.params.after = items[items.length - 1].id; + } while (args.params.after); }, }, }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 71982f6f3c02e..1d701720d6e9b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8950,7 +8950,10 @@ importers: '@pipedream/platform': 1.6.2 components/taskade: - specifiers: {} + specifiers: + '@pipedream/platform': ^3.0.0 + dependencies: + '@pipedream/platform': 3.0.0 components/tave: specifiers: {}