Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions apps/desktop/src/lib/trpc/routers/settings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { localDb } from "main/lib/local-db";
import {
DEFAULT_AUTO_APPLY_DEFAULT_PRESET,
DEFAULT_CONFIRM_ON_QUIT,
DEFAULT_TELEMETRY_ENABLED,
DEFAULT_TERMINAL_LINK_BEHAVIOR,
DEFAULT_TERMINAL_PERSISTENCE,
} from "shared/constants";
Expand Down Expand Up @@ -405,5 +406,25 @@ export const createSettingsRouter = () => {

return { success: true };
}),

getTelemetryEnabled: publicProcedure.query(() => {
const row = getSettings();
return row.telemetryEnabled ?? DEFAULT_TELEMETRY_ENABLED;
}),

setTelemetryEnabled: publicProcedure
.input(z.object({ enabled: z.boolean() }))
.mutation(({ input }) => {
localDb
.insert(settings)
.values({ id: 1, telemetryEnabled: input.enabled })
.onConflictDoUpdate({
target: settings.id,
set: { telemetryEnabled: input.enabled },
})
.run();

return { success: true };
}),
});
};
13 changes: 13 additions & 0 deletions apps/desktop/src/main/lib/analytics/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { settings } from "@superset/local-db";
import { app } from "electron";
import { env } from "main/env.main";
import { localDb } from "main/lib/local-db";
import { PostHog } from "posthog-node";
import { DEFAULT_TELEMETRY_ENABLED } from "shared/constants";

export let posthog: PostHog | null = null;
let userId: string | null = null;
Expand All @@ -20,6 +23,15 @@ function getClient(): PostHog | null {
return posthog;
}

function isTelemetryEnabled(): boolean {
try {
const row = localDb.select().from(settings).get();
return row?.telemetryEnabled ?? DEFAULT_TELEMETRY_ENABLED;
} catch {
return DEFAULT_TELEMETRY_ENABLED;
}
}
Comment on lines +26 to +33
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add error logging in the catch block.

The catch block silently swallows errors without any logging. Per coding guidelines, errors should at minimum be logged with context to aid debugging.

🛡️ Proposed fix to add error logging
 function isTelemetryEnabled(): boolean {
 	try {
 		const row = localDb.select().from(settings).get();
 		return row?.telemetryEnabled ?? DEFAULT_TELEMETRY_ENABLED;
-	} catch {
+	} catch (error) {
+		console.error("[analytics/telemetry] Failed to read telemetry setting:", error);
 		return DEFAULT_TELEMETRY_ENABLED;
 	}
 }

As per coding guidelines: "Never swallow errors silently; at minimum log them with context" and "Use prefixed console logging with pattern [domain/operation] message for all logging".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function isTelemetryEnabled(): boolean {
try {
const row = localDb.select().from(settings).get();
return row?.telemetryEnabled ?? DEFAULT_TELEMETRY_ENABLED;
} catch {
return DEFAULT_TELEMETRY_ENABLED;
}
}
function isTelemetryEnabled(): boolean {
try {
const row = localDb.select().from(settings).get();
return row?.telemetryEnabled ?? DEFAULT_TELEMETRY_ENABLED;
} catch (error) {
console.error("[analytics/telemetry] Failed to read telemetry setting:", error);
return DEFAULT_TELEMETRY_ENABLED;
}
}
🤖 Prompt for AI Agents
In `@apps/desktop/src/main/lib/analytics/index.ts` around lines 26 - 33, The catch
in isTelemetryEnabled silently swallows errors; update the catch block to log
the caught error with context using the prefixed pattern (e.g.
"[analytics/isTelemetryEnabled]") before returning
DEFAULT_TELEMETRY_ENABLED—capture the exception from the failing call to
localDb.select().from(settings).get() and call console.error (or the module's
logger) with a clear message and the error object to ensure errors are surfaced
for debugging.


export function setUserId(id: string | null): void {
userId = id;
}
Expand All @@ -29,6 +41,7 @@ export function track(
properties?: Record<string, unknown>,
): void {
if (!userId) return;
if (!isTelemetryEnabled()) return;

const client = getClient();
if (!client) return;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useEffect } from "react";
import { electronTrpc } from "renderer/lib/electron-trpc";
import { posthog } from "renderer/lib/posthog";

export function TelemetrySync() {
const { data: telemetryEnabled } =
electronTrpc.settings.getTelemetryEnabled.useQuery();

useEffect(() => {
if (telemetryEnabled === undefined) return;

try {
if (telemetryEnabled) {
if (typeof posthog?.opt_in_capturing === "function") {
posthog.opt_in_capturing();
}
} else {
if (typeof posthog?.opt_out_capturing === "function") {
posthog.opt_out_capturing();
}
}
} catch (error) {
console.error(
"[telemetry-sync] Failed to update telemetry state:",
error,
);
}
}, [telemetryEnabled]);

return null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { TelemetrySync } from "./TelemetrySync";
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ export function BehaviorSettings({ visibleItems }: BehaviorSettingsProps) {
SETTING_ITEM_ID.BEHAVIOR_BRANCH_PREFIX,
visibleItems,
);
const showTelemetry = isItemVisible(
SETTING_ITEM_ID.BEHAVIOR_TELEMETRY,
visibleItems,
);

const utils = electronTrpc.useUtils();

Expand All @@ -58,6 +62,35 @@ export function BehaviorSettings({ visibleItems }: BehaviorSettingsProps) {
setConfirmOnQuit.mutate({ enabled });
};

const { data: telemetryEnabled, isLoading: isTelemetryLoading } =
electronTrpc.settings.getTelemetryEnabled.useQuery();
const setTelemetryEnabled =
electronTrpc.settings.setTelemetryEnabled.useMutation({
onMutate: async ({ enabled }) => {
await utils.settings.getTelemetryEnabled.cancel();
const previous = utils.settings.getTelemetryEnabled.getData();
utils.settings.getTelemetryEnabled.setData(undefined, enabled);
return { previous };
},
onError: (err, _vars, context) => {
console.error("[settings/telemetry] Failed to update:", err);
if (context?.previous !== undefined) {
utils.settings.getTelemetryEnabled.setData(
undefined,
context.previous,
);
}
},
onSettled: () => {
utils.settings.getTelemetryEnabled.invalidate();
},
});

const handleTelemetryToggle = (enabled: boolean) => {
console.log("[settings/telemetry] Toggling to:", enabled);
setTelemetryEnabled.mutate({ enabled });
};

const { data: branchPrefix, isLoading: isBranchPrefixLoading } =
electronTrpc.settings.getBranchPrefix.useQuery();
const { data: gitInfo } = electronTrpc.settings.getGitInfo.useQuery();
Expand Down Expand Up @@ -187,6 +220,25 @@ export function BehaviorSettings({ visibleItems }: BehaviorSettingsProps) {
</div>
</div>
)}

{showTelemetry && (
<div className="flex items-center justify-between">
<div className="space-y-0.5">
<Label htmlFor="telemetry" className="text-sm font-medium">
Send anonymous usage data
</Label>
<p className="text-xs text-muted-foreground">
Help improve Superset by sending anonymous usage data
</p>
</div>
<Switch
id="telemetry"
checked={telemetryEnabled ?? true}
onCheckedChange={handleTelemetryToggle}
disabled={isTelemetryLoading || setTelemetryEnabled.isPending}
/>
</div>
)}
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const SETTING_ITEM_ID = {

BEHAVIOR_CONFIRM_QUIT: "behavior-confirm-quit",
BEHAVIOR_BRANCH_PREFIX: "behavior-branch-prefix",
BEHAVIOR_TELEMETRY: "behavior-telemetry",

TERMINAL_PRESETS: "terminal-presets",
TERMINAL_QUICK_ADD: "terminal-quick-add",
Expand Down Expand Up @@ -326,6 +327,24 @@ export const SETTINGS_ITEMS: SettingsItem[] = [
"custom",
],
},
{
id: SETTING_ITEM_ID.BEHAVIOR_TELEMETRY,
section: "behavior",
title: "Send anonymous usage data",
description: "Help improve Superset by sending anonymous usage data",
keywords: [
"telemetry",
"analytics",
"tracking",
"privacy",
"data",
"usage",
"anonymous",
"metrics",
"opt out",
"disable",
],
},
{
id: SETTING_ITEM_ID.TERMINAL_PRESETS,
section: "terminal",
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop/src/renderer/routes/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Alerter } from "@superset/ui/atoms/Alert";
import type { ReactNode } from "react";
import { PostHogUserIdentifier } from "renderer/components/PostHogUserIdentifier";
import { TelemetrySync } from "renderer/components/TelemetrySync";
import { ThemedToaster } from "renderer/components/ThemedToaster";
import { AuthProvider } from "renderer/providers/AuthProvider";
import { ElectronTRPCProvider } from "renderer/providers/ElectronTRPCProvider";
Expand All @@ -12,6 +13,7 @@ export function RootLayout({ children }: { children: ReactNode }) {
<PostHogProvider>
<ElectronTRPCProvider>
<PostHogUserIdentifier />
<TelemetrySync />
<AuthProvider>
<MonacoProvider>
{children}
Expand Down
1 change: 1 addition & 0 deletions apps/desktop/src/shared/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export const DEFAULT_CONFIRM_ON_QUIT = true;
export const DEFAULT_TERMINAL_LINK_BEHAVIOR = "external-editor" as const;
export const DEFAULT_TERMINAL_PERSISTENCE = true;
export const DEFAULT_AUTO_APPLY_DEFAULT_PRESET = true;
export const DEFAULT_TELEMETRY_ENABLED = true;

// External links (documentation, help resources, etc.)
export const EXTERNAL_LINKS = {
Expand Down
1 change: 1 addition & 0 deletions packages/local-db/drizzle/0016_add_telemetry_enabled.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE `settings` ADD `telemetry_enabled` integer;
Loading
Loading