Skip to content

Commit

Permalink
feat(desktop): add umami
Browse files Browse the repository at this point in the history
feat(destkop):add umami
  • Loading branch information
xudaotutou committed Jan 20, 2025
1 parent 60a8ff6 commit 5c9fff2
Show file tree
Hide file tree
Showing 17 changed files with 204 additions and 60 deletions.
2 changes: 2 additions & 0 deletions frontend/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@sealos/driver": "workspace:^",
"@sealos/ui": "workspace:^",
"@tanstack/react-query": "^4.35.3",
"@umami/node": "^0.4.0",
"axios": "^1.5.1",
"clsx": "^1.2.1",
"cors": "^2.8.5",
Expand Down Expand Up @@ -93,6 +94,7 @@
"@types/nprogress": "^0.2.1",
"@types/react": "18.2.37",
"@types/react-dom": "18.0.11",
"@types/umami-browser": "^2.3.2",
"@types/uuid": "^9.0.4",
"dotenv-cli": "^7.3.0",
"jest": "^29.7.0",
Expand Down
5 changes: 4 additions & 1 deletion frontend/desktop/src/api/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,13 +186,16 @@ export const _enterpriseRealNameAuthRequest = (request: AxiosInstance) => (data:

export const _getAmount = (request: AxiosInstance) => () =>
request<never, ApiResp<{ balance: number; deductionBalance: number }>>('/api/account/getAmount');

export const _verifyToken = (request: AxiosInstance) => () =>
request<never, ApiResp<null>>('/api/auth/verify');
export const passwordExistRequest = _passwordExistRequest(request);
export const passwordLoginRequest = _passwordLoginRequest(request, (token) => {
useSessionStore.setState({ token });
});

export const passwordModifyRequest = _passwordModifyRequest(request);
export const UserInfo = _UserInfo(request);
export const verifyToken = _verifyToken(request);
export const regionList = _regionList(request);

export const getSmsBindCodeRequest = _getSmsBindCodeRequest(request);
Expand Down
4 changes: 1 addition & 3 deletions frontend/desktop/src/components/team/WorkspaceToggle.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { nsListRequest, switchRequest } from '@/api/namespace';
import NsListItem from '@/components/team/NsListItem';
import TeamCenter from '@/components/team/TeamCenter';
import useAppStore from '@/stores/app';
import useSessionStore from '@/stores/session';
import { NSType } from '@/types/team';
import { AccessTokenPayload } from '@/types/token';
Expand All @@ -16,13 +15,12 @@ import { CubeIcon, DesktopExchangeIcon } from '../icons';

export default function WorkspaceToggle() {
const disclosure = useDisclosure();
const { setWorkSpaceId, session } = useSessionStore();
const { session } = useSessionStore();
const { t } = useTranslation();
const user = session?.user;
const ns_uid = user?.ns_uid || '';
const router = useRouter();
const queryClient = useQueryClient();
const { init } = useAppStore();
const mutation = useMutation({
mutationFn: switchRequest,
async onSuccess(data) {
Expand Down
5 changes: 5 additions & 0 deletions frontend/desktop/src/constants/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@ export const LicenseFrontendKey = 'cloud.sealos.io/license-frontend';
export const templateDeployKey = 'cloud.sealos.io/deploy-on-sealos';

export const userSystemNamespace = 'user-system' as const;

export enum trackEventName {
'dailyLoginFirst' = 'dailyLoginFirst',
'signUp' = 'signUp'
}
1 change: 1 addition & 0 deletions frontend/desktop/src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,5 @@ const App = ({ Component, pageProps }: AppProps) => {
</QueryClientProvider>
);
};

export default appWithTranslation(App);
10 changes: 8 additions & 2 deletions frontend/desktop/src/pages/_document.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Head, Html, Main, NextScript } from 'next/document';
import { ColorModeScript } from '@chakra-ui/react';
import { theme } from '@/styles/chakraTheme';
import { ColorModeScript } from '@chakra-ui/react';
import { Head, Html, Main, NextScript } from 'next/document';
import Script from 'next/script';

export default function Document() {
return (
Expand Down Expand Up @@ -28,6 +29,11 @@ export default function Document() {
<ColorModeScript initialColorMode={theme.config.initialColorMode} />
<Main />
<NextScript />
<Script
defer
src="https://umami-damoxzso.sealoshzh.site/script.js"
data-website-id="f76f351f-9fc7-40db-84d8-500a673436bb"
/>
</body>
</Html>
);
Expand Down
36 changes: 22 additions & 14 deletions frontend/desktop/src/pages/api/platform/getAppConfig.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import { getAuthClientConfig } from '@/pages/api/platform/getAuthConfig';
import { getCloudConfig } from '@/pages/api/platform/getCloudConfig';
import { getLayoutConfig } from '@/pages/api/platform/getLayoutConfig';
import {
commitTransactionjob,
finishTransactionJob,
runTransactionjob
} from '@/services/backend/cronjob';
import { jsonRes } from '@/services/backend/response';
import type { NextApiRequest, NextApiResponse } from 'next';
import {
AppClientConfigType,
AuthClientConfigType,
CloudConfigType,
CommonClientConfigType,
DefaultAppClientConfig,
LayoutConfigType
LayoutConfigType,
TrackingConfigType
} from '@/types/system';
import { getCloudConfig } from '@/pages/api/platform/getCloudConfig';
import { getAuthClientConfig } from '@/pages/api/platform/getAuthConfig';
import { getLayoutConfig } from '@/pages/api/platform/getLayoutConfig';
import { getCommonClientConfig } from './getCommonConfig';
import { Cron } from 'croner';
import {
commitTransactionjob,
finishTransactionJob,
runTransactionjob
} from '@/services/backend/cronjob';
import type { NextApiRequest, NextApiResponse } from 'next';
import { getCommonClientConfig } from './getCommonConfig';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const config = await getAppConfig();
Expand All @@ -31,15 +32,17 @@ function genResConfig(
cloudConf: CloudConfigType,
authConf: AuthClientConfigType,
commonConf: CommonClientConfigType,
layoutConf: LayoutConfigType
layoutConf: LayoutConfigType,
tracking: Required<TrackingConfigType>
): AppClientConfigType {
return {
cloud: cloudConf,
common: commonConf,
desktop: {
auth: authConf,
layout: layoutConf
}
},
tracking: tracking
};
}

Expand All @@ -49,7 +52,12 @@ export async function getAppConfig(): Promise<AppClientConfigType> {
const authConf = await getAuthClientConfig();
const commonConf = await getCommonClientConfig();
const layoutConf = await getLayoutConfig();
const conf = genResConfig(cloudConf, authConf, commonConf, layoutConf);
const _tracking = global.AppConfig.tracking;
const tracking: Required<TrackingConfigType> = {
websiteId: _tracking.websiteId || '',
hostUrl: _tracking.hostUrl || ''
};
const conf = genResConfig(cloudConf, authConf, commonConf, layoutConf, tracking);
if (!global.commitCroner) {
// console.log('init commit croner');
global.commitCroner = new Cron('* * * * * *', commitTransactionjob, {
Expand Down
3 changes: 2 additions & 1 deletion frontend/desktop/src/pages/api/platform/getCommonConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
DefaultCommonClientConfig
} from '@/types/system';
import { readFileSync } from 'fs';
import type { NextApiRequest, NextApiResponse } from 'next';
import yaml from 'js-yaml';
import type { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const config = await getCommonClientConfig();
Expand All @@ -18,6 +18,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
}
function genResCommonClientConfig(common: CommonConfigType): CommonClientConfigType {
return {
trackingEnabled: !!common.trackingEnabled,
enterpriseRealNameAuthEnabled: !!common.enterpriseRealNameAuthEnabled,
realNameAuthEnabled: !!common.realNameAuthEnabled,
realNameReward: common.realNameReward || 0,
Expand Down
36 changes: 33 additions & 3 deletions frontend/desktop/src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { nsListRequest, switchRequest } from '@/api/namespace';
import DesktopContent from '@/components/desktop_content';
import { trackEventName } from '@/constants/account';
import useAppStore from '@/stores/app';
import useCallbackStore from '@/stores/callback';
import { useConfigStore } from '@/stores/config';
Expand All @@ -14,6 +15,7 @@ import { switchKubeconfigNamespace } from '@/utils/switchKubeconfigNamespace';
import { compareFirstLanguages } from '@/utils/tools';
import { Box, useColorMode } from '@chakra-ui/react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import dayjs from 'dayjs';
import { jwtDecode } from 'jwt-decode';
import { isString } from 'lodash';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
Expand All @@ -32,13 +34,13 @@ export const MoreAppsContext = createContext<IMoreAppsContext | null>(null);

export default function Home({ sealos_cloud_domain }: { sealos_cloud_domain: string }) {
const router = useRouter();
const { isUserLogin } = useSessionStore();
const { firstUse, setFirstUse, isUserLogin } = useSessionStore();
const { colorMode, toggleColorMode } = useColorMode();
const init = useAppStore((state) => state.init);
const setAutoLaunch = useAppStore((state) => state.setAutoLaunch);
const { autolaunchWorkspaceUid } = useAppStore();
const { session } = useSessionStore();
const { layoutConfig } = useConfigStore();
const { layoutConfig, commonConfig, trackingConfig } = useConfigStore();
const { workspaceInviteCode, setWorkspaceInviteCode } = useCallbackStore();
const { setCanShowGuide } = useDesktopConfigStore();

Expand Down Expand Up @@ -78,6 +80,9 @@ export default function Home({ sealos_cloud_domain }: { sealos_cloud_domain: str
const is_login = isUserLogin();
const whitelistApps = ['system-template', 'system-fastdeploy'];
if (!is_login) {
// clear firstusetime
setFirstUse(null);

const { appkey, appQuery } = parseOpenappQuery((query?.openapp as string) || '');
// Invited new user
if (query?.uid && typeof query?.uid === 'string') {
Expand All @@ -95,6 +100,7 @@ export default function Home({ sealos_cloud_domain }: { sealos_cloud_domain: str
if (isString(query?.workspaceUid)) workspaceUid = query.workspaceUid;
if (appkey && typeof appQuery === 'string')
setAutoLaunch(appkey, { raw: appQuery }, workspaceUid);

router.replace(destination);
} else {
let workspaceUid: string | undefined;
Expand Down Expand Up @@ -205,7 +211,31 @@ export default function Home({ sealos_cloud_domain }: { sealos_cloud_domain: str
return;
}
}, [workspaceInviteCode]);

useEffect(() => {
(async (state) => {
try {
if (
commonConfig?.trackingEnabled &&
(!firstUse || !dayjs(firstUse).isSame(dayjs(), 'day'))
) {
const umami = window.umami;
if (!!umami) {
const result = await umami.track(trackEventName.dailyLoginFirst, {
userId: session?.user.userId!,
userUid: session?.user.userUid!
});
if (result.ok && result.status === 200) {
setFirstUse(new Date());
} else {
console.error('Failed to update first use date');
}
}
}
} catch (e) {
console.log(e);
}
})();
}, [commonConfig, firstUse]);
return (
<Box position={'relative'} overflow={'hidden'} w="100vw" h="100vh">
<Head>
Expand Down
64 changes: 40 additions & 24 deletions frontend/desktop/src/services/backend/globalAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {
User,
UserStatus
} from 'prisma/global/generated/client';
import { enableSignUp } from '../enable';
import { enableSignUp, enableTracking } from '../enable';
import { trackSignUp } from './tracking';

type TransactionClient = Omit<
PrismaClient,
Expand Down Expand Up @@ -254,7 +255,6 @@ export async function signUpByPassword({

return { user };
});

return result;
} catch (error) {
console.error('globalAuth: Error during sign up:', error);
Expand Down Expand Up @@ -329,13 +329,21 @@ export const getGlobalToken = async ({
password,
semData
});
result && (user = result.user);
if (inviterId && result) {
inviteHandler({
inviterId: inviterId,
inviteeId: result?.user.name,
signResult: result
});
if (!!result) {
user = result.user;
if (inviterId && result) {
inviteHandler({
inviterId: inviterId,
inviteeId: result?.user.name,
signResult: result
});
}
if (enableTracking()) {
await trackSignUp({
userId: result.user.id,
userUid: result.user.uid
});
}
}
} else {
const result = await signInByPassword({
Expand All @@ -356,22 +364,30 @@ export const getGlobalToken = async ({
avatar_url,
semData
});
result && (user = result.user);
if (inviterId && result) {
inviteHandler({
inviterId: inviterId,
inviteeId: result?.user.name,
signResult: result
});
}
if (bdVid && result) {
uploadConvertData({ newType: [3], bdVid })
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
if (result) {
user = result.user;
if (inviterId) {
inviteHandler({
inviterId: inviterId,
inviteeId: result?.user.name,
signResult: result
});
}
if (bdVid) {
await uploadConvertData({ newType: [3], bdVid })
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
}
if (enableTracking()) {
await trackSignUp({
userId: result.user.id,
userUid: result.user.uid
});
}
}
} else {
const result = await signIn({
Expand Down
34 changes: 34 additions & 0 deletions frontend/desktop/src/services/backend/tracking/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { trackEventName } from '@/constants/account';
import { Umami } from '@umami/node';
const getUmami = () => {
return new Umami({
websiteId: global.AppConfig.tracking.websiteId,
hostUrl: global.AppConfig.tracking.hostUrl
});
};
export type TLoginPayload = {
userUid: string;
userId: string;
};
export const trackSignUp = (data: TLoginPayload) => {
console.log('signUpstart');
const umami = getUmami();
console.log('umami', umami);
return umami
.track(trackEventName.signUp, data)
.then((res) => {
console.log('[tracking][signUp][success]');
})
.catch((e) => {
console.error('[tracking][signUp]:', e);
return Promise.resolve(null);
});
};
export const trackDailyLoginFirst = (data: TLoginPayload) => {
const umami = getUmami();
console;
return umami.track(trackEventName.dailyLoginFirst, data).catch((e) => {
console.error('[tracking][dailyLoginFirst]:', e);
return Promise.resolve(null);
});
};
1 change: 1 addition & 0 deletions frontend/desktop/src/services/enable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const getBillingUrl = () => global.AppConfig.desktop.auth.billingUrl || '
export const getWorkorderUrl = () => global.AppConfig.desktop.auth.workorderUrl || '';
export const getCvmUrl = () => global.AppConfig.desktop.auth.cloudVitrualMachineUrl || '';
export const getTeamLimit = () => global.AppConfig.desktop.teamManagement?.maxTeamCount || 50;
export const enableTracking = () => !!global.AppConfig.common.trackingEnabled;
export const getTeamInviteLimit = () =>
global.AppConfig.desktop.teamManagement?.maxTeamMemberCount || 50;

Expand Down
Loading

0 comments on commit 5c9fff2

Please sign in to comment.