Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(desktop): add umami #5346

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -91,6 +92,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 @@ -208,13 +208,16 @@ export const _enterpriseRealNameAuthCancelRequest = (request: AxiosInstance) =>

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);
4 changes: 2 additions & 2 deletions frontend/desktop/src/pages/_document.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
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';

export default function Document() {
return (
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
Loading