From 75da6d28ba820938ffe0a160e68bd96f5c69169b Mon Sep 17 00:00:00 2001 From: michelle0927 Date: Fri, 18 Apr 2025 10:21:59 -0400 Subject: [PATCH 01/10] wip --- .../add-a-worksheet-tablerow.mjs | 20 +-- .../update-worksheet-tablerow.mjs | 18 +-- .../microsoft_excel/microsoft_excel.app.mjs | 59 +++++---- components/microsoft_excel/package.json | 2 +- .../sources/common/base-polling.mjs | 18 +++ .../sources/common/base-webhook.mjs | 114 ++++++++++++++++++ .../microsoft_excel/sources/common/base.mjs | 14 +++ .../new-item-created/new-item-created.mjs | 23 ++++ .../sources/new-item-created/test-event.mjs | 46 +++++++ .../new-item-updated/new-item-updated.mjs | 87 ++----------- .../sources/new-item-updated/test-event.mjs | 56 +++++++-- 11 files changed, 330 insertions(+), 127 deletions(-) create mode 100644 components/microsoft_excel/sources/common/base-polling.mjs create mode 100644 components/microsoft_excel/sources/common/base-webhook.mjs create mode 100644 components/microsoft_excel/sources/common/base.mjs create mode 100644 components/microsoft_excel/sources/new-item-created/new-item-created.mjs create mode 100644 components/microsoft_excel/sources/new-item-created/test-event.mjs diff --git a/components/microsoft_excel/actions/add-a-worksheet-tablerow/add-a-worksheet-tablerow.mjs b/components/microsoft_excel/actions/add-a-worksheet-tablerow/add-a-worksheet-tablerow.mjs index 102486632e8ba..8034654a63cda 100644 --- a/components/microsoft_excel/actions/add-a-worksheet-tablerow/add-a-worksheet-tablerow.mjs +++ b/components/microsoft_excel/actions/add-a-worksheet-tablerow/add-a-worksheet-tablerow.mjs @@ -3,8 +3,8 @@ import microsoftExcel from "../../microsoft_excel.app.mjs"; export default { key: "microsoft_excel-add-a-worksheet-tablerow", - name: "Add A Worksheet Tablerow", - version: "0.0.4", + name: "Add a Worksheet Tablerow", + version: "0.0.5", description: "Adds rows to the end of specific table. [See the documentation](https://learn.microsoft.com/en-us/graph/api/tablerowcollection-add?view=graph-rest-1.0&tabs=http)", type: "action", props: { @@ -15,10 +15,10 @@ export default { "folderId", ], }, - itemId: { + sheetId: { propDefinition: [ microsoftExcel, - "itemId", + "sheetId", ({ folderId }) => ({ folderId, }), @@ -29,8 +29,8 @@ export default { propDefinition: [ microsoftExcel, "tableId", - ({ itemId }) => ({ - itemId, + ({ sheetId }) => ({ + sheetId, }), ], hidden: true, @@ -49,10 +49,10 @@ export default { }, }, async additionalProps(props) { - if (this.itemId) { + if (this.sheetId) { try { await this.microsoftExcel.listTables({ - itemId: this.itemId, + sheetId: this.sheetId, }); } catch { props.tableName.hidden = false; @@ -65,7 +65,7 @@ export default { async run({ $ }) { const { microsoftExcel, - itemId, + sheetId, tableId, tableName, values, @@ -73,7 +73,7 @@ export default { const response = await microsoftExcel.addRow({ $, - itemId, + sheetId, tableId, tableName, data: { diff --git a/components/microsoft_excel/actions/update-worksheet-tablerow/update-worksheet-tablerow.mjs b/components/microsoft_excel/actions/update-worksheet-tablerow/update-worksheet-tablerow.mjs index 91c321da43468..a23c15e244aa0 100644 --- a/components/microsoft_excel/actions/update-worksheet-tablerow/update-worksheet-tablerow.mjs +++ b/components/microsoft_excel/actions/update-worksheet-tablerow/update-worksheet-tablerow.mjs @@ -3,7 +3,7 @@ import microsoftExcel from "../../microsoft_excel.app.mjs"; export default { key: "microsoft_excel-update-worksheet-tablerow", name: "Update Worksheet Tablerow", - version: "0.0.4", + version: "0.0.5", description: "Update the properties of tablerow object. `(Only for work or school account)` [See the documentation](https://learn.microsoft.com/en-us/graph/api/tablerow-update?view=graph-rest-1.0&tabs=http)", type: "action", props: { @@ -14,10 +14,10 @@ export default { "folderId", ], }, - itemId: { + sheetId: { propDefinition: [ microsoftExcel, - "itemId", + "sheetId", ({ folderId }) => ({ folderId, }), @@ -27,8 +27,8 @@ export default { propDefinition: [ microsoftExcel, "tableId", - ({ itemId }) => ({ - itemId, + ({ sheetId }) => ({ + sheetId, }), ], }, @@ -37,9 +37,9 @@ export default { microsoftExcel, "rowId", ({ - itemId, tableId, + sheetId, tableId, }) => ({ - itemId, + sheetId, tableId, }), ], @@ -55,7 +55,7 @@ export default { async run({ $ }) { const { microsoftExcel, - itemId, + sheetId, tableId, rowId, values, @@ -63,7 +63,7 @@ export default { const response = await microsoftExcel.updateRow({ $, - itemId, + sheetId, tableId, rowId, data: { diff --git a/components/microsoft_excel/microsoft_excel.app.mjs b/components/microsoft_excel/microsoft_excel.app.mjs index 4b10d83fdcfcc..3dbc34139e43b 100644 --- a/components/microsoft_excel/microsoft_excel.app.mjs +++ b/components/microsoft_excel/microsoft_excel.app.mjs @@ -6,8 +6,8 @@ export default { propDefinitions: { folderId: { type: "string", - label: "Folder Id", - description: "The ID of the folder where the item is located.", + label: "Folder ID", + description: "The ID of the folder where the item is located", async options() { const folders = await this.listFolderOptions(); return [ @@ -16,15 +16,14 @@ export default { ]; }, }, - itemId: { + sheetId: { type: "string", - label: "Item Id", - description: "The Id of the item you want to use.", + label: "Sheet ID", + description: "The ID of the spreadsheet you want to use", async options({ folderId }) { const { value } = await this.listItems({ folderId, }); - return value.filter( (item) => item.file?.mimeType === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ).map(({ @@ -37,13 +36,13 @@ export default { }, rowId: { type: "string", - label: "Row Id", - description: "The Id of the row you want to use.", + label: "Row ID", + description: "The ID of the row you want to use", async options({ - itemId, tableId, + sheetId, tableId, }) { const { value } = await this.listRows({ - itemId, + sheetId, tableId, }); @@ -57,11 +56,11 @@ export default { }, tableId: { type: "string", - label: "Table Id", - description: "The Id of the table you want to use.", - async options({ itemId }) { + label: "Table ID", + description: "The ID of the table you want to use", + async options({ sheetId }) { const { value } = await this.listTables({ - itemId, + sheetId, }); return value.map(({ @@ -99,11 +98,11 @@ export default { return axios($, config); }, addRow({ - itemId, tableId, tableName, ...args + sheetId, tableId, tableName, ...args }) { return this._makeRequest({ method: "POST", - path: `me/drive/items/${itemId}/workbook/tables/${tableId || tableName}/rows/add`, + path: `me/drive/items/${sheetId}/workbook/tables/${tableId || tableName}/rows/add`, ...args, }); }, @@ -131,28 +130,28 @@ export default { }); }, listRows({ - itemId, tableId, ...args + sheetId, tableId, ...args }) { return this._makeRequest({ - path: `me/drive/items/${itemId}/workbook/tables/${tableId}/rows`, + path: `me/drive/items/${sheetId}/workbook/tables/${tableId}/rows`, ...args, }); }, // List tables endpoint is not supported for personal accounts listTables({ - itemId, ...args + sheetId, ...args }) { return this._makeRequest({ - path: `me/drive/items/${itemId}/workbook/tables`, + path: `me/drive/items/${sheetId}/workbook/tables`, ...args, }); }, updateRow({ - itemId, tableId, rowId, ...args + sheetId, tableId, rowId, ...args }) { return this._makeRequest({ method: "PATCH", - path: `me/drive/items/${itemId}/workbook/tables/${tableId}/rows/itemAt(index=${rowId})`, + path: `me/drive/items/${sheetId}/workbook/tables/${tableId}/rows/itemAt(index=${rowId})`, ...args, }); }, @@ -172,6 +171,22 @@ export default { ...args, }); }, + getDriveItem({ + itemId, ...args + }) { + return this._makeRequest({ + path: `me/drive/items/${itemId}`, + ...args, + }); + }, + getDelta({ + path, token, ...args + }) { + return this._makeRequest({ + path: `${path}/delta?token=${token}`, + ...args, + }); + }, async listFolderOptions({ folderId = null, prefix = "", batchLimit = 20, ...args } = {}) { diff --git a/components/microsoft_excel/package.json b/components/microsoft_excel/package.json index 565385837fc08..1c018071ae470 100644 --- a/components/microsoft_excel/package.json +++ b/components/microsoft_excel/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/microsoft_excel", - "version": "0.1.3", + "version": "0.2.0", "description": "Pipedream Microsoft Excel Components", "main": "microsoft_excel.app.mjs", "keywords": [ diff --git a/components/microsoft_excel/sources/common/base-polling.mjs b/components/microsoft_excel/sources/common/base-polling.mjs new file mode 100644 index 0000000000000..57542f3d51775 --- /dev/null +++ b/components/microsoft_excel/sources/common/base-polling.mjs @@ -0,0 +1,18 @@ +import common from "./base.mjs"; +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; + +export default { + ...common, + props: { + ...common.props, + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + }, + async run() { + + }, +}; diff --git a/components/microsoft_excel/sources/common/base-webhook.mjs b/components/microsoft_excel/sources/common/base-webhook.mjs new file mode 100644 index 0000000000000..6ad893acb7e6e --- /dev/null +++ b/components/microsoft_excel/sources/common/base-webhook.mjs @@ -0,0 +1,114 @@ +import moment from "moment"; +import common from "./base.mjs"; + +export default { + ...common, + props: { + ...common.props, + http: { + type: "$.interface.http", + customResponse: true, + }, + folderId: { + propDefinition: [ + common.props.microsoftExcel, + "folderId", + ], + description: "The ID of the folder to watch for changes", + }, + }, + hooks: { + async activate() { + const response = await this.microsoftExcel.createHook({ + data: { + changeType: "updated", + notificationUrl: this.http.endpoint, + resource: "me/drive/root", + expirationDateTime: moment().add(30, "days"), + }, + }); + + this._setHookId(response.id); + + const { token } = await this.getDeltaValues(this.path(), "latest"); + this._setDeltaToken(token); + }, + async deactivate() { + const id = this._getHookId("hookId"); + await this.microsoftExcel.deleteHook(id); + }, + }, + methods: { + ...common.methods, + _getHookId() { + return this.db.get("hookId"); + }, + _setHookId(hookId) { + this.db.set("hookId", hookId); + }, + _getDeltaToken() { + return this.db.get("deltaToken"); + }, + _setDeltaToken(token) { + this.db.set("deltaToken", token); + }, + async updateSubscription() { + const hookId = this._getHookId(); + await this.microsoftExcel.updateSubscription({ + hookId, + data: { + expirationDateTime: moment().add(30, "days"), + }, + }); + }, + path() { + return this.folderId === "root" + ? "me/drive/root" + : `me/drive/items/${this.folderId}`; + }, + async getDeltaValues(path, token) { + const delta = await this.microsoftExcel.getDelta({ + path, + token, + }); + const deltaLink = delta["@odata.deltaLink"] || delta["@odata.nextLink"]; + return { + value: delta?.value, + token: new URL(deltaLink).searchParams.get("token"), + }; + }, + }, + async run({ query }) { + if (query.validationToken) { + this.http.respond({ + status: 200, + body: query.validationToken, + headers: { + "content-type": "text/plan", + }, + }); + return; + } + + let deltaValues; + try { + deltaValues = await this.getDeltaValues(this.path(), this._getDeltaToken()); + } catch { + deltaValues = await this.getDeltaValues(this.path(), "latest"); + } + const { + value, token, + } = deltaValues; + + await this.updateSubscription(); + this._setDeltaToken(token); + + const spreadsheets = value.filter(({ file }) => file?.mimeType === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + + if (!spreadsheets?.length) { + return; + } + + spreadsheets.forEach((item) => this.emitEvent(item)); + }, +}; diff --git a/components/microsoft_excel/sources/common/base.mjs b/components/microsoft_excel/sources/common/base.mjs new file mode 100644 index 0000000000000..f4a3d222efdc3 --- /dev/null +++ b/components/microsoft_excel/sources/common/base.mjs @@ -0,0 +1,14 @@ +import microsoftExcel from "../../microsoft_excel.app.mjs"; + +export default { + props: { + microsoftExcel, + db: "$.service.db", + }, + methods: { + emitEvent(item) { + const meta = this.generateMeta(item); + this.$emit(item, meta); + }, + }, +}; diff --git a/components/microsoft_excel/sources/new-item-created/new-item-created.mjs b/components/microsoft_excel/sources/new-item-created/new-item-created.mjs new file mode 100644 index 0000000000000..88792198c2e88 --- /dev/null +++ b/components/microsoft_excel/sources/new-item-created/new-item-created.mjs @@ -0,0 +1,23 @@ +import common from "../common/base-webhook.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + dedupe: "unique", + key: "microsoft_excel-new-item-created", + name: "New Spreadsheet Created (Instant)", + description: "Emit new event when a new Excel spreadsheet is created.", + version: "0.0.{{ts}}", + type: "source", + methods: { + ...common.methods, + generateMeta(item) { + return { + id: `${item.id}`, + summary: `Item ${item.name} created`, + ts: Date.parse(item.createdDateTime), + }; + }, + }, + sampleEmit, +}; diff --git a/components/microsoft_excel/sources/new-item-created/test-event.mjs b/components/microsoft_excel/sources/new-item-created/test-event.mjs new file mode 100644 index 0000000000000..f9a1165a44a24 --- /dev/null +++ b/components/microsoft_excel/sources/new-item-created/test-event.mjs @@ -0,0 +1,46 @@ +export default { + "@microsoft.graph.downloadUrl": "", + "createdDateTime": "2025-04-17T21:06:34.207Z", + "cTag": "", + "eTag": "", + "id": "", + "lastModifiedDateTime": "2025-04-17T21:06:37.6Z", + "name": "Book.xlsx", + "size": 8176, + "webUrl": "", + "reactions": { + "commentCount": 0 + }, + "createdBy": { + "application": { + "id": "" + }, + "user": { + "displayName": "", + "id": "" + } + }, + "lastModifiedBy": { + "user": { + "displayName": "", + "id": "" + } + }, + "parentReference": { + "driveId": "", + "driveType": "personal", + "id": "", + "name": "Documents", + "path": "/drive/root:/Documents" + }, + "file": { + "mimeType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "hashes": { + "quickXorHash": "" + } + }, + "fileSystemInfo": { + "createdDateTime": "2025-04-17T21:06:34.206Z", + "lastModifiedDateTime": "2025-04-17T21:06:37.583Z" + } +} \ No newline at end of file diff --git a/components/microsoft_excel/sources/new-item-updated/new-item-updated.mjs b/components/microsoft_excel/sources/new-item-updated/new-item-updated.mjs index b0560234f0b72..643ae7e823588 100644 --- a/components/microsoft_excel/sources/new-item-updated/new-item-updated.mjs +++ b/components/microsoft_excel/sources/new-item-updated/new-item-updated.mjs @@ -1,89 +1,24 @@ -import moment from "moment"; -import microsoftExcel from "../../microsoft_excel.app.mjs"; +import common from "../common/base-webhook.mjs"; import sampleEmit from "./test-event.mjs"; export default { + ...common, dedupe: "unique", key: "microsoft_excel-new-item-updated", - name: "New Item Updated (Instant)", - description: "Emit new event when an item is updated.", - version: "0.0.4", + name: "New Spreadsheet Updated (Instant)", + description: "Emit new event when an Excel spreadsheet is updated.", + version: "0.0.5", type: "source", - props: { - microsoftExcel, - http: { - type: "$.interface.http", - customResponse: true, - }, - db: "$.service.db", - }, - hooks: { - async activate() { - const response = await this.microsoftExcel.createHook({ - data: { - changeType: "updated", - notificationUrl: this.http.endpoint, - resource: "me/drive/root", - expirationDateTime: moment().add(30, "days"), - }, - }); - - this._setHookId(response.id); - }, - async deactivate() { - const id = this._getHookId("hookId"); - await this.microsoftExcel.deleteHook(id); - }, - }, methods: { - emitEvent(body) { - const meta = this.generateMeta(body); - this.$emit(body, meta); - }, - _getHookId() { - return this.db.get("hookId"); - }, - _setHookId(hookId) { - this.db.set("hookId", hookId); - }, - generateMeta(body) { - const { value } = body; - - const ts = new Date(); + ...common.methods, + generateMeta(item) { + const ts = Date.parse(item.lastModifiedDateTime); return { - id: `${value[0].tenantId}${ts}`, - summary: `The item ${value[0].tenantId - ? `with TenantId: ${value[0].tenantId} ` - : " "}was updated!`, - ts: ts, + id: `${item.id}${ts}`, + summary: `Item ${item.name} was updated`, + ts, }; }, - async updateSubscription() { - const hookId = this._getHookId(); - await this.microsoftExcel.updateSubscription({ - hookId, - data: { - expirationDateTime: moment().add(30, "days"), - }, - }); - }, - }, - async run({ - body, query, - }) { - if (query.validationToken) { - this.http.respond({ - status: 200, - body: query.validationToken, - headers: { - "content-type": "text/plan", - }, - }); - return; - } - - this.emitEvent(body); - await this.updateSubscription(); }, sampleEmit, }; diff --git a/components/microsoft_excel/sources/new-item-updated/test-event.mjs b/components/microsoft_excel/sources/new-item-updated/test-event.mjs index e00e7ea6c9307..9d8788646145b 100644 --- a/components/microsoft_excel/sources/new-item-updated/test-event.mjs +++ b/components/microsoft_excel/sources/new-item-updated/test-event.mjs @@ -1,11 +1,49 @@ export default { - "value": [{ - "subscriptionId": "109f1232-d794-1122-aabc-e12345afa726", - "clientState": null, - "resource": "me/drive/root", - "tenantId": "109f1232-d794-1122-aabc-e12345afa726", - "resourceData": null, - "subscriptionExpirationDateTime": "2024-10-22T12:02:12.637+00:00", - "changeType": "updated" - }] + "@microsoft.graph.downloadUrl": "", + "createdDateTime": "2024-08-02T18:04:17.28Z", + "cTag": "", + "eTag": "", + "id": "", + "lastModifiedDateTime": "2025-04-17T19:19:55.427Z", + "name": "Book.xlsx", + "size": 10367, + "webUrl": "", + "reactions": { + "commentCount": 0 + }, + "createdBy": { + "application": { + "id": "" + }, + "user": { + "displayName": "", + "id": "" + } + }, + "lastModifiedBy": { + "application": { + "id": "" + }, + "user": { + "displayName": "", + "id": "" + } + }, + "parentReference": { + "driveId": "", + "driveType": "personal", + "id": "", + "name": "root:", + "path": "/drive/root:" + }, + "file": { + "mimeType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "hashes": { + "quickXorHash": "" + } + }, + "fileSystemInfo": { + "createdDateTime": "2024-08-02T18:04:17.28Z", + "lastModifiedDateTime": "2025-04-17T19:19:55.103Z" + } } \ No newline at end of file From 82900f8cac7072d43c53c9fd53f6ca3bc89f05c5 Mon Sep 17 00:00:00 2001 From: michelle0927 Date: Fri, 18 Apr 2025 16:54:58 -0400 Subject: [PATCH 02/10] updates & new components --- .../add-a-worksheet-tablerow.mjs | 2 +- .../actions/add-row/add-row.mjs | 87 +++++++++++++++++++ .../actions/find-row/find-row.mjs | 81 +++++++++++++++++ .../actions/get-columns/get-columns.mjs | 63 ++++++++++++++ .../get-spreadsheet/get-spreadsheet.mjs | 63 ++++++++++++++ .../actions/get-table-rows/get-table-rows.mjs | 61 +++++++++++++ .../actions/update-cell/update-cell.mjs | 63 ++++++++++++++ .../update-worksheet-tablerow.mjs | 4 +- .../microsoft_excel/microsoft_excel.app.mjs | 73 ++++++++++++++-- components/microsoft_excel/package.json | 1 + .../sources/common/base-polling.mjs | 27 +++++- .../sources/common/base-webhook.mjs | 6 +- .../new-cell-value-changed.mjs | 58 +++++++++++++ .../new-item-created/new-item-created.mjs | 28 +++++- .../sources/new-row-added/new-row-added.mjs | 47 ++++++++++ 15 files changed, 649 insertions(+), 15 deletions(-) create mode 100644 components/microsoft_excel/actions/add-row/add-row.mjs create mode 100644 components/microsoft_excel/actions/find-row/find-row.mjs create mode 100644 components/microsoft_excel/actions/get-columns/get-columns.mjs create mode 100644 components/microsoft_excel/actions/get-spreadsheet/get-spreadsheet.mjs create mode 100644 components/microsoft_excel/actions/get-table-rows/get-table-rows.mjs create mode 100644 components/microsoft_excel/actions/update-cell/update-cell.mjs create mode 100644 components/microsoft_excel/sources/new-cell-value-changed/new-cell-value-changed.mjs create mode 100644 components/microsoft_excel/sources/new-row-added/new-row-added.mjs diff --git a/components/microsoft_excel/actions/add-a-worksheet-tablerow/add-a-worksheet-tablerow.mjs b/components/microsoft_excel/actions/add-a-worksheet-tablerow/add-a-worksheet-tablerow.mjs index 8034654a63cda..cb3f570004505 100644 --- a/components/microsoft_excel/actions/add-a-worksheet-tablerow/add-a-worksheet-tablerow.mjs +++ b/components/microsoft_excel/actions/add-a-worksheet-tablerow/add-a-worksheet-tablerow.mjs @@ -71,7 +71,7 @@ export default { values, } = this; - const response = await microsoftExcel.addRow({ + const response = await microsoftExcel.addTableRow({ $, sheetId, tableId, diff --git a/components/microsoft_excel/actions/add-row/add-row.mjs b/components/microsoft_excel/actions/add-row/add-row.mjs new file mode 100644 index 0000000000000..4f67463d51f8c --- /dev/null +++ b/components/microsoft_excel/actions/add-row/add-row.mjs @@ -0,0 +1,87 @@ +import microsoftExcel from "../../microsoft_excel.app.mjs"; + +export default { + key: "microsoft_excel-add-row", + name: "Add Row", + description: "Insert a new row into a specified Excel worksheet. [See the documentation](https://learn.microsoft.com/en-us/graph/api/range-insert?view=graph-rest-1.0&tabs=http)", + version: "0.0.1", + type: "action", + props: { + microsoftExcel, + folderId: { + propDefinition: [ + microsoftExcel, + "folderId", + ], + }, + sheetId: { + propDefinition: [ + microsoftExcel, + "sheetId", + ({ folderId }) => ({ + folderId, + }), + ], + }, + worksheet: { + propDefinition: [ + microsoftExcel, + "worksheet", + ({ sheetId }) => ({ + sheetId, + }), + ], + }, + values: { + type: "string[]", + label: "Values", + description: "An array of values for the new row. Each item in the array represents one cell. E.g. `[1, 2, 3]`", + }, + }, + async run({ $ }) { + const { address } = await this.microsoftExcel.getUsedRange({ + $, + sheetId: this.sheetId, + worksheet: this.worksheet, + }); + + // get next row range + const match = address.match(/^(.+!)?([A-Z]+)(\d+):([A-Z]+)(\d+)$/); + const [ + , sheet = "", + colStart, + /* eslint-disable no-unused-vars */ + rowStart, + colEnd, + ] = match; + const nextRow = parseInt(match[5], 10) + 1; + const range = `${sheet}${colStart}${nextRow}:${colEnd}${nextRow}`; + + // insert range + await this.microsoftExcel.insertRange({ + $, + sheetId: this.sheetId, + worksheet: this.worksheet, + range, + data: { + shift: "Down", + }, + }); + + // update range + const response = await this.microsoftExcel.updateRange({ + $, + sheetId: this.sheetId, + worksheet: this.worksheet, + range, + data: { + values: [ + this.values, + ], + }, + }); + + $.export("$summary", "Successfully added new row"); + return response; + }, +}; diff --git a/components/microsoft_excel/actions/find-row/find-row.mjs b/components/microsoft_excel/actions/find-row/find-row.mjs new file mode 100644 index 0000000000000..e8905ecbe153e --- /dev/null +++ b/components/microsoft_excel/actions/find-row/find-row.mjs @@ -0,0 +1,81 @@ +import microsoftExcel from "../../microsoft_excel.app.mjs"; + +export default { + key: "microsoft_excel-find-row", + name: "Find Row", + description: "Find a row by column and value in an Excel worksheet. [See the documentation](https://learn.microsoft.com/en-us/graph/api/range-get?view=graph-rest-1.0&tabs=http)", + version: "0.0.1", + type: "action", + props: { + microsoftExcel, + folderId: { + propDefinition: [ + microsoftExcel, + "folderId", + ], + }, + sheetId: { + propDefinition: [ + microsoftExcel, + "sheetId", + ({ folderId }) => ({ + folderId, + }), + ], + }, + worksheet: { + propDefinition: [ + microsoftExcel, + "worksheet", + ({ sheetId }) => ({ + sheetId, + }), + ], + }, + column: { + type: "string[]", + label: "Column", + description: "The column to search. E.g. `A`", + }, + value: { + type: "string", + label: "Value", + description: "The value to search for. For non-string values, use a custom expression. For example: `{{ 1 }}` for the numeric value 1", + }, + }, + async run({ $ }) { + const { + rowCount, address, + } = await this.microsoftExcel.getUsedRange({ + $, + sheetId: this.sheetId, + worksheet: this.worksheet, + }); + const lastColumn = address.match(/:([A-Z]+)\d+$/)[1]; + + const { values: rangeValues } = await this.microsoftExcel.getRange({ + $, + sheetId: this.sheetId, + worksheet: this.worksheet, + range: `${this.worksheet}!${this.column}1:${this.column}${rowCount}`, + }); + const values = rangeValues.map((v) => v[0]); + const index = values.indexOf(this.value); + + if (index === -1) { + $.export("$summary", "No matching rows found"); + return values; + } + + const row = index + 1; + const response = await this.microsoftExcel.getRange({ + $, + sheetId: this.sheetId, + worksheet: this.worksheet, + range: `${this.worksheet}!A${row}:${lastColumn}${row}`, + }); + + $.export("$summary", `Found value in row ${row}`); + return response; + }, +}; diff --git a/components/microsoft_excel/actions/get-columns/get-columns.mjs b/components/microsoft_excel/actions/get-columns/get-columns.mjs new file mode 100644 index 0000000000000..03386ca014381 --- /dev/null +++ b/components/microsoft_excel/actions/get-columns/get-columns.mjs @@ -0,0 +1,63 @@ +import microsoftExcel from "../../microsoft_excel.app.mjs"; + +export default { + key: "microsoft_excel-get-columns", + name: "Get Columns", + description: "Get the values of the specified columns in an Excel worksheet. [See the documentation](https://learn.microsoft.com/en-us/graph/api/range-get?view=graph-rest-1.0&tabs=http)", + version: "0.0.1", + type: "action", + props: { + microsoftExcel, + folderId: { + propDefinition: [ + microsoftExcel, + "folderId", + ], + }, + sheetId: { + propDefinition: [ + microsoftExcel, + "sheetId", + ({ folderId }) => ({ + folderId, + }), + ], + }, + worksheet: { + propDefinition: [ + microsoftExcel, + "worksheet", + ({ sheetId }) => ({ + sheetId, + }), + ], + }, + columns: { + type: "string[]", + label: "Columns", + description: "An array of column labels to retrieve. E.g. [\"A\", \"C\"]", + }, + }, + async run({ $ }) { + const { rowCount } = await this.microsoftExcel.getUsedRange({ + $, + sheetId: this.sheetId, + worksheet: this.worksheet, + }); + + const values = {}; + for (const column of this.columns) { + const response = await this.microsoftExcel.getRange({ + $, + sheetId: this.sheetId, + worksheet: this.worksheet, + range: `${this.worksheet}!${column}1:${column}${rowCount}`, + }); + values[column] = response.values.map((v) => v[0]); + } + + $.export("$summary", "Successfully retrieved column values"); + + return values; + }, +}; diff --git a/components/microsoft_excel/actions/get-spreadsheet/get-spreadsheet.mjs b/components/microsoft_excel/actions/get-spreadsheet/get-spreadsheet.mjs new file mode 100644 index 0000000000000..f1ae2258f7ede --- /dev/null +++ b/components/microsoft_excel/actions/get-spreadsheet/get-spreadsheet.mjs @@ -0,0 +1,63 @@ +import microsoftExcel from "../../microsoft_excel.app.mjs"; +import { json2csv } from "json-2-csv"; + +export default { + key: "microsoft_excel-get-spreadsheet", + name: "Get Spreadsheet", + description: "Get the values of a specified Excel worksheet. [See the documentation](https://learn.microsoft.com/en-us/graph/api/range-get?view=graph-rest-1.0&tabs=http)", + version: "0.0.1", + type: "action", + props: { + microsoftExcel, + folderId: { + propDefinition: [ + microsoftExcel, + "folderId", + ], + }, + sheetId: { + propDefinition: [ + microsoftExcel, + "sheetId", + ({ folderId }) => ({ + folderId, + }), + ], + }, + worksheet: { + propDefinition: [ + microsoftExcel, + "worksheet", + ({ sheetId }) => ({ + sheetId, + }), + ], + }, + range: { + type: "string", + label: "Range", + description: "The range within the worksheet to retrieve. E.g. `A1:C4`. If not specified, entire \"usedRange\" will be returned", + optional: true, + }, + }, + async run({ $ }) { + const response = this.range + ? await this.microsoftExcel.getRange({ + $, + sheetId: this.sheetId, + worksheet: this.worksheet, + range: `${this.worksheet}!${this.range}`, + }) + : await this.microsoftExcel.getUsedRange({ + $, + sheetId: this.sheetId, + worksheet: this.worksheet, + }); + + const csv = await json2csv(response.values); + response.csv = csv; + + $.export("$summary", "Successfully retrieved spreadsheet values"); + return response; + }, +}; diff --git a/components/microsoft_excel/actions/get-table-rows/get-table-rows.mjs b/components/microsoft_excel/actions/get-table-rows/get-table-rows.mjs new file mode 100644 index 0000000000000..00682dbbe86c4 --- /dev/null +++ b/components/microsoft_excel/actions/get-table-rows/get-table-rows.mjs @@ -0,0 +1,61 @@ +import microsoftExcel from "../../microsoft_excel.app.mjs"; + +export default { + key: "microsoft_excel-get-table-rows", + name: "Get Table Rows", + description: "Retrieve rows from a specified table in an Excel worksheet. [See the documentation](https://learn.microsoft.com/en-us/graph/api/tablerow-list?view=graph-rest-1.0&tabs=http)", + version: "0.0.1", + type: "action", + props: { + microsoftExcel, + folderId: { + propDefinition: [ + microsoftExcel, + "folderId", + ], + }, + sheetId: { + propDefinition: [ + microsoftExcel, + "sheetId", + ({ folderId }) => ({ + folderId, + }), + ], + }, + tableId: { + propDefinition: [ + microsoftExcel, + "tableId", + ({ sheetId }) => ({ + sheetId, + }), + ], + }, + }, + async run({ $ }) { + const rows = []; + const params = { + $top: 100, + $skip: 0, + }; + let total; + + do { + const { value } = await this.microsoftExcel.listTableRows({ + $, + sheetId: this.sheetId, + tableId: this.tableId, + params, + }); + rows.push(...value); + total = value.length; + params["$skip"] += params["$top"]; + } while (total); + + $.export("$summary", `Successfully retrieved ${rows.length} row${rows.length === 1 + ? "" + : "s"}`); + return rows; + }, +}; diff --git a/components/microsoft_excel/actions/update-cell/update-cell.mjs b/components/microsoft_excel/actions/update-cell/update-cell.mjs new file mode 100644 index 0000000000000..c59801f304d7f --- /dev/null +++ b/components/microsoft_excel/actions/update-cell/update-cell.mjs @@ -0,0 +1,63 @@ +import microsoftExcel from "../../microsoft_excel.app.mjs"; + +export default { + key: "microsoft_excel-update-cell", + name: "Update Cell", + description: "Update the value of a specific cell in an Excel worksheet. [See the documentation](https://learn.microsoft.com/en-us/graph/api/range-update?view=graph-rest-1.0&tabs=http)", + version: "0.0.1", + type: "action", + props: { + microsoftExcel, + folderId: { + propDefinition: [ + microsoftExcel, + "folderId", + ], + }, + sheetId: { + propDefinition: [ + microsoftExcel, + "sheetId", + ({ folderId }) => ({ + folderId, + }), + ], + }, + worksheet: { + propDefinition: [ + microsoftExcel, + "worksheet", + ({ sheetId }) => ({ + sheetId, + }), + ], + }, + cell: { + type: "string", + label: "Cell", + description: "The address of the cell to update. E.g. `A1`", + }, + value: { + type: "string", + label: "Value", + description: "The value to enter in the cell", + }, + }, + async run({ $ }) { + const response = await this.microsoftExcel.updateRange({ + $, + sheetId: this.sheetId, + worksheet: this.worksheet, + range: `${this.worksheet}!${this.cell}:${this.cell}`, + data: { + values: [ + [ + this.value, + ], + ], + }, + }); + $.export("$summary", `Successfully updated cell \`${this.cell}\``); + return response; + }, +}; diff --git a/components/microsoft_excel/actions/update-worksheet-tablerow/update-worksheet-tablerow.mjs b/components/microsoft_excel/actions/update-worksheet-tablerow/update-worksheet-tablerow.mjs index a23c15e244aa0..e90d06bf5b1d7 100644 --- a/components/microsoft_excel/actions/update-worksheet-tablerow/update-worksheet-tablerow.mjs +++ b/components/microsoft_excel/actions/update-worksheet-tablerow/update-worksheet-tablerow.mjs @@ -35,7 +35,7 @@ export default { rowId: { propDefinition: [ microsoftExcel, - "rowId", + "tableRowId", ({ sheetId, tableId, }) => ({ @@ -61,7 +61,7 @@ export default { values, } = this; - const response = await microsoftExcel.updateRow({ + const response = await microsoftExcel.updateTableRow({ $, sheetId, tableId, diff --git a/components/microsoft_excel/microsoft_excel.app.mjs b/components/microsoft_excel/microsoft_excel.app.mjs index 3dbc34139e43b..1a17fd7ea3ebb 100644 --- a/components/microsoft_excel/microsoft_excel.app.mjs +++ b/components/microsoft_excel/microsoft_excel.app.mjs @@ -1,4 +1,5 @@ import { axios } from "@pipedream/platform"; +const DEFAULT_LIMIT = 50; export default { type: "app", @@ -34,18 +35,35 @@ export default { })); }, }, - rowId: { + worksheet: { + type: "string", + label: "Worksheet", + description: "The name of the worksheet to use", + async options({ + sheetId, page, + }) { + const limit = DEFAULT_LIMIT; + const { value } = await this.listWorksheets({ + sheetId, + params: { + $top: limit, + $skip: limit * page, + }, + }); + return value.map(({ name }) => name ); + }, + }, + tableRowId: { type: "string", label: "Row ID", description: "The ID of the row you want to use", async options({ sheetId, tableId, }) { - const { value } = await this.listRows({ + const { value } = await this.listTableRows({ sheetId, tableId, }); - return value.map(({ index: value, values, }) => ({ @@ -62,7 +80,6 @@ export default { const { value } = await this.listTables({ sheetId, }); - return value.map(({ id: value, name: label, }) => ({ @@ -97,7 +114,7 @@ export default { return axios($, config); }, - addRow({ + addTableRow({ sheetId, tableId, tableName, ...args }) { return this._makeRequest({ @@ -129,7 +146,7 @@ export default { ...args, }); }, - listRows({ + listTableRows({ sheetId, tableId, ...args }) { return this._makeRequest({ @@ -146,7 +163,15 @@ export default { ...args, }); }, - updateRow({ + listWorksheets({ + sheetId, ...args + }) { + return this._makeRequest({ + path: `/me/drive/items/${sheetId}/workbook/worksheets`, + ...args, + }); + }, + updateTableRow({ sheetId, tableId, rowId, ...args }) { return this._makeRequest({ @@ -187,6 +212,40 @@ export default { ...args, }); }, + getRange({ + sheetId, worksheet, range, ...args + }) { + return this._makeRequest({ + path: `me/drive/items/${sheetId}/workbook/worksheets/${worksheet}/range(address='${range}')`, + ...args, + }); + }, + getUsedRange({ + sheetId, worksheet, ...args + }) { + return this._makeRequest({ + path: `me/drive/items/${sheetId}/workbook/worksheets/${worksheet}/range/usedRange`, + ...args, + }); + }, + insertRange({ + sheetId, worksheet, range, ...args + }) { + return this._makeRequest({ + method: "POST", + path: `me/drive/items/${sheetId}/workbook/worksheets/${worksheet}/range(address='${range}')/insert`, + ...args, + }); + }, + updateRange({ + sheetId, worksheet, range, ...args + }) { + return this._makeRequest({ + method: "PATCH", + path: `me/drive/items/${sheetId}/workbook/worksheets/${worksheet}/range(address='${range}')`, + ...args, + }); + }, async listFolderOptions({ folderId = null, prefix = "", batchLimit = 20, ...args } = {}) { diff --git a/components/microsoft_excel/package.json b/components/microsoft_excel/package.json index 1c018071ae470..89e8486239d42 100644 --- a/components/microsoft_excel/package.json +++ b/components/microsoft_excel/package.json @@ -14,6 +14,7 @@ }, "dependencies": { "@pipedream/platform": "^3.0.3", + "json-2-csv": "^5.5.9", "moment": "^2.29.4" } } diff --git a/components/microsoft_excel/sources/common/base-polling.mjs b/components/microsoft_excel/sources/common/base-polling.mjs index 57542f3d51775..9ae12f834d039 100644 --- a/components/microsoft_excel/sources/common/base-polling.mjs +++ b/components/microsoft_excel/sources/common/base-polling.mjs @@ -11,8 +11,29 @@ export default { intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, }, }, - }, - async run() { - + folderId: { + propDefinition: [ + common.props.microsoftExcel, + "folderId", + ], + }, + sheetId: { + propDefinition: [ + common.props.microsoftExcel, + "sheetId", + ({ folderId }) => ({ + folderId, + }), + ], + }, + worksheet: { + propDefinition: [ + common.props.microsoftExcel, + "worksheet", + ({ sheetId }) => ({ + sheetId, + }), + ], + }, }, }; diff --git a/components/microsoft_excel/sources/common/base-webhook.mjs b/components/microsoft_excel/sources/common/base-webhook.mjs index 6ad893acb7e6e..7a6cbefc5e66c 100644 --- a/components/microsoft_excel/sources/common/base-webhook.mjs +++ b/components/microsoft_excel/sources/common/base-webhook.mjs @@ -77,6 +77,9 @@ export default { token: new URL(deltaLink).searchParams.get("token"), }; }, + filterRelevantSpreadsheets(spreadsheets) { + return spreadsheets; + }, }, async run({ query }) { if (query.validationToken) { @@ -103,7 +106,8 @@ export default { await this.updateSubscription(); this._setDeltaToken(token); - const spreadsheets = value.filter(({ file }) => file?.mimeType === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + let spreadsheets = value.filter(({ file }) => file?.mimeType === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + spreadsheets = this.filterRelevantSpreadsheets(spreadsheets); if (!spreadsheets?.length) { return; diff --git a/components/microsoft_excel/sources/new-cell-value-changed/new-cell-value-changed.mjs b/components/microsoft_excel/sources/new-cell-value-changed/new-cell-value-changed.mjs new file mode 100644 index 0000000000000..06fec1b21f9c3 --- /dev/null +++ b/components/microsoft_excel/sources/new-cell-value-changed/new-cell-value-changed.mjs @@ -0,0 +1,58 @@ +import common from "../common/base-polling.mjs"; + +export default { + ...common, + key: "microsoft_excel-new-cell-value-changed", + name: "New Cell Value Changed", + description: "Emit new event when when a specific cell's value changes in an Excel worksheet", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + ...common.props, + cell: { + type: "string", + label: "Cell", + description: "The address of the cell to watch for changes. E.g. `A1`", + }, + }, + methods: { + ...common.methods, + _getCellValue() { + return this.db.get("cellValue"); + }, + _setCellValue(value) { + this.db.set("cellValue", value); + }, + generateMeta(item) { + const ts = Date.now(); + return { + id: `${item.address}${ts}`, + summary: "Cell value updated", + ts, + }; + }, + }, + async run() { + const previousCellValue = this._getCellValue(); + + const response = await this.microsoftExcel.getRange({ + sheetId: this.sheetId, + worksheet: this.worksheet, + range: `${this.worksheet}!${this.cell}:${this.cell}`, + }); + + const value = response.values[0][0]; + + if (value === previousCellValue) { + return; + } + + this._setCellValue(value); + if (previousCellValue) { + response.previousValue = previousCellValue; + } + + this.emitEvent(response); + }, +}; diff --git a/components/microsoft_excel/sources/new-item-created/new-item-created.mjs b/components/microsoft_excel/sources/new-item-created/new-item-created.mjs index 88792198c2e88..511ed0efa63b7 100644 --- a/components/microsoft_excel/sources/new-item-created/new-item-created.mjs +++ b/components/microsoft_excel/sources/new-item-created/new-item-created.mjs @@ -7,10 +7,36 @@ export default { key: "microsoft_excel-new-item-created", name: "New Spreadsheet Created (Instant)", description: "Emit new event when a new Excel spreadsheet is created.", - version: "0.0.{{ts}}", + version: "0.0.1", type: "source", + hooks: { + ...common.hooks, + async deploy() { + this._setLastCreatedTs(Date.now()); + }, + }, methods: { ...common.methods, + _getLastCreatedTs() { + return this.db.get("lastCreatedTs"); + }, + _setLastCreatedTs(lastCreatedTs) { + this.db.set("lastCreatedTs", lastCreatedTs); + }, + filterRelevantSpreadsheets(spreadsheets) { + const lastCreatedTs = this._getLastCreatedTs(); + let maxTs = lastCreatedTs; + const relevant = []; + for (const spreadsheet of spreadsheets) { + const ts = Date.parse(spreadsheet.createdDateTime); + if (ts > lastCreatedTs) { + relevant.push(spreadsheet); + maxTs = Math.max(ts, maxTs); + } + } + this._setLastCreatedTs(maxTs); + return relevant; + }, generateMeta(item) { return { id: `${item.id}`, diff --git a/components/microsoft_excel/sources/new-row-added/new-row-added.mjs b/components/microsoft_excel/sources/new-row-added/new-row-added.mjs new file mode 100644 index 0000000000000..b0140cb0f80f7 --- /dev/null +++ b/components/microsoft_excel/sources/new-row-added/new-row-added.mjs @@ -0,0 +1,47 @@ +import common from "../common/base-polling.mjs"; + +export default { + ...common, + key: "microsoft_excel-new-row-added", + name: "New Row Added", + description: "Emit new event when when a new row is added to an Excel worksheet", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + _getRowCount() { + return this.db.get("rowCount"); + }, + _setRowCount(value) { + this.db.set("rowCount", value); + }, + generateMeta(item) { + const ts = Date.now(); + return { + id: `${item.address}${ts}`, + summary: `${item.numRowsAdded} row(s) added`, + ts, + }; + }, + }, + async run() { + const previousRowCount = this._getRowCount(); + + const response = await this.microsoftExcel.getUsedRange({ + sheetId: this.sheetId, + worksheet: this.worksheet, + }); + + const { rowCount } = response; + + this._setRowCount(rowCount); + + if (!previousRowCount || rowCount <= previousRowCount) { + return; + } + + response.numRowsAdded = rowCount - previousRowCount; + this.emitEvent(response); + }, +}; From 7bb53a006113ca5b93eb2da1037f2ed22ee18799 Mon Sep 17 00:00:00 2001 From: michelle0927 Date: Fri, 18 Apr 2025 16:58:50 -0400 Subject: [PATCH 03/10] pnpm-lock.yaml --- pnpm-lock.yaml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 29c6699ad1c74..1572a9b7a30d8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7986,6 +7986,9 @@ importers: '@pipedream/platform': specifier: ^3.0.3 version: 3.0.3 + json-2-csv: + specifier: ^5.5.9 + version: 5.5.9 moment: specifier: ^2.29.4 version: 2.30.1 @@ -21837,6 +21840,10 @@ packages: resolution: {integrity: sha512-PZrpz5xLo2JPZa3L+kqMMMdZU5pRwMysTM1xd6pLhNtgQw4Iq3wbF2QWaQTVh+HRq9Yg4rcjDIJ+scfGLxmsjQ==} engines: {node: '>= 12'} + deeks@3.1.0: + resolution: {integrity: sha512-e7oWH1LzIdv/prMQ7pmlDlaVoL64glqzvNgkgQNgyec9ORPHrT2jaOqMtRyqJuwWjtfb6v+2rk9pmaHj+F137A==} + engines: {node: '>= 16'} + deep-assign@3.0.0: resolution: {integrity: sha512-YX2i9XjJ7h5q/aQ/IM9PEwEnDqETAIYbggmdDB3HLTlSgo1CxPsj6pvhPG68rq6SVE0+p+6Ywsm5fTYNrYtBWw==} engines: {node: '>=0.10.0'} @@ -22017,6 +22024,10 @@ packages: resolution: {integrity: sha512-Pv2hLQbUM8du5681lTWIYk0OtVBmNhMAeZNGeFhMMJBIR89Nw4XesBwee1Xtlfk83n71tn0Y6VsJOn4d3qIiTw==} engines: {node: '>=12'} + doc-path@4.1.1: + resolution: {integrity: sha512-h1ErTglQAVv2gCnOpD3sFS6uolDbOKHDU1BZq+Kl3npPqroU3dYL42lUgMfd5UimlwtRgp7C9dLGwqQ5D2HYgQ==} + engines: {node: '>=16'} + doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -24456,6 +24467,10 @@ packages: resolution: {integrity: sha512-IbqUB+yaycVNB/q2fiY5kyRjy5kRiEXqvNvGlxM5L0Bfi0RdvklVHc4t9MfeYF1GsZVpZWDBs9LdWmSjsQ8jvg==} engines: {node: '>= 12'} + json-2-csv@5.5.9: + resolution: {integrity: sha512-l4g6GZVHrsN+5SKkpOmGNSvho+saDZwXzj/xmcO0lJAgklzwsiqy70HS5tA9djcRvBEybZ9IF6R1MDFTEsaOGQ==} + engines: {node: '>= 16'} + json-bigint@1.0.0: resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} @@ -38754,6 +38769,8 @@ snapshots: deeks@2.6.1: {} + deeks@3.1.0: {} + deep-assign@3.0.0: dependencies: is-obj: 1.0.1 @@ -38930,6 +38947,8 @@ snapshots: doc-path@3.1.0: {} + doc-path@4.1.1: {} + doctrine@2.1.0: dependencies: esutils: 2.0.3 @@ -42359,6 +42378,11 @@ snapshots: deeks: 2.6.1 doc-path: 3.1.0 + json-2-csv@5.5.9: + dependencies: + deeks: 3.1.0 + doc-path: 4.1.1 + json-bigint@1.0.0: dependencies: bignumber.js: 9.1.2 From e7e84ddd8a6d22f9fdc9294445e80adbedb98506 Mon Sep 17 00:00:00 2001 From: michelle0927 Date: Fri, 18 Apr 2025 17:20:21 -0400 Subject: [PATCH 04/10] fix column prop --- components/microsoft_excel/actions/find-row/find-row.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/microsoft_excel/actions/find-row/find-row.mjs b/components/microsoft_excel/actions/find-row/find-row.mjs index e8905ecbe153e..46e2b23c97955 100644 --- a/components/microsoft_excel/actions/find-row/find-row.mjs +++ b/components/microsoft_excel/actions/find-row/find-row.mjs @@ -33,7 +33,7 @@ export default { ], }, column: { - type: "string[]", + type: "string", label: "Column", description: "The column to search. E.g. `A`", }, From cbd75479c03a21abce4a04721af97fb8b5d50229 Mon Sep 17 00:00:00 2001 From: michelle0927 Date: Mon, 21 Apr 2025 14:51:46 -0400 Subject: [PATCH 05/10] updates --- .../actions/add-row/add-row.mjs | 23 +++++++++++-------- .../actions/find-row/find-row.mjs | 4 ++-- .../actions/get-columns/get-columns.mjs | 6 +++-- .../get-spreadsheet/get-spreadsheet.mjs | 2 +- .../actions/update-cell/update-cell.mjs | 2 +- .../update-worksheet-tablerow.mjs | 7 ++++-- components/microsoft_excel/common/utils.mjs | 10 ++++++++ .../microsoft_excel/microsoft_excel.app.mjs | 2 +- .../sources/common/base-webhook.mjs | 14 ++++++++--- .../new-cell-value-changed.mjs | 2 +- 10 files changed, 49 insertions(+), 23 deletions(-) diff --git a/components/microsoft_excel/actions/add-row/add-row.mjs b/components/microsoft_excel/actions/add-row/add-row.mjs index 4f67463d51f8c..a531b019288f2 100644 --- a/components/microsoft_excel/actions/add-row/add-row.mjs +++ b/components/microsoft_excel/actions/add-row/add-row.mjs @@ -1,4 +1,7 @@ import microsoftExcel from "../../microsoft_excel.app.mjs"; +import { + parseObject, getColumnLetter, +} from "../../common/utils.mjs"; export default { key: "microsoft_excel-add-row", @@ -39,7 +42,9 @@ export default { }, }, async run({ $ }) { - const { address } = await this.microsoftExcel.getUsedRange({ + const { + address, columnCount, + } = await this.microsoftExcel.getUsedRange({ $, sheetId: this.sheetId, worksheet: this.worksheet, @@ -47,15 +52,13 @@ export default { // get next row range const match = address.match(/^(.+!)?([A-Z]+)(\d+):([A-Z]+)(\d+)$/); - const [ - , sheet = "", - colStart, - /* eslint-disable no-unused-vars */ - rowStart, - colEnd, - ] = match; const nextRow = parseInt(match[5], 10) + 1; - const range = `${sheet}${colStart}${nextRow}:${colEnd}${nextRow}`; + const values = parseObject(this.values); + if (values.length < columnCount) { + values.length = columnCount; + } + const colEnd = getColumnLetter(values.length); + const range = `A${nextRow}:${colEnd}${nextRow}`; // insert range await this.microsoftExcel.insertRange({ @@ -76,7 +79,7 @@ export default { range, data: { values: [ - this.values, + values, ], }, }); diff --git a/components/microsoft_excel/actions/find-row/find-row.mjs b/components/microsoft_excel/actions/find-row/find-row.mjs index 46e2b23c97955..6f15c8ec3311b 100644 --- a/components/microsoft_excel/actions/find-row/find-row.mjs +++ b/components/microsoft_excel/actions/find-row/find-row.mjs @@ -57,7 +57,7 @@ export default { $, sheetId: this.sheetId, worksheet: this.worksheet, - range: `${this.worksheet}!${this.column}1:${this.column}${rowCount}`, + range: `${this.column}1:${this.column}${rowCount}`, }); const values = rangeValues.map((v) => v[0]); const index = values.indexOf(this.value); @@ -72,7 +72,7 @@ export default { $, sheetId: this.sheetId, worksheet: this.worksheet, - range: `${this.worksheet}!A${row}:${lastColumn}${row}`, + range: `A${row}:${lastColumn}${row}`, }); $.export("$summary", `Found value in row ${row}`); diff --git a/components/microsoft_excel/actions/get-columns/get-columns.mjs b/components/microsoft_excel/actions/get-columns/get-columns.mjs index 03386ca014381..61b8f3c5dcd2f 100644 --- a/components/microsoft_excel/actions/get-columns/get-columns.mjs +++ b/components/microsoft_excel/actions/get-columns/get-columns.mjs @@ -1,4 +1,5 @@ import microsoftExcel from "../../microsoft_excel.app.mjs"; +import { parseObject } from "../../common/utils.mjs"; export default { key: "microsoft_excel-get-columns", @@ -46,12 +47,13 @@ export default { }); const values = {}; - for (const column of this.columns) { + const columns = parseObject(this.columns); + for (const column of columns) { const response = await this.microsoftExcel.getRange({ $, sheetId: this.sheetId, worksheet: this.worksheet, - range: `${this.worksheet}!${column}1:${column}${rowCount}`, + range: `${column}1:${column}${rowCount}`, }); values[column] = response.values.map((v) => v[0]); } diff --git a/components/microsoft_excel/actions/get-spreadsheet/get-spreadsheet.mjs b/components/microsoft_excel/actions/get-spreadsheet/get-spreadsheet.mjs index f1ae2258f7ede..9929ef5eb9088 100644 --- a/components/microsoft_excel/actions/get-spreadsheet/get-spreadsheet.mjs +++ b/components/microsoft_excel/actions/get-spreadsheet/get-spreadsheet.mjs @@ -46,7 +46,7 @@ export default { $, sheetId: this.sheetId, worksheet: this.worksheet, - range: `${this.worksheet}!${this.range}`, + range: `${this.range}`, }) : await this.microsoftExcel.getUsedRange({ $, diff --git a/components/microsoft_excel/actions/update-cell/update-cell.mjs b/components/microsoft_excel/actions/update-cell/update-cell.mjs index c59801f304d7f..8721d6274badb 100644 --- a/components/microsoft_excel/actions/update-cell/update-cell.mjs +++ b/components/microsoft_excel/actions/update-cell/update-cell.mjs @@ -48,7 +48,7 @@ export default { $, sheetId: this.sheetId, worksheet: this.worksheet, - range: `${this.worksheet}!${this.cell}:${this.cell}`, + range: `${this.cell}:${this.cell}`, data: { values: [ [ diff --git a/components/microsoft_excel/actions/update-worksheet-tablerow/update-worksheet-tablerow.mjs b/components/microsoft_excel/actions/update-worksheet-tablerow/update-worksheet-tablerow.mjs index e90d06bf5b1d7..bb198ff8b23c8 100644 --- a/components/microsoft_excel/actions/update-worksheet-tablerow/update-worksheet-tablerow.mjs +++ b/components/microsoft_excel/actions/update-worksheet-tablerow/update-worksheet-tablerow.mjs @@ -1,4 +1,5 @@ import microsoftExcel from "../../microsoft_excel.app.mjs"; +import { parseObject } from "../../common/utils.mjs"; export default { key: "microsoft_excel-update-worksheet-tablerow", @@ -49,7 +50,7 @@ export default { microsoftExcel, "values", ], - description: "Represents the raw values of the specified range. The data returned could be of type string, number, or a boolean. Cells that contain errors return the error string.", + description: "An array of values for the updated row. Each item in the array represents one cell. E.g. `[1, 2, 3]`", }, }, async run({ $ }) { @@ -67,7 +68,9 @@ export default { tableId, rowId, data: { - values: JSON.parse(values), + values: [ + parseObject(values), + ], }, }); diff --git a/components/microsoft_excel/common/utils.mjs b/components/microsoft_excel/common/utils.mjs index 154701004e72a..a7472a1b24fef 100644 --- a/components/microsoft_excel/common/utils.mjs +++ b/components/microsoft_excel/common/utils.mjs @@ -16,3 +16,13 @@ export const parseObject = (obj) => { } return obj; }; + +export function getColumnLetter(index) { + let letter = ""; + while (index > 0) { + const mod = (index - 1) % 26; + letter = String.fromCharCode(65 + mod) + letter; + index = Math.floor((index - 1) / 26); + } + return letter; +} diff --git a/components/microsoft_excel/microsoft_excel.app.mjs b/components/microsoft_excel/microsoft_excel.app.mjs index 1a17fd7ea3ebb..3728dc41a8a8a 100644 --- a/components/microsoft_excel/microsoft_excel.app.mjs +++ b/components/microsoft_excel/microsoft_excel.app.mjs @@ -176,7 +176,7 @@ export default { }) { return this._makeRequest({ method: "PATCH", - path: `me/drive/items/${sheetId}/workbook/tables/${tableId}/rows/itemAt(index=${rowId})`, + path: `me/drive/items/${sheetId}/workbook/tables/${tableId}/rows/ItemAt(index=${rowId})`, ...args, }); }, diff --git a/components/microsoft_excel/sources/common/base-webhook.mjs b/components/microsoft_excel/sources/common/base-webhook.mjs index 7a6cbefc5e66c..5f9c771f2bbcb 100644 --- a/components/microsoft_excel/sources/common/base-webhook.mjs +++ b/components/microsoft_excel/sources/common/base-webhook.mjs @@ -53,13 +53,21 @@ export default { this.db.set("deltaToken", token); }, async updateSubscription() { - const hookId = this._getHookId(); - await this.microsoftExcel.updateSubscription({ - hookId, + try { + await this.microsoftExcel.deleteHook(this._getHookId("hookId")); + } catch { + // couldn't find webhook + } + + const { id } = await this.microsoftExcel.createHook({ data: { + changeType: "updated", + notificationUrl: this.http.endpoint, + resource: "me/drive/root", expirationDateTime: moment().add(30, "days"), }, }); + this._setHookId(id); }, path() { return this.folderId === "root" diff --git a/components/microsoft_excel/sources/new-cell-value-changed/new-cell-value-changed.mjs b/components/microsoft_excel/sources/new-cell-value-changed/new-cell-value-changed.mjs index 06fec1b21f9c3..25cd33a500645 100644 --- a/components/microsoft_excel/sources/new-cell-value-changed/new-cell-value-changed.mjs +++ b/components/microsoft_excel/sources/new-cell-value-changed/new-cell-value-changed.mjs @@ -39,7 +39,7 @@ export default { const response = await this.microsoftExcel.getRange({ sheetId: this.sheetId, worksheet: this.worksheet, - range: `${this.worksheet}!${this.cell}:${this.cell}`, + range: `${this.cell}:${this.cell}`, }); const value = response.values[0][0]; From 23a592f2f82837fcaded56dcb4abfc780f30ab63 Mon Sep 17 00:00:00 2001 From: michelle0927 Date: Mon, 21 Apr 2025 14:53:22 -0400 Subject: [PATCH 06/10] pnpm-lock.yaml --- pnpm-lock.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1572a9b7a30d8..dfd25565d23a4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15238,7 +15238,7 @@ importers: version: 3.1.7 ts-jest: specifier: ^29.2.5 - version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.17.30)(babel-plugin-macros@3.1.0))(typescript@5.7.2) + version: 29.2.5(@babel/core@8.0.0-alpha.13)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@8.0.0-alpha.13))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.17.30)(babel-plugin-macros@3.1.0))(typescript@5.7.2) tsup: specifier: ^8.3.6 version: 8.3.6(@microsoft/api-extractor@7.47.12(@types/node@20.17.30))(jiti@1.21.6)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.6.1) @@ -15275,7 +15275,7 @@ importers: version: 3.1.0 jest: specifier: ^29.1.2 - version: 29.7.0(@types/node@20.17.6)(babel-plugin-macros@3.1.0) + version: 29.7.0(@types/node@20.17.30)(babel-plugin-macros@3.1.0) type-fest: specifier: ^4.15.0 version: 4.27.0 @@ -47702,7 +47702,7 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.17.30)(babel-plugin-macros@3.1.0))(typescript@5.7.2): + ts-jest@29.2.5(@babel/core@8.0.0-alpha.13)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@8.0.0-alpha.13))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.17.30)(babel-plugin-macros@3.1.0))(typescript@5.7.2): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 @@ -47716,10 +47716,10 @@ snapshots: typescript: 5.7.2 yargs-parser: 21.1.1 optionalDependencies: - '@babel/core': 7.26.0 + '@babel/core': 8.0.0-alpha.13 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.26.0) + babel-jest: 29.7.0(@babel/core@8.0.0-alpha.13) esbuild: 0.24.2 ts-jest@29.2.5(@babel/core@8.0.0-alpha.13)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@8.0.0-alpha.13))(jest@29.7.0(@types/node@20.17.6)(babel-plugin-macros@3.1.0))(typescript@5.6.3): From 34f70d4ce2bc84c90a878d60009d91a9cce34684 Mon Sep 17 00:00:00 2001 From: michelle0927 Date: Mon, 21 Apr 2025 14:55:09 -0400 Subject: [PATCH 07/10] pnpm-lock.yaml --- pnpm-lock.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dfd25565d23a4..1572a9b7a30d8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15238,7 +15238,7 @@ importers: version: 3.1.7 ts-jest: specifier: ^29.2.5 - version: 29.2.5(@babel/core@8.0.0-alpha.13)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@8.0.0-alpha.13))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.17.30)(babel-plugin-macros@3.1.0))(typescript@5.7.2) + version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.17.30)(babel-plugin-macros@3.1.0))(typescript@5.7.2) tsup: specifier: ^8.3.6 version: 8.3.6(@microsoft/api-extractor@7.47.12(@types/node@20.17.30))(jiti@1.21.6)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.6.1) @@ -15275,7 +15275,7 @@ importers: version: 3.1.0 jest: specifier: ^29.1.2 - version: 29.7.0(@types/node@20.17.30)(babel-plugin-macros@3.1.0) + version: 29.7.0(@types/node@20.17.6)(babel-plugin-macros@3.1.0) type-fest: specifier: ^4.15.0 version: 4.27.0 @@ -47702,7 +47702,7 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-jest@29.2.5(@babel/core@8.0.0-alpha.13)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@8.0.0-alpha.13))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.17.30)(babel-plugin-macros@3.1.0))(typescript@5.7.2): + ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.17.30)(babel-plugin-macros@3.1.0))(typescript@5.7.2): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 @@ -47716,10 +47716,10 @@ snapshots: typescript: 5.7.2 yargs-parser: 21.1.1 optionalDependencies: - '@babel/core': 8.0.0-alpha.13 + '@babel/core': 7.26.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@8.0.0-alpha.13) + babel-jest: 29.7.0(@babel/core@7.26.0) esbuild: 0.24.2 ts-jest@29.2.5(@babel/core@8.0.0-alpha.13)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@8.0.0-alpha.13))(jest@29.7.0(@types/node@20.17.6)(babel-plugin-macros@3.1.0))(typescript@5.6.3): From e2be6908da11b462a1ac9d4b5a717c9f2b6990aa Mon Sep 17 00:00:00 2001 From: michelle0927 Date: Mon, 21 Apr 2025 15:01:08 -0400 Subject: [PATCH 08/10] Update components/microsoft_excel/sources/common/base-webhook.mjs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- components/microsoft_excel/sources/common/base-webhook.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/microsoft_excel/sources/common/base-webhook.mjs b/components/microsoft_excel/sources/common/base-webhook.mjs index 5f9c771f2bbcb..f3e4ad6d3321d 100644 --- a/components/microsoft_excel/sources/common/base-webhook.mjs +++ b/components/microsoft_excel/sources/common/base-webhook.mjs @@ -95,9 +95,10 @@ export default { status: 200, body: query.validationToken, headers: { - "content-type": "text/plan", + "content-type": "text/plain", }, }); + } return; } From 2b3c47c29ad434fe7fcedeac873357e75ba13ae9 Mon Sep 17 00:00:00 2001 From: michelle0927 Date: Mon, 21 Apr 2025 15:05:28 -0400 Subject: [PATCH 09/10] fix --- components/microsoft_excel/sources/common/base-webhook.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/components/microsoft_excel/sources/common/base-webhook.mjs b/components/microsoft_excel/sources/common/base-webhook.mjs index f3e4ad6d3321d..172c0ed9d25a1 100644 --- a/components/microsoft_excel/sources/common/base-webhook.mjs +++ b/components/microsoft_excel/sources/common/base-webhook.mjs @@ -98,7 +98,6 @@ export default { "content-type": "text/plain", }, }); - } return; } From aa811fa9ee830d900c08cf0049f9f730d227a703 Mon Sep 17 00:00:00 2001 From: michelle0927 Date: Tue, 22 Apr 2025 13:31:20 -0400 Subject: [PATCH 10/10] updates --- .../actions/add-row/add-row.mjs | 37 +++++++++++++++---- .../actions/find-row/find-row.mjs | 7 +++- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/components/microsoft_excel/actions/add-row/add-row.mjs b/components/microsoft_excel/actions/add-row/add-row.mjs index a531b019288f2..a70a29c7b59cf 100644 --- a/components/microsoft_excel/actions/add-row/add-row.mjs +++ b/components/microsoft_excel/actions/add-row/add-row.mjs @@ -1,7 +1,5 @@ import microsoftExcel from "../../microsoft_excel.app.mjs"; -import { - parseObject, getColumnLetter, -} from "../../common/utils.mjs"; +import { getColumnLetter } from "../../common/utils.mjs"; export default { key: "microsoft_excel-add-row", @@ -41,6 +39,34 @@ export default { description: "An array of values for the new row. Each item in the array represents one cell. E.g. `[1, 2, 3]`", }, }, + methods: { + isArrayString(str) { + return typeof str === "string" && ((str.startsWith("[") && str.endsWith("]")) || ((str.startsWith("[[") || str.startsWith("[ [")) && (str.endsWith("]]") || str.endsWith("] ]")))); + }, + convertStringToArray(str) { + const arrayString = str.match(/\[\[?(.*?)\]?\]/)[1]; + return arrayString.split(","); + }, + parseValues(columnCount) { + let values = this.values; + if (Array.isArray(this.values)) { + if (Array.isArray(this.values[0])) { + values = this.values[0]; + } else if (this.isArrayString(this.values[0])) { + values = this.convertStringToArray(this.values[0]); + } + } else { + if (this.isArrayString(this.values)) { + values = this.convertStringToArray(this.values); + } + } + + if (values.length < columnCount) { + values.length = columnCount; + } + return values; + }, + }, async run({ $ }) { const { address, columnCount, @@ -53,10 +79,7 @@ export default { // get next row range const match = address.match(/^(.+!)?([A-Z]+)(\d+):([A-Z]+)(\d+)$/); const nextRow = parseInt(match[5], 10) + 1; - const values = parseObject(this.values); - if (values.length < columnCount) { - values.length = columnCount; - } + const values = this.parseValues(columnCount); const colEnd = getColumnLetter(values.length); const range = `A${nextRow}:${colEnd}${nextRow}`; diff --git a/components/microsoft_excel/actions/find-row/find-row.mjs b/components/microsoft_excel/actions/find-row/find-row.mjs index 6f15c8ec3311b..538d2921df176 100644 --- a/components/microsoft_excel/actions/find-row/find-row.mjs +++ b/components/microsoft_excel/actions/find-row/find-row.mjs @@ -40,7 +40,7 @@ export default { value: { type: "string", label: "Value", - description: "The value to search for. For non-string values, use a custom expression. For example: `{{ 1 }}` for the numeric value 1", + description: "The value to search for", }, }, async run({ $ }) { @@ -60,7 +60,10 @@ export default { range: `${this.column}1:${this.column}${rowCount}`, }); const values = rangeValues.map((v) => v[0]); - const index = values.indexOf(this.value); + let index = values.indexOf(this.value); + if (index === -1 && !isNaN(this.value)) { + index = values.indexOf(+this.value); + } if (index === -1) { $.export("$summary", "No matching rows found");