@guayaba/workflow-piece-google-sheets 0.14.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/.babelrc +3 -0
  2. package/.eslintrc.json +18 -0
  3. package/README.md +5 -0
  4. package/assets/logo.png +0 -0
  5. package/package.json +28 -0
  6. package/src/i18n/ar.json +124 -0
  7. package/src/i18n/bg.json +124 -0
  8. package/src/i18n/ca.json +132 -0
  9. package/src/i18n/de.json +165 -0
  10. package/src/i18n/es.json +165 -0
  11. package/src/i18n/fr.json +165 -0
  12. package/src/i18n/hi.json +132 -0
  13. package/src/i18n/hu.json +124 -0
  14. package/src/i18n/hy.json +124 -0
  15. package/src/i18n/id.json +132 -0
  16. package/src/i18n/it.json +124 -0
  17. package/src/i18n/ja.json +165 -0
  18. package/src/i18n/ko.json +124 -0
  19. package/src/i18n/nl.json +165 -0
  20. package/src/i18n/pl.json +124 -0
  21. package/src/i18n/pt.json +165 -0
  22. package/src/i18n/ru.json +132 -0
  23. package/src/i18n/sv.json +124 -0
  24. package/src/i18n/translation.json +165 -0
  25. package/src/i18n/uk.json +124 -0
  26. package/src/i18n/vi.json +132 -0
  27. package/src/i18n/zh.json +165 -0
  28. package/src/index.ts +93 -0
  29. package/src/lib/actions/clear-sheet.ts +60 -0
  30. package/src/lib/actions/copy-worksheet.ts +32 -0
  31. package/src/lib/actions/create-column.ts +109 -0
  32. package/src/lib/actions/create-spreadsheet.ts +122 -0
  33. package/src/lib/actions/create-worksheet.ts +62 -0
  34. package/src/lib/actions/delete-row.action.ts +40 -0
  35. package/src/lib/actions/delete-worksheet.ts +36 -0
  36. package/src/lib/actions/export-sheet.ts +86 -0
  37. package/src/lib/actions/find-row-by-num.ts +42 -0
  38. package/src/lib/actions/find-rows.ts +135 -0
  39. package/src/lib/actions/find-spreadsheets.ts +83 -0
  40. package/src/lib/actions/find-worksheet.ts +52 -0
  41. package/src/lib/actions/format-spreadsheet-row.ts +112 -0
  42. package/src/lib/actions/get-many-rows.ts +42 -0
  43. package/src/lib/actions/get-rows.ts +207 -0
  44. package/src/lib/actions/insert-multiple-rows.action.ts +542 -0
  45. package/src/lib/actions/insert-row.action.ts +111 -0
  46. package/src/lib/actions/rename-worksheet.ts +44 -0
  47. package/src/lib/actions/update-multiple-rows.ts +177 -0
  48. package/src/lib/actions/update-row.ts +93 -0
  49. package/src/lib/common/common.ts +383 -0
  50. package/src/lib/common/props.ts +274 -0
  51. package/src/lib/triggers/helpers.ts +155 -0
  52. package/src/lib/triggers/new-or-updated-row.trigger.ts +299 -0
  53. package/src/lib/triggers/new-row-added-webhook.ts +182 -0
  54. package/src/lib/triggers/new-spreadsheet.ts +88 -0
  55. package/src/lib/triggers/new-worksheet.ts +96 -0
  56. package/tsconfig.json +16 -0
  57. package/tsconfig.lib.json +15 -0
@@ -0,0 +1,299 @@
1
+ import { isNil } from '@guayaba/workflows-shared';
2
+ import { googleSheetsAuth } from '../common/common';
3
+ import { areSheetIdsValid, columnToLabel, GoogleSheetsAuthValue, labelToColumn } from '../common/common';
4
+ import {
5
+ createFileNotification,
6
+ deleteFileNotification,
7
+ getWorkSheetName,
8
+ getWorkSheetValues,
9
+ hashObject,
10
+ isChangeContentMessage,
11
+ isSyncMessage,
12
+ mapRowsToColumnLabels,
13
+ WebhookInformation,
14
+ } from './helpers';
15
+
16
+ import {
17
+ createTrigger,
18
+ TriggerStrategy,
19
+ DEDUPE_KEY_PROPERTY,
20
+ WebhookRenewStrategy,
21
+ Property,
22
+ DropdownOption,
23
+ } from '@guayaba/workflows-framework';
24
+
25
+ import crypto from 'crypto';
26
+ import { commonProps } from '../common/props';
27
+
28
+ const ALL_COLUMNS = 'all_columns';
29
+
30
+ export const newOrUpdatedRowTrigger = createTrigger({
31
+ auth: googleSheetsAuth,
32
+ name: 'google-sheets-new-or-updated-row',
33
+ displayName: 'New or Updated Row',
34
+ description: 'Triggers when a new row is added or modified in a spreadsheet.',
35
+ props: {
36
+ info: Property.MarkDown({
37
+ value:
38
+ 'Please note that there might be a delay of up to 3 minutes for the trigger to be fired, due to a delay from Google.',
39
+ }),
40
+ ...commonProps,
41
+ trigger_column: Property.Dropdown({
42
+ auth: googleSheetsAuth,
43
+ displayName: 'Trigger Column',
44
+ description: `Trigger on changes to cells in this column only. \nSelect **Any Column** if you want the flow to trigger on changes to any cell within the row.`,
45
+ required: false,
46
+ refreshers: ['spreadsheetId', 'sheetId'],
47
+ defaultValue: ALL_COLUMNS,
48
+ options: async ({ auth, spreadsheetId, sheetId }) => {
49
+ if (!auth || !spreadsheetId || isNil(sheetId)) {
50
+ return {
51
+ disabled: true,
52
+ options: [],
53
+ placeholder: `Please select sheet first`,
54
+ };
55
+ }
56
+
57
+ const spreadsheet_id = spreadsheetId as string;
58
+ const sheet_id = sheetId as number;
59
+
60
+ const sheetName = await getWorkSheetName(auth, spreadsheet_id, sheet_id);
61
+
62
+ const firstRowValues = await getWorkSheetValues(
63
+ auth,
64
+ spreadsheet_id,
65
+ `${sheetName}!1:1`,
66
+ );
67
+
68
+ const headers = firstRowValues[0] ?? [];
69
+ const headerCount = headers.length;
70
+ const labeledRowValues = mapRowsToColumnLabels(firstRowValues, 0, headerCount);
71
+ const labledHeaders = labeledRowValues.length > 0 ? labeledRowValues[0].values : {};
72
+
73
+ const options = Object.entries(labledHeaders).reduce((accumlator:DropdownOption<string>[],[key,value]) => {
74
+ accumlator.push({ label: value as string, value: key });
75
+ return accumlator;
76
+ }, [{ label: 'Any Column', value: ALL_COLUMNS }]);
77
+
78
+ return {
79
+ disabled: options.length === 0,
80
+ options,
81
+ };
82
+ },
83
+ }),
84
+ },
85
+
86
+ renewConfiguration: {
87
+ strategy: WebhookRenewStrategy.CRON,
88
+ cronExpression: '0 */12 * * *',
89
+ },
90
+
91
+ type: TriggerStrategy.WEBHOOK,
92
+
93
+ async onEnable(context) {
94
+ const inputSpreadsheetId = context.propsValue.spreadsheetId;
95
+ const inputSheetId = context.propsValue.sheetId;
96
+ const triggerColumn = context.propsValue.trigger_column ?? ALL_COLUMNS;
97
+
98
+ if (!areSheetIdsValid(inputSpreadsheetId, inputSheetId)) {
99
+ throw new Error('Please select a spreadsheet and sheet first.');
100
+ }
101
+ const sheetId = Number(inputSheetId);
102
+ const spreadsheetId = inputSpreadsheetId as string;
103
+
104
+ const sheetName = await getWorkSheetName(context.auth, spreadsheetId, sheetId);
105
+
106
+ const sheetValues = await getWorkSheetValues(context.auth, spreadsheetId, sheetName);
107
+
108
+ const rowHashes = [];
109
+
110
+ // create initial row level hashes and used it to check updated row
111
+ for (const row of sheetValues) {
112
+ let targetValue;
113
+ if (triggerColumn === ALL_COLUMNS) {
114
+ targetValue = row;
115
+ } else {
116
+ const currentTriggerColumnValue = row[labelToColumn(triggerColumn)];
117
+
118
+ targetValue =
119
+ currentTriggerColumnValue !== undefined && currentTriggerColumnValue !== '' // if column value is empty
120
+ ? [currentTriggerColumnValue]
121
+ : [];
122
+ }
123
+
124
+ const rowHash = crypto.createHash('md5').update(JSON.stringify(targetValue)).digest('hex');
125
+ rowHashes.push(rowHash);
126
+ }
127
+
128
+ // store compressed values
129
+ await context.store.put(`${sheetId}`, rowHashes);
130
+
131
+ // create file watch notification
132
+ const fileNotificationRes = await createFileNotification(
133
+ context.auth,
134
+ spreadsheetId,
135
+ context.webhookUrl,
136
+ context.propsValue.includeTeamDrives,
137
+ );
138
+
139
+ await context.store.put<WebhookInformation>(
140
+ 'google-sheets-new-or-updated-row',
141
+ fileNotificationRes.data,
142
+ );
143
+ },
144
+
145
+ async onDisable(context) {
146
+ const webhook = await context.store.get<WebhookInformation>('google-sheets-new-or-updated-row');
147
+
148
+ if (webhook != null && webhook.id != null && webhook.resourceId != null) {
149
+ try
150
+ {
151
+ await deleteFileNotification(context.auth, webhook.id, webhook.resourceId);
152
+ }
153
+ catch(err){
154
+ console.debug("deleteFileNotification failed :",JSON.stringify(err));
155
+ }
156
+ }
157
+ },
158
+
159
+ async run(context) {
160
+ if (isSyncMessage(context.payload.headers)) {
161
+ return [];
162
+ }
163
+
164
+ if (!isChangeContentMessage(context.payload.headers)) {
165
+ return [];
166
+ }
167
+
168
+ const inputSpreadsheetId = context.propsValue.spreadsheetId;
169
+ const inputSheetId = context.propsValue.sheetId;
170
+ const triggerColumn = context.propsValue.trigger_column ?? ALL_COLUMNS;
171
+
172
+ if (!areSheetIdsValid(inputSpreadsheetId, inputSheetId)) {
173
+ throw new Error('Please select a spreadsheet and sheet first.');
174
+ }
175
+
176
+ const sheetId = Number(inputSheetId);
177
+ const spreadsheetId = inputSpreadsheetId as string;
178
+
179
+ const sheetName = await getWorkSheetName(context.auth, spreadsheetId, sheetId);
180
+
181
+ const oldValuesHashes = (await context.store.get(`${sheetId}`)) as any[];
182
+
183
+ /* Fetch rows values with all columns as this will be used on returning updated/new row data
184
+ */
185
+ const currentValues = await getWorkSheetValues(context.auth, spreadsheetId, sheetName);
186
+
187
+ const headers = currentValues[0] ?? [];
188
+ const headerCount = headers.length;
189
+
190
+ // const rowCount = Math.max(oldValuesHashes.length, currentValues.length);
191
+
192
+ const changedValues = [];
193
+ const newRowHashes = [];
194
+
195
+ for (let row = 0; row < currentValues.length; row++) {
196
+ const currentRowValue = currentValues[row];
197
+
198
+ /**
199
+ * This variable store value based on trigger column.
200
+ * If trigger column is all_columns then store entry row as target value, else store only column value.
201
+ */
202
+ let targetValue;
203
+ if (triggerColumn === ALL_COLUMNS) {
204
+ targetValue = currentRowValue;
205
+ } else {
206
+ const currentTriggerColumnValue = currentRowValue[labelToColumn(triggerColumn)];
207
+
208
+ targetValue =
209
+ currentTriggerColumnValue !== undefined && currentTriggerColumnValue !== ''
210
+ ? [currentTriggerColumnValue]
211
+ : [];
212
+ }
213
+
214
+ // create hash for new row values
215
+ const currentRowHash = crypto
216
+ .createHash('md5')
217
+ .update(JSON.stringify(targetValue))
218
+ .digest('hex');
219
+ newRowHashes.push(currentRowHash);
220
+
221
+ // If row is empty then skip
222
+ if (currentRowValue === undefined || currentRowValue.length === 0) {
223
+ continue;
224
+ }
225
+
226
+ const oldRowHash =
227
+ !isNil(oldValuesHashes) && row < oldValuesHashes.length ? oldValuesHashes[row] : undefined;
228
+
229
+ if (oldRowHash === undefined || oldRowHash != currentRowHash) {
230
+ const formattedValues: any = {};
231
+
232
+ for (let column = 0; column < headerCount; column++) {
233
+ formattedValues[columnToLabel(column)] = currentValues[row][column] ?? '';
234
+ }
235
+
236
+ changedValues.push({
237
+ row: row + 1,
238
+ values: formattedValues,
239
+ });
240
+ }
241
+ }
242
+
243
+ // update the row hashes
244
+ await context.store.put(`${sheetId}`, newRowHashes);
245
+
246
+ return changedValues.map((row) => {
247
+ return {
248
+ ...row,
249
+ [DEDUPE_KEY_PROPERTY]: hashObject(row),
250
+ };
251
+ });
252
+ },
253
+
254
+ async test(context) {
255
+ const inputSpreadsheetId = context.propsValue.spreadsheetId;
256
+ const inputSheetId = context.propsValue.sheetId;
257
+
258
+ if (!areSheetIdsValid(inputSpreadsheetId, inputSheetId)) {
259
+ throw new Error('Please select a spreadsheet and sheet first.');
260
+ }
261
+
262
+ const sheetId = Number(inputSheetId);
263
+ const spreadsheetId = inputSpreadsheetId as string;
264
+
265
+ const sheetName = await getWorkSheetName(context.auth, spreadsheetId, sheetId);
266
+ const currentSheetValues = await getWorkSheetValues(context.auth, spreadsheetId, sheetName);
267
+
268
+ const headers = currentSheetValues[0] ?? [];
269
+ const headerCount = headers.length;
270
+
271
+ const transformedRowValues = mapRowsToColumnLabels(currentSheetValues, 0, headerCount)
272
+ .slice(-5)
273
+ .reverse();
274
+
275
+ return transformedRowValues;
276
+ },
277
+
278
+ async onRenew(context) {
279
+ // get current channel ID & resource ID
280
+ const webhook = await context.store.get<WebhookInformation>(`google-sheets-new-or-updated-row`);
281
+ if (webhook != null && webhook.id != null && webhook.resourceId != null) {
282
+ // delete current channel
283
+ await deleteFileNotification(context.auth, webhook.id, webhook.resourceId);
284
+ const fileNotificationRes = await createFileNotification(
285
+ context.auth,
286
+ context.propsValue.spreadsheetId!,
287
+ context.webhookUrl,
288
+ context.propsValue.includeTeamDrives,
289
+ );
290
+ // store channel response
291
+ await context.store.put<WebhookInformation>(
292
+ 'google-sheets-new-or-updated-row',
293
+ fileNotificationRes.data,
294
+ );
295
+ }
296
+ },
297
+
298
+ sampleData: {},
299
+ });
@@ -0,0 +1,182 @@
1
+ import {
2
+ DEDUPE_KEY_PROPERTY,
3
+ Property,
4
+ TriggerStrategy,
5
+ WebhookRenewStrategy,
6
+ createTrigger,
7
+ } from '@guayaba/workflows-framework';
8
+
9
+ import {
10
+ createFileNotification,
11
+ deleteFileNotification,
12
+ getWorkSheetName,
13
+ getWorkSheetValues,
14
+ hashObject,
15
+ isChangeContentMessage,
16
+ isSyncMessage,
17
+ mapRowsToColumnLabels,
18
+ WebhookInformation,
19
+ } from './helpers';
20
+
21
+ import { googleSheetsAuth } from '../common/common';
22
+ import { commonProps } from '../common/props';
23
+ import { areSheetIdsValid, } from '../common/common';
24
+
25
+ export const newRowAddedTrigger = createTrigger({
26
+ auth: googleSheetsAuth,
27
+ name: 'googlesheets_new_row_added',
28
+ displayName: 'New Row Added',
29
+ description: 'Triggers when a new row is added to bottom of a spreadsheet.',
30
+ props: {
31
+ info: Property.MarkDown({
32
+ value:
33
+ 'Please note that there might be a delay of up to 3 minutes for the trigger to be fired, due to a delay from Google.',
34
+ }),
35
+ ...commonProps,
36
+ },
37
+ renewConfiguration: {
38
+ strategy: WebhookRenewStrategy.CRON,
39
+ cronExpression: '0 */12 * * *',
40
+ },
41
+ type: TriggerStrategy.WEBHOOK,
42
+ async onEnable(context) {
43
+ const { spreadsheetId:inputSpreadsheetId, sheetId:inputSheetId } = context.propsValue;
44
+
45
+ if (!areSheetIdsValid(inputSpreadsheetId, inputSheetId)) {
46
+ throw new Error('Please select a spreadsheet and sheet first.');
47
+ }
48
+
49
+ const sheetId = Number(inputSheetId);
50
+ const spreadsheetId = inputSpreadsheetId as string;
51
+
52
+ const sheetName = await getWorkSheetName(context.auth, spreadsheetId, sheetId);
53
+ const currentSheetValues = await getWorkSheetValues(context.auth, spreadsheetId, sheetName);
54
+
55
+ await context.store.put(`${sheetId}`, currentSheetValues.length);
56
+
57
+ const fileNotificationRes = await createFileNotification(
58
+ context.auth,
59
+ spreadsheetId,
60
+ context.webhookUrl,
61
+ context.propsValue.includeTeamDrives,
62
+ );
63
+
64
+ await context.store.put<WebhookInformation>(
65
+ 'googlesheets_new_row_added',
66
+ fileNotificationRes.data,
67
+ );
68
+ },
69
+ async onDisable(context) {
70
+ const webhook = await context.store.get<WebhookInformation>(`googlesheets_new_row_added`);
71
+ if (webhook != null && webhook.id != null && webhook.resourceId != null) {
72
+ try
73
+ {
74
+ await deleteFileNotification(context.auth, webhook.id, webhook.resourceId);
75
+ }
76
+ catch(err){
77
+ console.debug("deleteFileNotification failed :",JSON.stringify(err));
78
+ }
79
+ }
80
+ },
81
+ async run(context) {
82
+ if (isSyncMessage(context.payload.headers)) {
83
+ return [];
84
+ }
85
+ if (!isChangeContentMessage(context.payload.headers)) {
86
+ return [];
87
+ }
88
+
89
+ const { spreadsheetId:inputSpreadsheetId, sheetId:inputSheetId } = context.propsValue;
90
+
91
+ if (!areSheetIdsValid(inputSpreadsheetId, inputSheetId)) {
92
+ throw new Error('Please select a spreadsheet and sheet first.');
93
+ }
94
+
95
+ const sheetId = Number(inputSheetId);
96
+ const spreadsheetId = inputSpreadsheetId as string;
97
+
98
+ const oldRowCount = (await context.store.get(`${sheetId}`)) as number;
99
+
100
+ const sheetName = await getWorkSheetName(context.auth, spreadsheetId, sheetId);
101
+ const currentRowValues = await getWorkSheetValues(context.auth, spreadsheetId, sheetName);
102
+ const currentRowCount = currentRowValues.length;
103
+
104
+ const headers = currentRowValues[0] ?? [];
105
+ const headerCount = headers.length;
106
+
107
+ if (oldRowCount >= currentRowCount) {
108
+ if (oldRowCount > currentRowCount) {
109
+ await context.store.put(`${sheetId}`, currentRowCount);
110
+ }
111
+ return [];
112
+ }
113
+
114
+ // create A1 notation range for new rows
115
+ const range = `${sheetName}!${oldRowCount + 1}:${currentRowCount}`;
116
+
117
+ const newRowValues = await getWorkSheetValues(
118
+ context.auth,
119
+ spreadsheetId,
120
+ range,
121
+ );
122
+
123
+ await context.store.put(`${sheetId}`, currentRowCount);
124
+
125
+ const transformedRowValues = mapRowsToColumnLabels(newRowValues, oldRowCount,headerCount);
126
+ return transformedRowValues.map((row) => {
127
+ return {
128
+ ...row,
129
+ [DEDUPE_KEY_PROPERTY]: hashObject(row),
130
+ };
131
+ });
132
+ },
133
+ async onRenew(context) {
134
+ // get current channel ID & resource ID
135
+ const webhook = await context.store.get<WebhookInformation>(`googlesheets_new_row_added`);
136
+
137
+ const { spreadsheetId:inputSpreadsheetId, sheetId:inputSheetId } = context.propsValue;
138
+
139
+ if (!areSheetIdsValid(inputSpreadsheetId, inputSheetId)) {
140
+ throw new Error('Please select a spreadsheet and sheet first.');
141
+ }
142
+
143
+ const spreadsheetId = inputSpreadsheetId as string;
144
+
145
+ if (webhook != null && webhook.id != null && webhook.resourceId != null) {
146
+ await deleteFileNotification(context.auth, webhook.id, webhook.resourceId);
147
+ const fileNotificationRes = await createFileNotification(
148
+ context.auth,
149
+ spreadsheetId,
150
+ context.webhookUrl,
151
+ context.propsValue.includeTeamDrives,
152
+ );
153
+ await context.store.put<WebhookInformation>(
154
+ 'googlesheets_new_row_added',
155
+ fileNotificationRes.data,
156
+ );
157
+ }
158
+ },
159
+ async test(context) {
160
+ const { spreadsheetId:inputSpreadsheetId, sheetId:inputSheetId } = context.propsValue;
161
+
162
+ if (!areSheetIdsValid(inputSpreadsheetId, inputSheetId)) {
163
+ throw new Error('Please select a spreadsheet and sheet first.');
164
+ }
165
+
166
+ const sheetId = Number(inputSheetId);
167
+ const spreadsheetId = inputSpreadsheetId as string;
168
+
169
+ const sheetName = await getWorkSheetName(context.auth, spreadsheetId, sheetId);
170
+ const currentSheetValues = await getWorkSheetValues(context.auth, spreadsheetId, sheetName);
171
+
172
+ const headers = currentSheetValues[0] ?? [];
173
+ const headerCount = headers.length;
174
+
175
+ const transformedRowValues = mapRowsToColumnLabels(currentSheetValues, 0,headerCount)
176
+ .slice(-5)
177
+ .reverse();
178
+
179
+ return transformedRowValues;
180
+ },
181
+ sampleData: {},
182
+ });
@@ -0,0 +1,88 @@
1
+ import {
2
+ AppConnectionValueForAuthProperty,
3
+ createTrigger,
4
+ TriggerStrategy,
5
+ } from '@guayaba/workflows-framework';
6
+ import { googleSheetsAuth } from '../common/common';
7
+ import { DedupeStrategy, Polling, pollingHelper } from '@guayaba/workflows-common';
8
+
9
+ import dayjs from 'dayjs';
10
+ import { google, drive_v3 } from 'googleapis';
11
+ import { includeTeamDrivesProp } from '../common/props';
12
+ import { createGoogleClient, GoogleSheetsAuthValue } from '../common/common';
13
+
14
+ type Props = {
15
+ includeTeamDrives?: boolean;
16
+ };
17
+
18
+ const polling: Polling<AppConnectionValueForAuthProperty<typeof googleSheetsAuth>, Props> = {
19
+ strategy: DedupeStrategy.TIMEBASED,
20
+ async items({ auth, propsValue, lastFetchEpochMS }) {
21
+ const authValue = auth as GoogleSheetsAuthValue;
22
+ const q = ["mimeType='application/vnd.google-apps.spreadsheet'", 'trashed = false'];
23
+ if (lastFetchEpochMS) {
24
+ q.push(`createdTime > '${dayjs(lastFetchEpochMS).toISOString()}'`);
25
+ }
26
+ const authClient = await createGoogleClient(authValue);
27
+ const drive = google.drive({ version: 'v3', auth: authClient });
28
+ let nextPageToken;
29
+ const items = [];
30
+ do {
31
+ const response: any = await drive.files.list({
32
+ q: q.join(' and '),
33
+ fields: '*',
34
+ orderBy: 'createdTime desc',
35
+ supportsAllDrives: true,
36
+ includeItemsFromAllDrives: propsValue.includeTeamDrives,
37
+ pageToken: nextPageToken,
38
+ });
39
+ const fileList: drive_v3.Schema$FileList = response.data;
40
+ if (fileList.files) {
41
+ items.push(...fileList.files);
42
+ }
43
+ if (lastFetchEpochMS === 0) break;
44
+ nextPageToken = response.data.nextPageToken;
45
+ } while (nextPageToken);
46
+ return items.map((item) => ({
47
+ epochMilliSeconds: dayjs(item.createdTime).valueOf(),
48
+ data: item,
49
+ }));
50
+ },
51
+ };
52
+ export const newSpreadsheetTrigger = createTrigger({
53
+ auth: googleSheetsAuth,
54
+ name: 'new-spreadsheet',
55
+ displayName: 'New Spreadsheet',
56
+ description: 'Triggers when a new spreadsheet is created.',
57
+ type: TriggerStrategy.POLLING,
58
+ props: {
59
+ includeTeamDrives: includeTeamDrivesProp(),
60
+ },
61
+ async onEnable(context) {
62
+ await pollingHelper.onEnable(polling, {
63
+ auth: context.auth,
64
+ store: context.store,
65
+ propsValue: context.propsValue,
66
+ });
67
+ },
68
+ async onDisable(context) {
69
+ await pollingHelper.onDisable(polling, {
70
+ auth: context.auth,
71
+ store: context.store,
72
+ propsValue: context.propsValue,
73
+ });
74
+ },
75
+ async test(context) {
76
+ return await pollingHelper.test(polling, context);
77
+ },
78
+ async run(context) {
79
+ return await pollingHelper.poll(polling, context);
80
+ },
81
+ sampleData: {
82
+ kind: 'drive#file',
83
+ mimeType: 'application/vnd.google-apps.spreadsheet',
84
+ webViewLink: 'https://docs.google.com/document/d/1_9xjsrYFgHVvgqYwAJ8KcsDcNU/edit?usp=drivesdk',
85
+ id: '1_9xjsrYFgHVvgqYwAJ8KcsDcN3AzPelsux',
86
+ name: 'Test Document',
87
+ },
88
+ });
@@ -0,0 +1,96 @@
1
+ import { googleSheetsAuth } from '../common/common';
2
+ import { createTrigger, TriggerStrategy } from '@guayaba/workflows-framework';
3
+ import { google } from 'googleapis';
4
+ import { isNil } from '@guayaba/workflows-shared';
5
+ import { includeTeamDrivesProp, spreadsheetIdProp } from '../common/props';
6
+ import { createGoogleClient } from '../common/common';
7
+
8
+ export const newWorksheetTrigger = createTrigger({
9
+ auth: googleSheetsAuth,
10
+ name: 'new-worksheet',
11
+ displayName: 'New Worksheet',
12
+ description: 'Triggers when a worksheet is created in a spreadsheet.',
13
+ type: TriggerStrategy.POLLING,
14
+ props: {
15
+ includeTeamDrives: includeTeamDrivesProp(),
16
+ spreadsheetId: spreadsheetIdProp('Spreadsheet', '',true),
17
+ },
18
+ async onEnable(context) {
19
+ const ids: number[] = [];
20
+ const authClient = await createGoogleClient(context.auth);
21
+ const sheets = google.sheets({ version: 'v4', auth: authClient });
22
+ const response = await sheets.spreadsheets.get({
23
+ spreadsheetId: context.propsValue.spreadsheetId as string,
24
+ });
25
+ if (response.data.sheets) {
26
+ for (const sheet of response.data.sheets) {
27
+ const sheetId = sheet.properties?.sheetId;
28
+ if (sheetId) {
29
+ ids.push(sheetId);
30
+ }
31
+ }
32
+ }
33
+ await context.store.put('worksheets', JSON.stringify(ids));
34
+ },
35
+ async onDisable(context) {
36
+ await context.store.delete('worksheets');
37
+ },
38
+ async test(context) {
39
+ const worksheets = [];
40
+ const authClient = await createGoogleClient(context.auth);
41
+ const sheets = google.sheets({ version: 'v4', auth: authClient });
42
+ const response = await sheets.spreadsheets.get({
43
+ spreadsheetId: context.propsValue.spreadsheetId as string,
44
+ });
45
+
46
+ if (response.data.sheets) {
47
+ for (const sheet of response.data.sheets) {
48
+ worksheets.push(sheet);
49
+ }
50
+ }
51
+ return worksheets;
52
+ },
53
+ async run(context) {
54
+ const existingIds = (await context.store.get<string>('worksheets')) ?? '[]';
55
+ const parsedExistingIds = JSON.parse(existingIds) as number[];
56
+
57
+ const authClient = await createGoogleClient(context.auth);
58
+
59
+ const sheets = google.sheets({ version: 'v4', auth: authClient });
60
+
61
+ const response = await sheets.spreadsheets.get({
62
+ spreadsheetId: context.propsValue.spreadsheetId as string,
63
+ });
64
+ if (isNil(response.data.sheets) || response.data.sheets.length === 0) {
65
+ return [];
66
+ }
67
+ // Filter valid worksheetss
68
+ const newWorksheets = response.data.sheets.filter((sheet) => {
69
+ const sheetId = sheet.properties?.sheetId ?? undefined;
70
+ return sheetId !== undefined && !parsedExistingIds.includes(sheetId);
71
+ });
72
+
73
+ const newIds = newWorksheets
74
+ .map((sheet) => sheet.properties?.sheetId ?? undefined)
75
+ .filter((id): id is number => id !== undefined);
76
+
77
+ if (newIds.length === 0) {
78
+ return [];
79
+ }
80
+ // Store new IDs
81
+ await context.store.put('worksheets', JSON.stringify([...newIds, ...parsedExistingIds]));
82
+ return newWorksheets;
83
+ },
84
+ sampleData: {
85
+ properties: {
86
+ sheetId: 2077270595,
87
+ title: 'Sheet5',
88
+ index: 1,
89
+ sheetType: 'GRID',
90
+ gridProperties: {
91
+ rowCount: 1000,
92
+ columnCount: 26,
93
+ },
94
+ },
95
+ },
96
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "extends": "../../../../tsconfig.base.json",
3
+ "files": [],
4
+ "include": [],
5
+ "references": [
6
+ {
7
+ "path": "./tsconfig.lib.json"
8
+ }
9
+ ],
10
+ "compilerOptions": {
11
+ "forceConsistentCasingInFileNames": true,
12
+ "strict": true,
13
+ "noImplicitReturns": true,
14
+ "noFallthroughCasesInSwitch": true
15
+ }
16
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "module": "commonjs",
5
+ "rootDir": ".",
6
+ "baseUrl": ".",
7
+ "paths": {},
8
+ "outDir": "./dist",
9
+ "declaration": true,
10
+ "declarationMap": true,
11
+ "types": ["node"]
12
+ },
13
+ "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
14
+ "include": ["src/**/*.ts"]
15
+ }