From 9306b4f7f69d15db3e5ff780bd48a6aad1dd2a54 Mon Sep 17 00:00:00 2001 From: Michelle Bergeron Date: Tue, 15 Jul 2025 13:27:03 -0400 Subject: [PATCH 1/4] new components --- .../list-stock-updates/list-stock-updates.mjs | 56 +++++++++++ .../update-stock-update.mjs | 48 ++++++++++ components/channable/channable.app.mjs | 94 ++++++++++++++++++- components/channable/package.json | 7 +- components/channable/sources/common/base.mjs | 84 +++++++++++++++++ .../new-stock-update-created.mjs | 27 ++++++ .../stock-update-updated.mjs | 28 ++++++ 7 files changed, 337 insertions(+), 7 deletions(-) create mode 100644 components/channable/actions/list-stock-updates/list-stock-updates.mjs create mode 100644 components/channable/actions/update-stock-update/update-stock-update.mjs create mode 100644 components/channable/sources/common/base.mjs create mode 100644 components/channable/sources/new-stock-update-created/new-stock-update-created.mjs create mode 100644 components/channable/sources/stock-update-updated/stock-update-updated.mjs diff --git a/components/channable/actions/list-stock-updates/list-stock-updates.mjs b/components/channable/actions/list-stock-updates/list-stock-updates.mjs new file mode 100644 index 0000000000000..46358dabac838 --- /dev/null +++ b/components/channable/actions/list-stock-updates/list-stock-updates.mjs @@ -0,0 +1,56 @@ +import channable from "../../channable.app.mjs"; + +export default { + key: "channable-list-stock-updates", + name: "List Stock Updates", + description: "List stock updates for a company and project. [See the documentation](https://api.channable.com/v1/docs#tag/stock_updates/operation/get_stock_updates_companies__company_id__projects__project_id__offers_get)", + version: "0.0.1", + type: "action", + props: { + channable, + search: { + type: "string", + label: "Search", + description: "A text based search query", + optional: true, + }, + startDate: { + type: "string", + label: "Start Date", + description: "The start date of the stock updates", + optional: true, + }, + endDate: { + type: "string", + label: "End Date", + description: "The end date of the stock updates", + optional: true, + }, + max: { + type: "integer", + label: "Max", + description: "The maximum number of stock updates to return", + default: 100, + optional: true, + }, + }, + async run({ $ }) { + const stockUpdates = await this.channable.getPaginatedResources({ + fn: this.channable.listStockUpdates, + args: { + $, + params: { + search: this.search, + start_date: this.startDate, + end_date: this.endDate, + }, + max: this.max, + }, + resourceKey: "offers", + }); + $.export("$summary", `Found ${stockUpdates.length} stock update${stockUpdates.length === 1 + ? "" + : "s"}`); + return stockUpdates; + }, +}; diff --git a/components/channable/actions/update-stock-update/update-stock-update.mjs b/components/channable/actions/update-stock-update/update-stock-update.mjs new file mode 100644 index 0000000000000..936bb9ea4059e --- /dev/null +++ b/components/channable/actions/update-stock-update/update-stock-update.mjs @@ -0,0 +1,48 @@ +import channable from "../../channable.app.mjs"; + +export default { + key: "channable-update-stock-update", + name: "Update Stock Update", + description: "Update a stock update for a company and project. [See the documentation](https://api.channable.com/v1/docs#tag/stock_updates/operation/stock_updates_update_companies__company_id__projects__project_id__stock_updates_post)", + version: "0.0.1", + type: "action", + props: { + channable, + stockUpdateId: { + propDefinition: [ + channable, + "stockUpdateId", + ], + }, + stock: { + type: "integer", + label: "Stock", + description: "Whole new stock value for the item, not a delta", + }, + title: { + type: "string", + label: "Title", + description: "The title of the stock update", + }, + gtin: { + type: "string", + label: "GTIN", + description: "The GTIN of the item", + }, + }, + async run({ $ }) { + const response = await this.channable.updateStockUpdate({ + $, + data: [ + { + id: this.stockUpdateId, + stock: this.stock, + title: this.title, + gtin: this.gtin, + }, + ], + }); + $.export("$summary", `Updated stock update ${this.stockUpdateId}`); + return response; + }, +}; diff --git a/components/channable/channable.app.mjs b/components/channable/channable.app.mjs index c570231b5cb43..33bc05d4c05e7 100644 --- a/components/channable/channable.app.mjs +++ b/components/channable/channable.app.mjs @@ -1,11 +1,95 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "channable", - propDefinitions: {}, + propDefinitions: { + stockUpdateId: { + type: "string", + label: "Stock Update ID", + description: "The ID of a stock update", + async options({ page }) { + const { offers } = await this.listStockUpdates({ + params: { + limit: 100, + offset: page * 100, + }, + }); + return offers?.map((offer) => ({ + label: offer.label, + value: offer.id, + })) || []; + }, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return "https://api.channable.com/v1"; + }, + _companyId() { + return this.$auth.company_id; + }, + _projectId() { + return this.$auth.project_id; + }, + _makeRequest({ + $ = this, path, ...opts + }) { + return axios($, { + url: `${this._baseUrl()}${path}`, + headers: { + Authorization: `Bearer ${this.$auth.api_token}`, + }, + ...opts, + }); + }, + listStockUpdates(opts = {}) { + return this._makeRequest({ + path: `/companies/${this._companyId()}/projects/${this._projectId()}/offers`, + ...opts, + }); + }, + updateStockUpdate(opts = {}) { + return this._makeRequest({ + path: `/companies/${this._companyId()}/projects/${this._projectId()}/stock_updates`, + method: "POST", + ...opts, + }); + }, + async *paginate({ + fn, args, resourceKey, max, + }) { + args = { + ...args, + params: { + ...args?.params, + limit: 100, + offset: 0, + }, + }; + let total, count = 0; + do { + const response = await fn(args); + const items = response[resourceKey]; + const total = items?.length; + if (!total) { + return; + } + for (const item of items) { + yield item; + if (max && ++count >= max) { + return; + } + } + args.params.offset += args.params.limit; + } while (total === args.params.limit); + }, + async getPaginatedResources(opts) { + const resources = []; + for await (const resource of this.paginate(opts)) { + resources.push(resource); + } + return resources; }, }, -}; \ No newline at end of file +}; diff --git a/components/channable/package.json b/components/channable/package.json index 13de9e940d8a3..c51037d1ff4ed 100644 --- a/components/channable/package.json +++ b/components/channable/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/channable", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Channable Components", "main": "channable.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.1.0" } -} \ No newline at end of file +} diff --git a/components/channable/sources/common/base.mjs b/components/channable/sources/common/base.mjs new file mode 100644 index 0000000000000..974e0f1273fee --- /dev/null +++ b/components/channable/sources/common/base.mjs @@ -0,0 +1,84 @@ +import channable from "../../channable.app.mjs"; +import { + DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, ConfigurationError, +} from "@pipedream/platform"; + +export default { + props: { + channable, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + }, + methods: { + _getLastTs() { + return this.db.get("lastTs"); + }, + _setLastTs(ts) { + this.db.set("lastTs", ts); + }, + getResourceKey() { + return "offers"; + }, + async processEvent(max) { + const lastTs = this._getLastTs(); + let maxTs = lastTs; + const tsField = this.getTsField(); + + const results = await this.channable.paginate({ + fn: this.getResourceFn(), + args: { + params: { + last_modified_after: lastTs, + }, + }, + resourceKey: this.getResourceKey(), + }); + + let items = []; + for await (const result of results) { + const ts = result[tsField]; + if (!maxTs || Date.parse(ts) > Date.parse(maxTs)) { + maxTs = ts; + } + items.push(result); + } + + if (!items.length) { + return; + } + + this._setLastTs(maxTs); + + if (max && items.length > max) { + items = items.slice(0, max); + } + + items.forEach((item) => { + const meta = this.generateMeta(item); + this.$emit(item, meta); + }); + }, + getResourceFn() { + throw new ConfigurationError("getResourceFn must be implemented"); + }, + getTsField() { + throw new ConfigurationError("getTsField must be implemented"); + }, + generateMeta() { + throw new ConfigurationError("generateMeta must be implemented"); + }, + }, + hooks: { + async deploy() { + await this.processEvent(25); + }, + }, + async run() { + await this.processEvent(); + }, +}; diff --git a/components/channable/sources/new-stock-update-created/new-stock-update-created.mjs b/components/channable/sources/new-stock-update-created/new-stock-update-created.mjs new file mode 100644 index 0000000000000..2d8393d5526bc --- /dev/null +++ b/components/channable/sources/new-stock-update-created/new-stock-update-created.mjs @@ -0,0 +1,27 @@ +import common from "../common/base.mjs"; + +export default { + ...common, + key: "channable-new-stock-update-created", + name: "New Stock Update Created", + description: "Emit new event when a new stock update is created. [See the documentation](https://api.channable.com/v1/docs#tag/stock_updates/operation/get_stock_updates_companies__company_id__projects__project_id__offers_get)", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getResourceFn() { + return this.channable.listStockUpdates; + }, + getTsField() { + return "created"; + }, + generateMeta(item) { + return { + id: item.id, + summary: `New stock update created: ${item.id}`, + ts: Date.parse(item.created), + }; + }, + }, +}; diff --git a/components/channable/sources/stock-update-updated/stock-update-updated.mjs b/components/channable/sources/stock-update-updated/stock-update-updated.mjs new file mode 100644 index 0000000000000..9ec16dbcb4119 --- /dev/null +++ b/components/channable/sources/stock-update-updated/stock-update-updated.mjs @@ -0,0 +1,28 @@ +import common from "../common/base.mjs"; + +export default { + ...common, + key: "channable-stock-update-updated", + name: "Stock Update Updated", + description: "Emit new event when a stock update is updated. [See the documentation](https://api.channable.com/v1/docs#tag/stock_updates/operation/get_stock_updates_companies__company_id__projects__project_id__offers_get)", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getResourceFn() { + return this.channable.listStockUpdates; + }, + getTsField() { + return "modified"; + }, + generateMeta(item) { + const ts = Date.parse(item.modified); + return { + id: `${item.id}-${ts}`, + summary: `Stock update updated: ${item.id}`, + ts, + }; + }, + }, +}; From 1002f2ce91124ba7065525245ce9fe8523abe6b7 Mon Sep 17 00:00:00 2001 From: Michelle Bergeron Date: Tue, 15 Jul 2025 13:28:04 -0400 Subject: [PATCH 2/4] pnpm-lock.yaml --- pnpm-lock.yaml | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5097d77eb36e3..dd27f21de734e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1872,8 +1872,7 @@ importers: specifier: ^3.0.0 version: 3.0.3 - components/bright_data: - specifiers: {} + components/bright_data: {} components/brilliant_directories: dependencies: @@ -2271,7 +2270,11 @@ importers: specifier: ^3.1.0 version: 3.1.0 - components/channable: {} + components/channable: + dependencies: + '@pipedream/platform': + specifier: ^3.1.0 + version: 3.1.0 components/channeladvisor: dependencies: @@ -2646,14 +2649,11 @@ importers: specifier: ^1.0.1 version: 1.0.1 - components/clio_australia: - specifiers: {} + components/clio_australia: {} - components/clio_canada: - specifiers: {} + components/clio_canada: {} - components/clio_eu: - specifiers: {} + components/clio_eu: {} components/clockify: dependencies: @@ -11470,8 +11470,7 @@ importers: specifier: ^1.5.1 version: 1.6.6 - components/rhombus: - specifiers: {} + components/rhombus: {} components/richpanel: dependencies: From cb6b9ff7bc86237a716dda86334910d3ddcf915b Mon Sep 17 00:00:00 2001 From: Michelle Bergeron Date: Tue, 15 Jul 2025 13:35:50 -0400 Subject: [PATCH 3/4] update --- components/channable/channable.app.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/channable/channable.app.mjs b/components/channable/channable.app.mjs index 33bc05d4c05e7..50af440abefbc 100644 --- a/components/channable/channable.app.mjs +++ b/components/channable/channable.app.mjs @@ -71,7 +71,7 @@ export default { do { const response = await fn(args); const items = response[resourceKey]; - const total = items?.length; + total = items?.length; if (!total) { return; } From 6dfb0422cb38073319d51009e74656b8b1f61713 Mon Sep 17 00:00:00 2001 From: Michelle Bergeron Date: Wed, 16 Jul 2025 10:43:37 -0400 Subject: [PATCH 4/4] pnpm-lock.yaml --- pnpm-lock.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c54e3882d41a1..a51461c5c41ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8252,8 +8252,7 @@ importers: components/membervault: {} - components/memento_database: - specifiers: {} + components/memento_database: {} components/memix: {} @@ -11573,8 +11572,7 @@ importers: specifier: ^3.1.0 version: 3.1.0 - components/robopost: - specifiers: {} + components/robopost: {} components/rocket_chat: dependencies: