From 8ba379bbda8a097c65899441e03f6d2438648512 Mon Sep 17 00:00:00 2001 From: Steve Sewell Date: Thu, 10 Sep 2026 08:50:46 -0700 Subject: [PATCH 1/7] chore: publish branch work in templates/analytics (2 files) --- .../canonical-first-party-dashboard-repair.ts | 7 +++- .../lib/first-party-dashboard-repair.spec.ts | 33 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts b/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts index 850df17e6a..a18fba6e33 100644 --- a/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +++ b/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts @@ -73,6 +73,10 @@ SELECT date, template, visitors FROM wau ORDER BY date, template`; +function isMalformedFirstPartyBigQueryWauSql(sql: string): boolean { + return sql.includes("WHEN '{{timeRange}}' = '{{timeRange}}'"); +} + export function repairFirstPartyBigQueryDashboardQueries( config: Record, ): { config: Record; changed: boolean } { @@ -86,7 +90,8 @@ export function repairFirstPartyBigQueryDashboardQueries( panel.id !== "wau-over-time" || panel.source !== "bigquery" || typeof panel.sql !== "string" || - panel.sql.trim() !== "" + (panel.sql.trim() !== "" && + !isMalformedFirstPartyBigQueryWauSql(panel.sql)) ) { return rawPanel; } diff --git a/templates/analytics/server/lib/first-party-dashboard-repair.spec.ts b/templates/analytics/server/lib/first-party-dashboard-repair.spec.ts index 6b19d897f3..1ac6577f91 100644 --- a/templates/analytics/server/lib/first-party-dashboard-repair.spec.ts +++ b/templates/analytics/server/lib/first-party-dashboard-repair.spec.ts @@ -474,6 +474,39 @@ describe("repairPersistedFirstPartyDashboardQueries", () => { expect(panels[2].sql).toBe(""); }); + it("repairs the malformed non-empty BigQuery wau query", async () => { + const weekly = requiredFirstPartyPanel("wau-over-time"); + const malformedSql = FIRST_PARTY_BIGQUERY_WAU_SQL.replace( + "WHEN '{{timeRange}}' = '7d'", + "WHEN '{{timeRange}}' = '{{timeRange}}'", + ); + const row = legacyRow({ + id: FIRST_PARTY_BIGQUERY_DASHBOARD_ID, + config: JSON.stringify({ + panels: [ + { + ...weekly, + source: "bigquery", + sql: malformedSql, + }, + ], + }), + }); + const mocks = createDb(row); + dbMocks.getDb.mockReturnValue(mocks.db); + + await expect(repairPersistedFirstPartyDashboardQueries()).resolves.toBe( + true, + ); + + const updateCalls = mocks.updateSet.mock.calls as unknown as Array< + [{ config: string }] + >; + expect(JSON.parse(updateCalls[0]![0].config).panels[0].sql).toBe( + FIRST_PARTY_BIGQUERY_WAU_SQL, + ); + }); + it("repairs the deployed materialized one-day retention panel during startup", async () => { const retention = requiredFirstPartyPanel("one-day-retention-by-template"); const row = legacyRow({ From 577c7c21e0bd9905a40992750a34e3099cb89294 Mon Sep 17 00:00:00 2001 From: Steve Sewell Date: Thu, 10 Sep 2026 09:47:01 -0700 Subject: [PATCH 2/7] chore: publish branch work in templates/analytics (2 files) --- .../canonical-first-party-dashboard-repair.ts | 14 +++++++++- .../lib/first-party-dashboard-repair.spec.ts | 28 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts b/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts index a18fba6e33..03778b01ee 100644 --- a/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +++ b/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts @@ -73,8 +73,20 @@ SELECT date, template, visitors FROM wau ORDER BY date, template`; +const MALFORMED_FIRST_PARTY_BIGQUERY_WAU_SQL = + FIRST_PARTY_BIGQUERY_WAU_SQL.replace( + "WHEN '{{timeRange}}' = '7d'", + "WHEN '{{timeRange}}' = '{{timeRange}}'", + ); + +function normalizeSql(sql: string): string { + return sql.replace(/\s+/g, " ").trim(); +} + function isMalformedFirstPartyBigQueryWauSql(sql: string): boolean { - return sql.includes("WHEN '{{timeRange}}' = '{{timeRange}}'"); + return ( + normalizeSql(sql) === normalizeSql(MALFORMED_FIRST_PARTY_BIGQUERY_WAU_SQL) + ); } export function repairFirstPartyBigQueryDashboardQueries( diff --git a/templates/analytics/server/lib/first-party-dashboard-repair.spec.ts b/templates/analytics/server/lib/first-party-dashboard-repair.spec.ts index 1ac6577f91..d4617aeb0c 100644 --- a/templates/analytics/server/lib/first-party-dashboard-repair.spec.ts +++ b/templates/analytics/server/lib/first-party-dashboard-repair.spec.ts @@ -507,6 +507,34 @@ describe("repairPersistedFirstPartyDashboardQueries", () => { ); }); + it("preserves a customized malformed-looking BigQuery wau query", async () => { + const weekly = requiredFirstPartyPanel("wau-over-time"); + const customizedSql = FIRST_PARTY_BIGQUERY_WAU_SQL.replace( + "WHEN '{{timeRange}}' = '7d'", + "WHEN '{{timeRange}}' = '{{timeRange}}'", + ).replace("ORDER BY date, template", "ORDER BY template, date"); + const row = legacyRow({ + id: FIRST_PARTY_BIGQUERY_DASHBOARD_ID, + config: JSON.stringify({ + panels: [ + { + ...weekly, + source: "bigquery", + sql: customizedSql, + }, + ], + }), + }); + const mocks = createDb(row); + dbMocks.getDb.mockReturnValue(mocks.db); + + await expect(repairPersistedFirstPartyDashboardQueries()).resolves.toBe( + false, + ); + + expect(mocks.update).not.toHaveBeenCalled(); + }); + it("repairs the deployed materialized one-day retention panel during startup", async () => { const retention = requiredFirstPartyPanel("one-day-retention-by-template"); const row = legacyRow({ From 49b5aa1ecd7af8cfa072df6831357ec7664ada51 Mon Sep 17 00:00:00 2001 From: Steve Sewell Date: Thu, 10 Sep 2026 10:20:17 -0700 Subject: [PATCH 3/7] chore: publish branch work in templates/analytics (2 files) --- .../canonical-first-party-dashboard-repair.ts | 8 +----- .../lib/first-party-dashboard-repair.spec.ts | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts b/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts index 03778b01ee..1a028686fe 100644 --- a/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +++ b/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts @@ -79,14 +79,8 @@ const MALFORMED_FIRST_PARTY_BIGQUERY_WAU_SQL = "WHEN '{{timeRange}}' = '{{timeRange}}'", ); -function normalizeSql(sql: string): string { - return sql.replace(/\s+/g, " ").trim(); -} - function isMalformedFirstPartyBigQueryWauSql(sql: string): boolean { - return ( - normalizeSql(sql) === normalizeSql(MALFORMED_FIRST_PARTY_BIGQUERY_WAU_SQL) - ); + return sql.trim() === MALFORMED_FIRST_PARTY_BIGQUERY_WAU_SQL.trim(); } export function repairFirstPartyBigQueryDashboardQueries( diff --git a/templates/analytics/server/lib/first-party-dashboard-repair.spec.ts b/templates/analytics/server/lib/first-party-dashboard-repair.spec.ts index d4617aeb0c..d2e6d57dcd 100644 --- a/templates/analytics/server/lib/first-party-dashboard-repair.spec.ts +++ b/templates/analytics/server/lib/first-party-dashboard-repair.spec.ts @@ -535,6 +535,34 @@ describe("repairPersistedFirstPartyDashboardQueries", () => { expect(mocks.update).not.toHaveBeenCalled(); }); + it("preserves a malformed-looking query when a SQL literal changes", async () => { + const weekly = requiredFirstPartyPanel("wau-over-time"); + const customizedSql = FIRST_PARTY_BIGQUERY_WAU_SQL.replace( + "WHEN '{{timeRange}}' = '7d'", + "WHEN '{{timeRange}}' = '{{timeRange}}'", + ).replace("'session status'", "'session status'"); + const row = legacyRow({ + id: FIRST_PARTY_BIGQUERY_DASHBOARD_ID, + config: JSON.stringify({ + panels: [ + { + ...weekly, + source: "bigquery", + sql: customizedSql, + }, + ], + }), + }); + const mocks = createDb(row); + dbMocks.getDb.mockReturnValue(mocks.db); + + await expect(repairPersistedFirstPartyDashboardQueries()).resolves.toBe( + false, + ); + + expect(mocks.update).not.toHaveBeenCalled(); + }); + it("repairs the deployed materialized one-day retention panel during startup", async () => { const retention = requiredFirstPartyPanel("one-day-retention-by-template"); const row = legacyRow({ From 3b5d1b6af70ca6cb3ea91ea134abc7f537b4654a Mon Sep 17 00:00:00 2001 From: Steve Sewell Date: Thu, 10 Sep 2026 11:00:39 -0700 Subject: [PATCH 4/7] chore: publish branch work in scripts/qa-standalone-chat-dev-smoke.ts (1 files) --- scripts/qa-standalone-chat-dev-smoke.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/qa-standalone-chat-dev-smoke.ts b/scripts/qa-standalone-chat-dev-smoke.ts index 921716a3cb..25b6cba278 100644 --- a/scripts/qa-standalone-chat-dev-smoke.ts +++ b/scripts/qa-standalone-chat-dev-smoke.ts @@ -671,6 +671,10 @@ function suppressedNoiseBlock(): string { function isBenignConsoleError(text: string): boolean { if (text.startsWith("Failed to load resource:")) return true; if (text.includes("favicon")) return true; + if ( + text.startsWith("Encountered a script tag while rendering React component.") + ) + return true; return false; } From e3b86f26bb7eca761686a230309e009ab9c56254 Mon Sep 17 00:00:00 2001 From: Steve Sewell Date: Thu, 10 Sep 2026 11:26:21 -0700 Subject: [PATCH 5/7] chore: publish branch work in templates/analytics (1 files) --- ...y-active-user-charts-now-show-the-full-selected-histo.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 templates/analytics/changelog/2026-09-10-bigquery-active-user-charts-now-show-the-full-selected-histo.md diff --git a/templates/analytics/changelog/2026-09-10-bigquery-active-user-charts-now-show-the-full-selected-histo.md b/templates/analytics/changelog/2026-09-10-bigquery-active-user-charts-now-show-the-full-selected-histo.md new file mode 100644 index 0000000000..800b16885c --- /dev/null +++ b/templates/analytics/changelog/2026-09-10-bigquery-active-user-charts-now-show-the-full-selected-histo.md @@ -0,0 +1,6 @@ +--- +type: fixed +date: 2026-09-10 +--- + +BigQuery active-user charts now show the full selected history From 1eed98a6a25bf00b2c8f9edd0b8b25436f2429b6 Mon Sep 17 00:00:00 2001 From: Steve Sewell Date: Thu, 10 Sep 2026 11:27:49 -0700 Subject: [PATCH 6/7] chore: publish branch work in templates/analytics (1 files) --- ...query-active-user-charts-now-show-the-full-selected-histo.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/analytics/changelog/2026-09-10-bigquery-active-user-charts-now-show-the-full-selected-histo.md b/templates/analytics/changelog/2026-09-10-bigquery-active-user-charts-now-show-the-full-selected-histo.md index 800b16885c..f446f67afd 100644 --- a/templates/analytics/changelog/2026-09-10-bigquery-active-user-charts-now-show-the-full-selected-histo.md +++ b/templates/analytics/changelog/2026-09-10-bigquery-active-user-charts-now-show-the-full-selected-histo.md @@ -3,4 +3,4 @@ type: fixed date: 2026-09-10 --- -BigQuery active-user charts now show the full selected history +BigQuery active-user charts now show the full selected history. From 482d58b246bfe9e25130a45ff8fc74a9833ed9ea Mon Sep 17 00:00:00 2001 From: Steve Sewell Date: Thu, 10 Sep 2026 13:29:20 -0700 Subject: [PATCH 7/7] test: align analytics sidebar assertions with shared sidebar --- .../app/components/layout/Layout.spec.ts | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/templates/analytics/app/components/layout/Layout.spec.ts b/templates/analytics/app/components/layout/Layout.spec.ts index 771bf3d8e6..22b055f82e 100644 --- a/templates/analytics/app/components/layout/Layout.spec.ts +++ b/templates/analytics/app/components/layout/Layout.spec.ts @@ -34,15 +34,13 @@ describe("Analytics layout sidebar route policy", () => { 'className="flex min-h-0 flex-1 flex-col overflow-hidden py-2"', ); expect(source).toContain( - 'className="min-h-0 min-w-0 flex flex-1 flex-col gap-1 overflow-x-hidden overflow-y-auto px-2 text-sm font-medium"', + 'className="min-h-0 min-w-0 flex flex-1 flex-col space-y-0.5 overflow-x-hidden overflow-y-auto px-2 py-3"', ); - expect(source).toContain('className="flex min-w-0 flex-col gap-1 pb-1"'); expect(source).toContain( - 'className="shrink-0 min-w-0 px-2 pt-2 text-sm font-medium"', - ); - expect(source).toContain( - 'className="flex h-12 shrink-0 items-center border-b border-border px-4"', + 'className="mt-3 shrink-0 min-w-0 space-y-0.5 border-t border-border/70 px-2 pt-3"', ); + expect(source).toContain(" { ); expect(source).toContain( - 'className="flex min-h-0 flex-1 flex-col items-center gap-0.5 overflow-y-auto px-1 py-2"', - ); - expect(source).toContain( - '"flex h-9 w-9 items-center justify-center rounded-md transition-colors"', + 'className="flex min-h-0 flex-1 flex-col items-center gap-1 overflow-y-auto px-2 py-3"', ); expect(source).toContain( - 'className="min-h-0 min-w-0 flex flex-1 flex-col gap-1 overflow-x-hidden overflow-y-auto px-2 text-sm font-medium"', + 'className="min-h-0 min-w-0 flex flex-1 flex-col space-y-0.5 overflow-x-hidden overflow-y-auto px-2 py-3"', ); }); });