Skip to content

Commit cfcdb6e

Browse files
update source
1 parent 1ff970d commit cfcdb6e

File tree

4 files changed

+424
-58
lines changed

4 files changed

+424
-58
lines changed

components/google_sheets/sources/new-comment/new-comment.mjs

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,30 @@
1-
import httpBase from "../common/http-based/sheet.mjs";
1+
import app from "../../google_sheets.app.mjs";
22
import sampleEmit from "./test-event.mjs";
33

44
export default {
5-
...httpBase,
65
key: "google_sheets-new-comment",
76
name: "New Comment (Instant)",
87
description: "Emit new event each time a comment is added to a spreadsheet.",
9-
version: "0.1.3",
8+
version: "0.2.0",
109
dedupe: "unique",
1110
type: "source",
11+
props: {
12+
app,
13+
db: "$.service.db",
14+
timer: {
15+
type: "$.interface.timer",
16+
default: {
17+
intervalSeconds: 60,
18+
},
19+
},
20+
sheetID: {
21+
propDefinition: [
22+
app,
23+
"sheetID",
24+
],
25+
},
26+
},
1227
methods: {
13-
...httpBase.methods,
1428
_getLastTs() {
1529
return this.db.get("lastTs");
1630
},
@@ -24,18 +38,20 @@ export default {
2438
ts: Date.parse(comment.createdTime),
2539
};
2640
},
27-
takeSheetSnapshot() {},
28-
getSheetId() {
29-
return this.sheetID.toString();
30-
},
3141
async processSpreadsheet() {
3242
const comments = [];
3343
const lastTs = this._getLastTs();
34-
const results = this.googleSheets.listComments(this.sheetID, lastTs);
35-
for await (const comment of results) {
36-
comments.push(comment);
44+
45+
try {
46+
const results = this.app.listComments(this.sheetID, lastTs);
47+
for await (const comment of results) {
48+
comments.push(comment);
49+
}
50+
} catch (error) {
51+
console.error("Error fetching comments:", error);
3752
}
3853
if (!comments.length) {
54+
console.log("No new comments since last check");
3955
return;
4056
}
4157
this._setLastTs(comments[0].createdTime);
@@ -45,17 +61,8 @@ export default {
4561
});
4662
},
4763
},
48-
async run(event) {
49-
if (event.timestamp) {
50-
// Component was invoked by timer
51-
return this.renewSubscription();
52-
}
53-
54-
if (!this.isEventRelevant(event)) {
55-
console.log("Sync notification, exiting early");
56-
return;
57-
}
58-
64+
async run() {
65+
// Component was invoked by timer
5966
await this.processSpreadsheet();
6067
},
6168
sampleEmit,
Lines changed: 156 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,167 @@
1-
import httpBase from "../common/http-based/sheet.mjs";
2-
import newRowAdded from "../common/new-row-added.mjs";
31
import sampleEmit from "./test-event.mjs";
42

53
export default {
6-
...httpBase,
7-
...newRowAdded,
84
key: "google_sheets-new-row-added",
9-
name: "New Row Added (Instant)",
10-
description: "Emit new event each time a row or rows are added to the bottom of a spreadsheet.",
11-
version: "0.2.3",
12-
dedupe: "unique",
135
type: "source",
6+
name: "New Row Added (Polling)",
7+
description:
8+
"Emit new event each time a row or rows are added to the bottom of a spreadsheet.",
9+
version: "0.3.0",
10+
dedupe: "unique",
1411
props: {
15-
...httpBase.props,
16-
...newRowAdded.props,
12+
db: "$.service.db",
13+
http: "$.interface.http",
14+
google_sheets: {
15+
type: "app",
16+
app: "google_sheets",
17+
label: "Google Sheets",
18+
description: "Google Sheets account used to access the Sheets API",
19+
},
20+
spreadsheet_id: {
21+
type: "string",
22+
label: "Spreadsheet ID",
23+
description: "The Google Sheets spreadsheet ID",
24+
},
25+
sheet_name: {
26+
type: "string",
27+
label: "Sheet Name",
28+
description: "The name of the sheet to monitor (e.g., 'Sheet1')",
29+
},
1730
},
1831
methods: {
19-
...httpBase.methods,
20-
...newRowAdded.methods,
32+
async getSheetData() {
33+
const {
34+
google_sheets,
35+
spreadsheet_id,
36+
sheet_name,
37+
} = this;
38+
39+
const response = await google_sheets.request({
40+
url: `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheet_id}/values/${encodeURIComponent(sheet_name)}`,
41+
method: "GET",
42+
});
43+
44+
if (response && response.values) {
45+
return response.values;
46+
}
47+
return [];
48+
},
49+
50+
async getHeaderRow() {
51+
const data = await this.getSheetData();
52+
if (data.length > 0) {
53+
return data[0];
54+
}
55+
return [];
56+
},
57+
58+
rowToObject(headers, rowData) {
59+
const obj = {};
60+
headers.forEach((header, idx) => {
61+
obj[header] = rowData[idx] || "";
62+
});
63+
return obj;
64+
},
65+
66+
getStoredRowCount() {
67+
const {
68+
spreadsheet_id,
69+
sheet_name,
70+
db,
71+
} = this;
72+
const stateKey = `row-count-${spreadsheet_id}-${sheet_name}`;
73+
return db.get(stateKey) || 0;
74+
},
75+
76+
updateStoredRowCount(count) {
77+
const {
78+
spreadsheet_id,
79+
sheet_name,
80+
db,
81+
} = this;
82+
const stateKey = `row-count-${spreadsheet_id}-${sheet_name}`;
83+
db.set(stateKey, count);
84+
},
85+
86+
getStoredRows() {
87+
const {
88+
spreadsheet_id,
89+
sheet_name,
90+
db,
91+
} = this;
92+
const stateKey = `rows-${spreadsheet_id}-${sheet_name}`;
93+
return db.get(stateKey) || [];
94+
},
95+
96+
updateStoredRows(rows) {
97+
const {
98+
spreadsheet_id,
99+
sheet_name,
100+
db,
101+
} = this;
102+
const stateKey = `rows-${spreadsheet_id}-${sheet_name}`;
103+
db.set(stateKey, rows);
104+
},
105+
},
106+
async run() {
107+
const {
108+
spreadsheet_id,
109+
sheet_name,
110+
} = this;
111+
112+
if (!spreadsheet_id || !sheet_name) {
113+
throw new Error("Please provide both Spreadsheet ID and Sheet Name");
114+
}
115+
116+
try {
117+
const allData = await this.getSheetData();
118+
119+
// Sheet must have at least a header row
120+
if (allData.length === 0) {
121+
this.updateStoredRowCount(0);
122+
return;
123+
}
124+
125+
const headers = allData[0];
126+
const currentRows = allData.slice(1); // Exclude header
127+
const storedRowCount = this.getStoredRowCount();
128+
129+
// Detect new rows added to the bottom
130+
if (currentRows.length > storedRowCount) {
131+
const newRows = currentRows.slice(storedRowCount);
132+
133+
// Emit event for new rows
134+
newRows.forEach((rowData, idx) => {
135+
const rowNumber = storedRowCount + idx + 2; // +2: 1 for header, 1 for 1-indexing
136+
const rowObject = this.rowToObject(headers, rowData);
137+
138+
this.$emit(
139+
{
140+
row_number: rowNumber,
141+
values: rowData,
142+
object: rowObject,
143+
spreadsheet_id,
144+
sheet_name,
145+
timestamp: new Date().toISOString(),
146+
},
147+
{
148+
id: `${spreadsheet_id}-${sheet_name}-row-${rowNumber}`,
149+
summary: `New row added at row ${rowNumber}`,
150+
ts: Date.now(),
151+
},
152+
);
153+
});
154+
155+
// Update stored row count
156+
this.updateStoredRowCount(currentRows.length);
157+
} else if (storedRowCount === 0) {
158+
// First run: store current row count without emitting
159+
this.updateStoredRowCount(currentRows.length);
160+
}
161+
} catch (error) {
162+
console.error(`Error fetching sheet data: ${error.message}`);
163+
throw error;
164+
}
21165
},
22166
sampleEmit,
23167
};

0 commit comments

Comments
 (0)