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 14, 2025
1 parent 60a8ff6 commit c8d3a8d
Show file tree
Hide file tree
Showing 15 changed files with 172 additions and 42 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
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
38 changes: 35 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 } = 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,33 @@ 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 result = await sendFirstUse();
const umami = window?.umami;
console.log('umami!!!', 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);
}
})();
}, []);
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
9 changes: 9 additions & 0 deletions frontend/desktop/src/stores/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ type SessionState = {
token: string;
provider?: OauthProvider;
oauth_state: string;
firstUse: Date | null;
setSession: (ss: Session) => void;
setSessionProp: <T extends keyof Session>(key: T, value: Session[T]) => void;
delSession: () => void;
setFirstUse: (d: Date | null) => void;
isUserLogin: () => boolean;
/*
when proxy oauth2.0 ,the domainState need to be used
Expand All @@ -26,6 +28,7 @@ type SessionState = {
action: string;
statePayload: string[];
};

setProvider: (provider?: OauthProvider) => void;
setToken: (token: string) => void;
lastWorkSpaceId: string;
Expand All @@ -37,9 +40,15 @@ const useSessionStore = create<SessionState>()(
immer((set, get) => ({
session: undefined,
provider: undefined,
firstUse: null,
oauth_state: '',
token: '',
lastWorkSpaceId: '',
setFirstUse(d) {
set({
firstUse: d
});
},
setSession: (ss: Session) => set({ session: ss }),
setSessionProp: (key: keyof Session, value: any) => {
set((state) => {
Expand Down
14 changes: 8 additions & 6 deletions frontend/desktop/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { type MongoClient } from 'mongodb';
import { type AppConfigType } from './system';
import { Umami } from '@umami/node';
import { Cron } from 'croner';
import { type MongoClient } from 'mongodb';
import { Transporter } from 'nodemailer';
import SMTPPool from 'nodemailer/lib/smtp-pool';
import { type AppConfigType } from './system';
export * from './api';
export * from './session';
export * from './app';
export * from './crd';
export * from './license';
export * from './login';
export * from './payment';
export * from './region';
export * from './session';
export * from './system';
export * from './login';
export * from './tools';
export * from './license';
export * from './region';

declare global {
var mongodb: MongoClient | null;
Expand All @@ -23,4 +24,5 @@ declare global {
var WechatAccessToken: string | undefined;
var WechatExpiresIn: number | undefined;
var nodemailer: Transporter<SMTPPool.SentMessageInfo> | undefined;
var umami: Umami | undefined;
}
Loading

0 comments on commit c8d3a8d

Please sign in to comment.