diff --git a/.github/workflows/template-build-linux-x64.yml b/.github/workflows/template-build-linux-x64.yml index c6d1eac97d..08cb1dadaf 100644 --- a/.github/workflows/template-build-linux-x64.yml +++ b/.github/workflows/template-build-linux-x64.yml @@ -98,8 +98,8 @@ jobs: make build-and-publish env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ANALYTICS_ID: ${{ secrets.JAN_APP_POSTHOG_PROJECT_API_KEY }} - ANALYTICS_HOST: ${{ secrets.JAN_APP_POSTHOG_URL }} + ANALYTICS_ID: ${{ secrets.JAN_APP_UMAMI_PROJECT_API_KEY }} + ANALYTICS_HOST: ${{ secrets.JAN_APP_UMAMI_URL }} - name: Upload Artifact .deb file if: inputs.public_provider != 'github' diff --git a/.github/workflows/template-build-macos.yml b/.github/workflows/template-build-macos.yml index bc48e6c212..0ad1d3a6a0 100644 --- a/.github/workflows/template-build-macos.yml +++ b/.github/workflows/template-build-macos.yml @@ -137,8 +137,8 @@ jobs: APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} APP_PATH: "." DEVELOPER_ID: ${{ secrets.DEVELOPER_ID }} - ANALYTICS_ID: ${{ secrets.JAN_APP_POSTHOG_PROJECT_API_KEY }} - ANALYTICS_HOST: ${{ secrets.JAN_APP_POSTHOG_URL }} + ANALYTICS_ID: ${{ secrets.JAN_APP_UMAMI_PROJECT_API_KEY }} + ANALYTICS_HOST: ${{ secrets.JAN_APP_UMAMI_URL }} - name: Upload Artifact if: inputs.public_provider != 'github' diff --git a/.github/workflows/template-build-windows-x64.yml b/.github/workflows/template-build-windows-x64.yml index 5d96b3f499..b81997bde2 100644 --- a/.github/workflows/template-build-windows-x64.yml +++ b/.github/workflows/template-build-windows-x64.yml @@ -127,8 +127,8 @@ jobs: make build-and-publish env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ANALYTICS_ID: ${{ secrets.JAN_APP_POSTHOG_PROJECT_API_KEY }} - ANALYTICS_HOST: ${{ secrets.JAN_APP_POSTHOG_URL }} + ANALYTICS_ID: ${{ secrets.JAN_APP_UMAMI_PROJECT_API_KEY }} + ANALYTICS_HOST: ${{ secrets.JAN_APP_UMAMI_URL }} AZURE_KEY_VAULT_URI: ${{ secrets.AZURE_KEY_VAULT_URI }} AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} diff --git a/docs/.env.example b/docs/.env.example index 6755f2520e..b4a7fa5f1f 100644 --- a/docs/.env.example +++ b/docs/.env.example @@ -1,5 +1,5 @@ GTM_ID=xxxx -POSTHOG_PROJECT_API_KEY=xxxx -POSTHOG_APP_URL=xxxx +UMAMI_PROJECT_API_KEY=xxxx +UMAMI_APP_URL=xxxx ALGOLIA_API_KEY=xxxx ALGOLIA_APP_ID=xxxx \ No newline at end of file diff --git a/electron/tests/hub.e2e.spec.ts b/electron/tests/hub.e2e.spec.ts index 6bfe45ac47..cc72e037ea 100644 --- a/electron/tests/hub.e2e.spec.ts +++ b/electron/tests/hub.e2e.spec.ts @@ -38,7 +38,6 @@ test.afterAll(async () => { }) test('explores hub', async () => { - // Set the timeout for this test to 60 seconds test.setTimeout(TIMEOUT) await page.getByTestId('Hub').first().click({ timeout: TIMEOUT, diff --git a/electron/tests/navigation.e2e.spec.ts b/electron/tests/navigation.e2e.spec.ts index 2066fa60a1..5c8721c2fa 100644 --- a/electron/tests/navigation.e2e.spec.ts +++ b/electron/tests/navigation.e2e.spec.ts @@ -38,6 +38,7 @@ test.afterAll(async () => { }) test('renders left navigation panel', async () => { + test.setTimeout(TIMEOUT) const systemMonitorBtn = await page .getByTestId('System Monitor') .first() @@ -50,8 +51,11 @@ test('renders left navigation panel', async () => { .isEnabled({ timeout: TIMEOUT }) expect([systemMonitorBtn, settingsBtn].filter((e) => !e).length).toBe(0) // Chat section should be there - const apiServer = await page.getByTestId('Local API Server').first() - expect(apiServer).toBeVisible({ + await page.getByTestId('Local API Server').first().click({ + timeout: TIMEOUT, + }) + const localServer = await page.getByTestId('local-server-testid').first() + await expect(localServer).toBeVisible({ timeout: TIMEOUT, }) }) diff --git a/electron/tests/settings.e2e.spec.ts b/electron/tests/settings.e2e.spec.ts index 765c3cba7d..ad2d7b4a49 100644 --- a/electron/tests/settings.e2e.spec.ts +++ b/electron/tests/settings.e2e.spec.ts @@ -38,7 +38,8 @@ test.afterAll(async () => { }) test('shows settings', async () => { + test.setTimeout(TIMEOUT) await page.getByTestId('Settings').first().click({ timeout: TIMEOUT }) const settingDescription = page.getByTestId('testid-setting-description') - expect(settingDescription).toBeVisible({ timeout: TIMEOUT }) + await expect(settingDescription).toBeVisible({ timeout: TIMEOUT }) }) diff --git a/web/containers/Providers/index.tsx b/web/containers/Providers/index.tsx index dd9069a95b..895c22177f 100644 --- a/web/containers/Providers/index.tsx +++ b/web/containers/Providers/index.tsx @@ -6,8 +6,6 @@ import { Toaster } from 'react-hot-toast' import { TooltipProvider } from '@janhq/uikit' -import { PostHogProvider } from 'posthog-js/react' - import GPUDriverPrompt from '@/containers/GPUDriverPromptModal' import EventListenerWrapper from '@/containers/Providers/EventListener' import JotaiWrapper from '@/containers/Providers/Jotai' @@ -21,7 +19,7 @@ import { setupBaseExtensions, } from '@/services/extensionService' -import { instance } from '@/utils/posthog' +import Umami from '@/utils/umami' import KeyListener from './KeyListener' @@ -70,25 +68,22 @@ const Providers = (props: PropsWithChildren) => { }, [setupCore]) return ( - - - - {setupCore && activated && ( - - - - - {children} - - {!isMac && } - - - - - )} - - - + + + + {setupCore && activated && ( + + + + {children} + {!isMac && } + + + + + )} + + ) } diff --git a/web/next.config.js b/web/next.config.js index 0b6a8bc92d..a2e202c515 100644 --- a/web/next.config.js +++ b/web/next.config.js @@ -25,10 +25,8 @@ const nextConfig = { ...config.plugins, new webpack.DefinePlugin({ VERSION: JSON.stringify(packageJson.version), - ANALYTICS_ID: - JSON.stringify(process.env.ANALYTICS_ID) ?? JSON.stringify('xxx'), - ANALYTICS_HOST: - JSON.stringify(process.env.ANALYTICS_HOST) ?? JSON.stringify('xxx'), + ANALYTICS_ID: JSON.stringify(process.env.ANALYTICS_ID), + ANALYTICS_HOST: JSON.stringify(process.env.ANALYTICS_HOST), API_BASE_URL: JSON.stringify('http://localhost:1337'), isMac: process.platform === 'darwin', isWindows: process.platform === 'win32', diff --git a/web/screens/LocalServer/index.tsx b/web/screens/LocalServer/index.tsx index e7f3c7fc20..b96f4c228f 100644 --- a/web/screens/LocalServer/index.tsx +++ b/web/screens/LocalServer/index.tsx @@ -103,7 +103,7 @@ const LocalServerScreen = () => { }, [handleChangePort, port]) return ( -
+
{/* Left SideBar */}
diff --git a/web/utils/posthog.ts b/web/utils/posthog.ts deleted file mode 100644 index 9bcbaa8ce2..0000000000 --- a/web/utils/posthog.ts +++ /dev/null @@ -1,50 +0,0 @@ -import posthog, { Properties } from 'posthog-js' - -// Initialize PostHog -posthog.init(ANALYTICS_ID, { - api_host: ANALYTICS_HOST, - autocapture: false, - capture_pageview: false, - capture_pageleave: false, - rageclick: false, -}) -// Export the PostHog instance -export const instance = posthog - -// Enum for Analytics Events -export enum AnalyticsEvent { - Ping = 'Ping', -} - -// Function to determine the operating system -function getOperatingSystem(): string { - if (isMac) return 'MacOS' - if (isWindows) return 'Windows' - if (isLinux) return 'Linux' - return 'Unknown' -} - -function captureAppVersionAndOS() { - const properties: Properties = { - $appVersion: VERSION, - $userOperatingSystem: getOperatingSystem(), - // Set the following Posthog default properties to empty strings - $initial_browser: '', - $browser: '', - $initial_browser_version: '', - $browser_version: '', - $initial_current_url: '', - $current_url: '', - $initial_device_type: '', - $device_type: '', - $initial_pathname: '', - $pathname: '', - $initial_referrer: '', - $referrer: '', - $initial_referring_domain: '', - $referring_domain: '', - } - posthog.capture(AnalyticsEvent.Ping, properties) -} - -captureAppVersionAndOS() diff --git a/web/utils/umami.tsx b/web/utils/umami.tsx new file mode 100644 index 0000000000..ac9e703049 --- /dev/null +++ b/web/utils/umami.tsx @@ -0,0 +1,65 @@ +import { useEffect } from 'react' + +import Script from 'next/script' + +// Define the type for the umami data object +interface UmamiData { + version: string +} + +declare global { + interface Window { + umami: + | { + track: (event: string, data?: UmamiData) => void + } + | undefined + } +} + +const Umami = () => { + const appVersion = VERSION + const analyticsHost = ANALYTICS_HOST + const analyticsId = ANALYTICS_ID + + useEffect(() => { + if (!appVersion || !analyticsHost || !analyticsId) return + const ping = () => { + // Check if umami is defined before ping + if (window.umami !== null && typeof window.umami !== 'undefined') { + window.umami.track(appVersion, { + version: appVersion, + }) + } + } + + // Wait for umami to be defined before ping + if (window.umami !== null && typeof window.umami !== 'undefined') { + ping() + } else { + // Listen for umami script load event + document.addEventListener('umami:loaded', ping) + } + + // Cleanup function to remove event listener if the component unmounts + return () => { + document.removeEventListener('umami:loaded', ping) + } + }, [appVersion, analyticsHost, analyticsId]) + + return ( + <> + {appVersion && analyticsHost && analyticsId && ( +