mirror of
https://github.com/ivabus/gui
synced 2025-04-23 14:07:14 +03:00
init mixpanel (#227)
* #217 iinit mixpanel and track installation succes and failure --------- Co-authored-by: neil <neil@neils-MacBook-Pro.local>
This commit is contained in:
parent
cf0a2d1b8a
commit
c61712fd6d
10 changed files with 107 additions and 16 deletions
1
.github/workflows/build-sign-notarize.yml
vendored
1
.github/workflows/build-sign-notarize.yml
vendored
|
@ -88,6 +88,7 @@ jobs:
|
|||
if: startsWith(inputs.platform, 'darwin')
|
||||
run: tea -SE xc dist
|
||||
env:
|
||||
PUBLIC_MIXPANEL_TOKEN: ${{ secrets.MIXPANEL_PROJECT_TOKEN }}
|
||||
DEBUG_BUILD: ${{ inputs.debug }}
|
||||
PUBLIC_VERSION: ${{ steps.gui-version.outputs.version }}
|
||||
USE_HARD_LINKS: false
|
||||
|
|
|
@ -160,7 +160,3 @@ ipcMain.handle("open-terminal", async (_, data) => {
|
|||
console.error("elast:", error);
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle("get-lang", function () {
|
||||
return app.getLocale();
|
||||
});
|
||||
|
|
|
@ -3,6 +3,7 @@ import path from "path";
|
|||
import fs from "fs";
|
||||
import { getTeaPath } from "./tea-dir";
|
||||
import * as v1Client from "./v1-client";
|
||||
import { app } from "electron";
|
||||
|
||||
const sessionFilePath = path.join(getTeaPath(), "tea.xyz/gui/tmp.dat");
|
||||
const sessionFolder = path.join(getTeaPath(), "tea.xyz/gui");
|
||||
|
@ -11,6 +12,7 @@ interface Session {
|
|||
device_id?: string;
|
||||
key?: string;
|
||||
user?: any;
|
||||
locale?: string;
|
||||
}
|
||||
|
||||
export async function initSessionData() {
|
||||
|
@ -21,14 +23,16 @@ export async function initSessionData() {
|
|||
}
|
||||
|
||||
export async function readSessionData(): Promise<Session> {
|
||||
const locale = app.getLocale();
|
||||
try {
|
||||
const sessionBuffer = await fs.readFileSync(sessionFilePath);
|
||||
const session = JSON.parse(sessionBuffer.toString()) as Session;
|
||||
session.locale = locale;
|
||||
return session;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
const req = await v1Client.get<{ deviceId: string }>("/auth/registerDevice");
|
||||
const data = { device_id: req.deviceId };
|
||||
const data = { device_id: req.deviceId, locale };
|
||||
await writeSessionData(data);
|
||||
return data;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,9 @@
|
|||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/svelte": "^3.2.2",
|
||||
"@types/testing-library__jest-dom": "^5.14.5",
|
||||
"@types/bcryptjs": "^2.4.2",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"@types/mixpanel-browser": "^2.38.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.27.0",
|
||||
"@typescript-eslint/parser": "^5.27.0",
|
||||
"autoprefixer": "^10.4.13",
|
||||
|
@ -70,8 +73,6 @@
|
|||
"type": "module",
|
||||
"dependencies": {
|
||||
"@electron/asar": "^3.2.3",
|
||||
"@types/bcryptjs": "^2.4.2",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"@vitest/coverage-c8": "^0.27.1",
|
||||
"axios": "^1.3.2",
|
||||
"bcryptjs": "^2.4.3",
|
||||
|
@ -87,6 +88,7 @@
|
|||
"js-yaml": "^4.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lorem-ipsum": "^2.0.8",
|
||||
"mixpanel-browser": "^2.45.0",
|
||||
"mkdirp": "^2.1.3",
|
||||
"semver": "^7.3.8",
|
||||
"svelte-markdown": "^0.2.3",
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import { onMount } from 'svelte';
|
||||
import { getPackageBottles } from '@native';
|
||||
import { openTerminal } from '@native';
|
||||
import { trackInstall, trackInstallFailed } from '$libs/analytics';
|
||||
|
||||
export let pkg: Package;
|
||||
let bottles: Bottle[] = [];
|
||||
|
@ -20,7 +21,14 @@
|
|||
};
|
||||
|
||||
const onOpenTerminal = () => {
|
||||
openTerminal(`sh <(curl tea.xyz) +${pkg.full_name}`);
|
||||
try {
|
||||
openTerminal(`sh <(curl tea.xyz) +${pkg.full_name}`);
|
||||
trackInstall(pkg.full_name);
|
||||
} catch (error) {
|
||||
let message = 'Unknown Error'
|
||||
if (error instanceof Error) message = error.message
|
||||
trackInstallFailed(pkg.full_name, message || "unknown");
|
||||
}
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import { packagesStore } from '$libs/stores';
|
||||
|
||||
import { installPackage } from '@native';
|
||||
import { trackInstall, trackInstallFailed } from '$libs/analytics';
|
||||
|
||||
export let title = 'Packages';
|
||||
export let category = ''; // filter
|
||||
|
@ -45,9 +46,12 @@
|
|||
try {
|
||||
pkg.state = PackageStates.INSTALLING;
|
||||
await installPackage(pkg.full_name);
|
||||
trackInstall(pkg.full_name);
|
||||
pkg.state = PackageStates.INSTALLED;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
let message = 'Unknown Error'
|
||||
if (error instanceof Error) message = error.message
|
||||
trackInstallFailed(pkg.full_name, message || "unknown");
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
|
65
modules/desktop/src/libs/analytics.ts
Normal file
65
modules/desktop/src/libs/analytics.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
import mixpanel from "mixpanel-browser";
|
||||
import * as pub from "$env/static/public";
|
||||
import { getSession } from "@native";
|
||||
|
||||
type DefaultMixpanelProps = {
|
||||
device_id: string;
|
||||
uid: string;
|
||||
distinct_id: string;
|
||||
locale: string;
|
||||
gui_version: string;
|
||||
};
|
||||
let mixpanelDefaultData: DefaultMixpanelProps;
|
||||
const getLocalSession = async (): Promise<DefaultMixpanelProps> => {
|
||||
if (mixpanelDefaultData) return mixpanelDefaultData;
|
||||
const session = await getSession();
|
||||
mixpanelDefaultData = {
|
||||
device_id: session?.device_id || "unregistered",
|
||||
uid: session?.user?.developer_id || "unauthenticated",
|
||||
distinct_id: session?.device_id || "unregistered",
|
||||
locale: session?.locale || "unknown",
|
||||
gui_version: pub.PUBLIC_VERSION
|
||||
};
|
||||
return mixpanelDefaultData;
|
||||
};
|
||||
|
||||
mixpanel.init(pub.PUBLIC_MIXPANEL_TOKEN, { debug: true });
|
||||
|
||||
enum AnalyticsAction {
|
||||
install = "INSTALL_ACTION",
|
||||
install_failed = "INSTALL_ACTION_FAILED"
|
||||
}
|
||||
|
||||
const trackAction = (action: AnalyticsAction, data?: { [key: string]: any }) => {
|
||||
getLocalSession()
|
||||
.then((props) => {
|
||||
mixpanel.track(action, {
|
||||
...(data || {}),
|
||||
...props
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
// TODO: log remote error stream
|
||||
console.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* save success installation event to mixpanel
|
||||
* @param packageFullname full installation name of the package
|
||||
* @returns void
|
||||
*/
|
||||
export const trackInstall = (packageFullname: string) =>
|
||||
trackAction(AnalyticsAction.install, { pkg: packageFullname });
|
||||
|
||||
/**
|
||||
* save failed installation event to mixpanel
|
||||
* @param packageFullname full installation name of the package
|
||||
* @param error error message
|
||||
*/
|
||||
export const trackInstallFailed = (packageFullname: string, error: string) => {
|
||||
trackAction(AnalyticsAction.install_failed, {
|
||||
pkg: packageFullname,
|
||||
error
|
||||
});
|
||||
};
|
|
@ -5,8 +5,6 @@ import type { Developer } from "@tea/ui/types";
|
|||
import type { Session } from "$libs/types";
|
||||
import { getSession as electronGetSession, updateSession as electronUpdateSession } from "@native";
|
||||
|
||||
const basePath = ".tea/tea.xyz/gui";
|
||||
|
||||
export let session: Session | null = null;
|
||||
export const getSession = async (): Promise<Session | null> => {
|
||||
session = await electronGetSession();
|
||||
|
|
|
@ -47,4 +47,5 @@ export interface Session {
|
|||
device_id?: string;
|
||||
key?: string;
|
||||
user?: Developer;
|
||||
locale?: string;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ importers:
|
|||
'@testing-library/svelte': ^3.2.2
|
||||
'@types/bcryptjs': ^2.4.2
|
||||
'@types/js-yaml': ^4.0.5
|
||||
'@types/mixpanel-browser': ^2.38.1
|
||||
'@types/testing-library__jest-dom': ^5.14.5
|
||||
'@typescript-eslint/eslint-plugin': ^5.27.0
|
||||
'@typescript-eslint/parser': ^5.27.0
|
||||
|
@ -48,6 +49,7 @@ importers:
|
|||
jsdom: ^21.0.0
|
||||
lodash: ^4.17.21
|
||||
lorem-ipsum: ^2.0.8
|
||||
mixpanel-browser: ^2.45.0
|
||||
mkdirp: ^2.1.3
|
||||
postcss: ^8.4.19
|
||||
prettier: ^2.7.1
|
||||
|
@ -70,8 +72,6 @@ importers:
|
|||
yaml: ^2.2.1
|
||||
dependencies:
|
||||
'@electron/asar': 3.2.3
|
||||
'@types/bcryptjs': 2.4.2
|
||||
'@types/js-yaml': 4.0.5
|
||||
'@vitest/coverage-c8': 0.27.1_jsdom@21.0.0
|
||||
axios: 1.3.2
|
||||
bcryptjs: 2.4.3
|
||||
|
@ -87,6 +87,7 @@ importers:
|
|||
js-yaml: 4.1.0
|
||||
lodash: 4.17.21
|
||||
lorem-ipsum: 2.0.8
|
||||
mixpanel-browser: 2.45.0
|
||||
mkdirp: 2.1.3
|
||||
semver: 7.3.8
|
||||
svelte-markdown: 0.2.3_svelte@3.55.1
|
||||
|
@ -105,6 +106,9 @@ importers:
|
|||
'@tea/ui': link:../ui
|
||||
'@testing-library/jest-dom': 5.16.5
|
||||
'@testing-library/svelte': 3.2.2_svelte@3.55.1
|
||||
'@types/bcryptjs': 2.4.2
|
||||
'@types/js-yaml': 4.0.5
|
||||
'@types/mixpanel-browser': 2.38.1
|
||||
'@types/testing-library__jest-dom': 5.14.5
|
||||
'@typescript-eslint/eslint-plugin': 5.43.0_wze2rj5tow7zwqpgbdx2buoy3m
|
||||
'@typescript-eslint/parser': 5.43.0_e3uo4sehh4zr4i6m57mkkxxv7y
|
||||
|
@ -3792,7 +3796,7 @@ packages:
|
|||
peerDependencies:
|
||||
'@sveltejs/kit': ^1.0.0
|
||||
dependencies:
|
||||
'@sveltejs/kit': 1.0.1_svelte@3.55.1+vite@4.1.1
|
||||
'@sveltejs/kit': 1.0.1_svelte@3.55.0+vite@4.1.1
|
||||
import-meta-resolve: 2.2.0
|
||||
dev: true
|
||||
|
||||
|
@ -4079,7 +4083,7 @@ packages:
|
|||
|
||||
/@types/bcryptjs/2.4.2:
|
||||
resolution: {integrity: sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==}
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/@types/body-parser/1.19.2:
|
||||
resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==}
|
||||
|
@ -4209,7 +4213,7 @@ packages:
|
|||
|
||||
/@types/js-yaml/4.0.5:
|
||||
resolution: {integrity: sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==}
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/@types/json-schema/7.0.11:
|
||||
resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
|
||||
|
@ -4250,6 +4254,10 @@ packages:
|
|||
/@types/minimatch/5.1.2:
|
||||
resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==}
|
||||
|
||||
/@types/mixpanel-browser/2.38.1:
|
||||
resolution: {integrity: sha512-XzQbwgiOPsFXUQnjz3vSwcwrvJDbQ35bCiwa/1VXGrHvU1ti9+eqO1GY91DShzkEzKkkEEkxfNshS5dbBZqd7w==}
|
||||
dev: true
|
||||
|
||||
/@types/ms/0.7.31:
|
||||
resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==}
|
||||
dev: true
|
||||
|
@ -9745,6 +9753,10 @@ packages:
|
|||
is-extendable: 1.0.1
|
||||
dev: true
|
||||
|
||||
/mixpanel-browser/2.45.0:
|
||||
resolution: {integrity: sha512-PQ1DaTk68yyYtLA0iejmzPA9iNDhT4uIZpqZjRTw7HWpYfl123fydHb2laKanaKjm8YDmrGGz3+xZ4Q6joogyg==}
|
||||
dev: false
|
||||
|
||||
/mkdirp/0.5.6:
|
||||
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
|
||||
hasBin: true
|
||||
|
|
Loading…
Reference in a new issue