From 883d2b6995b43b78812f797315ffdeed66cf0496 Mon Sep 17 00:00:00 2001 From: Joaquim d'Souza Date: Tue, 7 Apr 2026 12:19:10 +0200 Subject: [PATCH 1/4] fix: add google sheets to refreshWebhooks jobs --- src/server/adaptors/googlesheets.ts | 28 ++++++++++++++++---- src/server/jobs/refreshWebhooks.ts | 41 ++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/src/server/adaptors/googlesheets.ts b/src/server/adaptors/googlesheets.ts index ee15ee04c..f819c978d 100644 --- a/src/server/adaptors/googlesheets.ts +++ b/src/server/adaptors/googlesheets.ts @@ -339,8 +339,9 @@ export class GoogleSheetsAdaptor implements DataSourceAdaptor { } /** - * Checks if the webhook sheet contains formula errors. - * Returns true if #ERROR! or other error values are detected. + * Checks if the webhook sheet contains formula errors or is missing rows. + * Returns true if #ERROR! or other error values are detected, or if the + * webhook sheet has fewer rows than the main sheet (excluding the header row). */ async hasWebhookErrors(): Promise { try { @@ -350,9 +351,18 @@ export class GoogleSheetsAdaptor implements DataSourceAdaptor { const notificationDomain = new URL(notificationUrl).hostname; const webhookSheetName = `Mapped Webhook: ${notificationDomain}/${this.dataSourceId}`; - // Read first few cells from webhook sheet to check for errors - const url = `https://sheets.googleapis.com/v4/spreadsheets/${this.spreadsheetId}/values/${encodeURIComponent(webhookSheetName)}!A1:B5`; - const response = await this.makeGoogleSheetsRequest(url); + // Get main sheet row count (column A, same as prepareWebhookSheet) + const mainSheetUrl = `https://sheets.googleapis.com/v4/spreadsheets/${this.spreadsheetId}/values/${encodeURIComponent(`${this.sheetName}!A:A`)}`; + const mainSheetResponse = await this.makeGoogleSheetsRequest(mainSheetUrl); + const mainSheetData = mainSheetResponse.ok + ? ((await mainSheetResponse.json()) as { values: string[][] }) + : { values: [] }; + // Subtract 1 for the header row + const mainRowCount = Math.max(0, (mainSheetData.values?.length || 0) - 1); + + // Read all rows from webhook sheet column A to check for errors and count rows + const webhookUrl = `https://sheets.googleapis.com/v4/spreadsheets/${this.spreadsheetId}/values/${encodeURIComponent(webhookSheetName)}!A:B`; + const response = await this.makeGoogleSheetsRequest(webhookUrl); if (!response.ok) { return false; // Sheet doesn't exist or can't be read @@ -376,6 +386,14 @@ export class GoogleSheetsAdaptor implements DataSourceAdaptor { } } + // Check if webhook sheet is missing rows relative to the main sheet + if (rows.length < mainRowCount) { + logger.warn( + `Webhook sheet for ${this.dataSourceId} has ${rows.length} rows but main sheet has ${mainRowCount} data rows`, + ); + return true; + } + return false; } catch (error) { logger.warn(`Could not check webhook errors for ${this.dataSourceId}`, { diff --git a/src/server/jobs/refreshWebhooks.ts b/src/server/jobs/refreshWebhooks.ts index f110ce8e5..0ebd93f59 100644 --- a/src/server/jobs/refreshWebhooks.ts +++ b/src/server/jobs/refreshWebhooks.ts @@ -1,5 +1,10 @@ -import { DataSourceType, airtableConfigSchema } from "@/models/DataSource"; +import { + DataSourceType, + airtableConfigSchema, + googleSheetsConfigSchema, +} from "@/models/DataSource"; import { AirtableAdaptor } from "@/server/adaptors/airtable"; +import { GoogleSheetsAdaptor } from "@/server/adaptors/googlesheets"; import { findDataSourceById, findDataSourcesByType, @@ -42,6 +47,40 @@ const refreshWebhooks = async (args: object | null): Promise => { continue; } } + + const googleSheetsDataSources = await findDataSourcesByType( + DataSourceType.GoogleSheets, + ); + for (const source of googleSheetsDataSources) { + const result = googleSheetsConfigSchema.safeParse(source.config); + if (!result.success) { + logger.warn( + `Failed to parse Google Sheets config for data source ${source.id}`, + { error: result.error }, + ); + continue; + } + const config = result.data; + const adaptor = new GoogleSheetsAdaptor( + source.id, + config.spreadsheetId, + config.sheetName, + config.oAuthCredentials, + ); + try { + const hasErrors = await adaptor.hasWebhookErrors(); + if (hasErrors) { + await adaptor.repairWebhook(); + } + } catch (error) { + logger.warn( + `Failed to repair Google Sheets webhook for data source ${source.id}`, + { error }, + ); + continue; + } + } + return true; }; From 38db54ca5980189f695fc9e484607acc7152aa37 Mon Sep 17 00:00:00 2001 From: joaquimds Date: Tue, 7 Apr 2026 12:36:31 +0200 Subject: [PATCH 2/4] Update src/server/jobs/refreshWebhooks.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/server/jobs/refreshWebhooks.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/server/jobs/refreshWebhooks.ts b/src/server/jobs/refreshWebhooks.ts index 0ebd93f59..fbc39af27 100644 --- a/src/server/jobs/refreshWebhooks.ts +++ b/src/server/jobs/refreshWebhooks.ts @@ -67,14 +67,18 @@ const refreshWebhooks = async (args: object | null): Promise => { config.sheetName, config.oAuthCredentials, ); + const enable = source.autoEnrich || source.autoImport; try { - const hasErrors = await adaptor.hasWebhookErrors(); - if (hasErrors) { - await adaptor.repairWebhook(); + await adaptor.toggleWebhook(enable); + if (enable) { + const hasErrors = await adaptor.hasWebhookErrors(); + if (hasErrors) { + await adaptor.repairWebhook(); + } } } catch (error) { logger.warn( - `Failed to repair Google Sheets webhook for data source ${source.id}`, + `Failed to refresh Google Sheets webhook for data source ${source.id}`, { error }, ); continue; From 4f95552a642d33a9a14497c80fad5152adf820b3 Mon Sep 17 00:00:00 2001 From: joaquimds Date: Tue, 7 Apr 2026 12:37:02 +0200 Subject: [PATCH 3/4] Update src/server/adaptors/googlesheets.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/server/adaptors/googlesheets.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/server/adaptors/googlesheets.ts b/src/server/adaptors/googlesheets.ts index f819c978d..433883e33 100644 --- a/src/server/adaptors/googlesheets.ts +++ b/src/server/adaptors/googlesheets.ts @@ -387,9 +387,12 @@ export class GoogleSheetsAdaptor implements DataSourceAdaptor { } // Check if webhook sheet is missing rows relative to the main sheet - if (rows.length < mainRowCount) { + // Row 1 in the webhook sheet contains the row-count formula, so exclude it + // to compare webhook data rows against main-sheet data rows. + const webhookDataRowCount = Math.max(0, rows.length - 1); + if (webhookDataRowCount < mainRowCount) { logger.warn( - `Webhook sheet for ${this.dataSourceId} has ${rows.length} rows but main sheet has ${mainRowCount} data rows`, + `Webhook sheet for ${this.dataSourceId} has ${webhookDataRowCount} data rows but main sheet has ${mainRowCount} data rows`, ); return true; } From 08f44654578eb8720d04c44ad3d543690b2c104f Mon Sep 17 00:00:00 2001 From: Joaquim d'Souza Date: Tue, 7 Apr 2026 12:37:55 +0200 Subject: [PATCH 4/4] fix: lint --- src/app/(private)/hooks/useDataSourceListCache.ts | 2 -- src/server/adaptors/googlesheets.ts | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/app/(private)/hooks/useDataSourceListCache.ts b/src/app/(private)/hooks/useDataSourceListCache.ts index 0cffeb578..eec126106 100644 --- a/src/app/(private)/hooks/useDataSourceListCache.ts +++ b/src/app/(private)/hooks/useDataSourceListCache.ts @@ -62,7 +62,6 @@ export function useDataSourceListCache() { ...ds, ...updater({ ...ds, - organisationName: "", organisationOverride: null, }), } @@ -77,7 +76,6 @@ export function useDataSourceListCache() { ...old, ...updater({ ...old, - organisationName: "", organisationOverride: null, }), }; diff --git a/src/server/adaptors/googlesheets.ts b/src/server/adaptors/googlesheets.ts index 433883e33..ee4c4de30 100644 --- a/src/server/adaptors/googlesheets.ts +++ b/src/server/adaptors/googlesheets.ts @@ -353,7 +353,8 @@ export class GoogleSheetsAdaptor implements DataSourceAdaptor { // Get main sheet row count (column A, same as prepareWebhookSheet) const mainSheetUrl = `https://sheets.googleapis.com/v4/spreadsheets/${this.spreadsheetId}/values/${encodeURIComponent(`${this.sheetName}!A:A`)}`; - const mainSheetResponse = await this.makeGoogleSheetsRequest(mainSheetUrl); + const mainSheetResponse = + await this.makeGoogleSheetsRequest(mainSheetUrl); const mainSheetData = mainSheetResponse.ok ? ((await mainSheetResponse.json()) as { values: string[][] }) : { values: [] };