mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-25 00:36:31 +02:00
Add PostHog analytics to desktop main process
This commit is contained in:
parent
e85c355592
commit
8566b03c91
7 changed files with 75 additions and 1 deletions
2
.github/workflows/desktop-release.yml
vendored
2
.github/workflows/desktop-release.yml
vendored
|
|
@ -71,6 +71,8 @@ jobs:
|
|||
working-directory: surfsense_desktop
|
||||
env:
|
||||
HOSTED_FRONTEND_URL: ${{ vars.HOSTED_FRONTEND_URL }}
|
||||
POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }}
|
||||
POSTHOG_HOST: ${{ vars.POSTHOG_HOST }}
|
||||
|
||||
- name: Package & Publish
|
||||
run: pnpm exec electron-builder ${{ matrix.platform }} --config electron-builder.yml --publish always -c.extraMetadata.version=${{ steps.version.outputs.VERSION }}
|
||||
|
|
|
|||
|
|
@ -4,3 +4,7 @@
|
|||
# The hosted web frontend URL. Used to intercept OAuth redirects and keep them
|
||||
# inside the desktop app. Set to your production frontend domain.
|
||||
HOSTED_FRONTEND_URL=https://surfsense.net
|
||||
|
||||
# PostHog analytics (leave empty to disable)
|
||||
POSTHOG_KEY=
|
||||
POSTHOG_HOST=https://us.i.posthog.com
|
||||
|
|
|
|||
|
|
@ -111,6 +111,12 @@ async function buildElectron() {
|
|||
'process.env.HOSTED_FRONTEND_URL': JSON.stringify(
|
||||
process.env.HOSTED_FRONTEND_URL || desktopEnv.HOSTED_FRONTEND_URL || 'https://surfsense.net'
|
||||
),
|
||||
'process.env.POSTHOG_KEY': JSON.stringify(
|
||||
process.env.POSTHOG_KEY || desktopEnv.POSTHOG_KEY || ''
|
||||
),
|
||||
'process.env.POSTHOG_HOST': JSON.stringify(
|
||||
process.env.POSTHOG_HOST || desktopEnv.POSTHOG_HOST || 'https://us.i.posthog.com'
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { registerAutocomplete, unregisterAutocomplete } from './modules/autocomp
|
|||
import { registerFolderWatcher, unregisterFolderWatcher } from './modules/folder-watcher';
|
||||
import { registerIpcHandlers } from './ipc/handlers';
|
||||
import { createTray, destroyTray } from './modules/tray';
|
||||
import { initAnalytics, shutdownAnalytics, trackEvent } from './modules/analytics';
|
||||
|
||||
registerGlobalErrorHandlers();
|
||||
|
||||
|
|
@ -22,6 +23,8 @@ if (!setupDeepLinks()) {
|
|||
registerIpcHandlers();
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
initAnalytics();
|
||||
trackEvent('desktop_app_launched');
|
||||
setupMenu();
|
||||
try {
|
||||
await startNextServer();
|
||||
|
|
@ -70,9 +73,15 @@ app.on('before-quit', () => {
|
|||
isQuitting = true;
|
||||
});
|
||||
|
||||
app.on('will-quit', () => {
|
||||
let didCleanup = false;
|
||||
app.on('will-quit', async (e) => {
|
||||
if (didCleanup) return;
|
||||
didCleanup = true;
|
||||
e.preventDefault();
|
||||
unregisterQuickAsk();
|
||||
unregisterAutocomplete();
|
||||
unregisterFolderWatcher();
|
||||
destroyTray();
|
||||
await shutdownAnalytics();
|
||||
app.exit();
|
||||
});
|
||||
|
|
|
|||
46
surfsense_desktop/src/modules/analytics.ts
Normal file
46
surfsense_desktop/src/modules/analytics.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import { PostHog } from 'posthog-node';
|
||||
import { machineIdSync } from 'node-machine-id';
|
||||
import { app } from 'electron';
|
||||
|
||||
let client: PostHog | null = null;
|
||||
let distinctId = '';
|
||||
|
||||
export function initAnalytics(): void {
|
||||
const key = process.env.POSTHOG_KEY;
|
||||
if (!key) return;
|
||||
|
||||
try {
|
||||
distinctId = machineIdSync(true);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
client = new PostHog(key, {
|
||||
host: process.env.POSTHOG_HOST || 'https://us.i.posthog.com',
|
||||
flushAt: 20,
|
||||
flushInterval: 10000,
|
||||
});
|
||||
}
|
||||
|
||||
export function trackEvent(event: string, properties?: Record<string, unknown>): void {
|
||||
if (!client) return;
|
||||
|
||||
client.capture({
|
||||
distinctId,
|
||||
event,
|
||||
properties: {
|
||||
platform: 'desktop',
|
||||
app_version: app.getVersion(),
|
||||
os: process.platform,
|
||||
...properties,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function shutdownAnalytics(): Promise<void> {
|
||||
if (!client) return;
|
||||
|
||||
const timeout = new Promise<void>((resolve) => setTimeout(resolve, 3000));
|
||||
await Promise.race([client.shutdown(), timeout]);
|
||||
client = null;
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import { captureScreen } from './screenshot';
|
|||
import { createSuggestionWindow, destroySuggestion, getSuggestionWindow } from './suggestion-window';
|
||||
import { getShortcuts } from '../shortcuts';
|
||||
import { getActiveSearchSpaceId } from '../active-search-space';
|
||||
import { trackEvent } from '../analytics';
|
||||
|
||||
let currentShortcut = '';
|
||||
let autocompleteEnabled = true;
|
||||
|
|
@ -41,6 +42,7 @@ async function triggerAutocomplete(): Promise<void> {
|
|||
console.warn('[autocomplete] No active search space. Select a search space first.');
|
||||
return;
|
||||
}
|
||||
trackEvent('desktop_autocomplete_triggered', { search_space_id: searchSpaceId });
|
||||
const cursor = screen.getCursorScreenPoint();
|
||||
const win = createSuggestionWindow(cursor.x, cursor.y);
|
||||
|
||||
|
|
@ -87,9 +89,11 @@ function registerIpcHandlers(): void {
|
|||
ipcRegistered = true;
|
||||
|
||||
ipcMain.handle(IPC_CHANNELS.ACCEPT_SUGGESTION, async (_event, text: string) => {
|
||||
trackEvent('desktop_autocomplete_accepted');
|
||||
await acceptAndInject(text);
|
||||
});
|
||||
ipcMain.handle(IPC_CHANNELS.DISMISS_SUGGESTION, () => {
|
||||
trackEvent('desktop_autocomplete_dismissed');
|
||||
destroySuggestion();
|
||||
});
|
||||
ipcMain.handle(IPC_CHANNELS.SET_AUTOCOMPLETE_ENABLED, (_event, enabled: boolean) => {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { checkAccessibilityPermission, getFrontmostApp, simulateCopy, simulatePa
|
|||
import { getServerPort } from './server';
|
||||
import { getShortcuts } from './shortcuts';
|
||||
import { getActiveSearchSpaceId } from './active-search-space';
|
||||
import { trackEvent } from './analytics';
|
||||
|
||||
let currentShortcut = '';
|
||||
let quickAskWindow: BrowserWindow | null = null;
|
||||
|
|
@ -120,6 +121,7 @@ async function quickAskHandler(): Promise<void> {
|
|||
|
||||
sourceApp = getFrontmostApp();
|
||||
console.log('[quick-ask] Source app:', sourceApp, '| Opening Quick Assist with', text.length, 'chars', selected ? '(selected)' : text ? '(clipboard fallback)' : '(empty)');
|
||||
trackEvent('desktop_quick_ask_opened', { has_selected_text: !!selected });
|
||||
openQuickAsk(text);
|
||||
}
|
||||
|
||||
|
|
@ -151,6 +153,7 @@ function registerIpcHandlers(): void {
|
|||
|
||||
if (!checkAccessibilityPermission()) return;
|
||||
|
||||
trackEvent('desktop_quick_ask_replaced');
|
||||
clipboard.writeText(text);
|
||||
destroyQuickAsk();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue