feat: add analytics group call (#3757)

* feat: add analytics group call

* feat: add safety check for billing breakdown variable
This commit is contained in:
Yunus M 2023-10-17 16:54:37 +05:30 committed by GitHub
parent 377dbd8aec
commit f7fe64a8df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 101 additions and 48 deletions

View File

@ -22,7 +22,8 @@ import { Dispatch } from 'redux';
import { AppState } from 'store/reducers'; import { AppState } from 'store/reducers';
import AppActions from 'types/actions'; import AppActions from 'types/actions';
import { UPDATE_FEATURE_FLAG_RESPONSE } from 'types/actions/app'; import { UPDATE_FEATURE_FLAG_RESPONSE } from 'types/actions/app';
import AppReducer from 'types/reducer/app'; import AppReducer, { User } from 'types/reducer/app';
import { extractDomain, isCloudUser } from 'utils/app';
import { trackPageView } from 'utils/segmentAnalytics'; import { trackPageView } from 'utils/segmentAnalytics';
import PrivateRoute from './Private'; import PrivateRoute from './Private';
@ -32,7 +33,7 @@ function App(): JSX.Element {
const themeConfig = useThemeConfig(); const themeConfig = useThemeConfig();
const { data } = useLicense(); const { data } = useLicense();
const [routes, setRoutes] = useState(defaultRoutes); const [routes, setRoutes] = useState(defaultRoutes);
const { role, isLoggedIn: isLoggedInState, user } = useSelector< const { role, isLoggedIn: isLoggedInState, user, org } = useSelector<
AppState, AppState,
AppReducer AppReducer
>((state) => state.app); >((state) => state.app);
@ -41,6 +42,8 @@ function App(): JSX.Element {
const { hostname, pathname } = window.location; const { hostname, pathname } = window.location;
const isCloudUserVal = isCloudUser();
const featureResponse = useGetFeatureFlag((allFlags) => { const featureResponse = useGetFeatureFlag((allFlags) => {
const isOnboardingEnabled = const isOnboardingEnabled =
allFlags.find((flag) => flag.name === FeatureKeys.ONBOARDING)?.active || allFlags.find((flag) => flag.name === FeatureKeys.ONBOARDING)?.active ||
@ -58,10 +61,7 @@ function App(): JSX.Element {
}, },
}); });
if ( if (!isOnboardingEnabled || !isCloudUserVal) {
!isOnboardingEnabled ||
!(hostname && hostname.endsWith('signoz.cloud'))
) {
const newRoutes = routes.filter( const newRoutes = routes.filter(
(route) => route?.path !== ROUTES.GET_STARTED, (route) => route?.path !== ROUTES.GET_STARTED,
); );
@ -86,6 +86,35 @@ function App(): JSX.Element {
license.isCurrent && license.planKey === LICENSE_PLAN_KEY.BASIC_PLAN, license.isCurrent && license.planKey === LICENSE_PLAN_KEY.BASIC_PLAN,
) || data?.payload?.licenses === null; ) || data?.payload?.licenses === null;
const enableAnalytics = (user: User): void => {
const orgName =
org && Array.isArray(org) && org.length > 0 ? org[0].name : '';
const identifyPayload = {
email: user?.email,
name: user?.name,
company_name: orgName,
role,
};
const domain = extractDomain(user?.email);
const hostNameParts = hostname.split('.');
const groupTraits = {
name: orgName,
tenant_id: hostNameParts[0],
data_region: hostNameParts[1],
tenant_url: hostname,
company_domain: domain,
};
window.analytics.identify(user?.email, identifyPayload);
window.analytics.group(domain, groupTraits);
window.clarity('identify', user.email, user.name);
};
useEffect(() => { useEffect(() => {
const isIdentifiedUser = getLocalStorageApi(LOCALSTORAGE.IS_IDENTIFIED_USER); const isIdentifiedUser = getLocalStorageApi(LOCALSTORAGE.IS_IDENTIFIED_USER);
@ -98,12 +127,9 @@ function App(): JSX.Element {
) { ) {
setLocalStorageApi(LOCALSTORAGE.IS_IDENTIFIED_USER, 'true'); setLocalStorageApi(LOCALSTORAGE.IS_IDENTIFIED_USER, 'true');
window.analytics.identify(user?.email, { if (isCloudUserVal) {
email: user?.email, enableAnalytics(user);
name: user?.name, }
});
window.clarity('identify', user.email, user.name);
} }
if (isOnBasicPlan || (isLoggedInState && role && role !== 'ADMIN')) { if (isOnBasicPlan || (isLoggedInState && role && role !== 'ADMIN')) {

View File

@ -176,6 +176,7 @@ export default function BillingContainer(): JSX.Element {
} = data?.payload || {}; } = data?.payload || {};
const formattedUsageData: any[] = []; const formattedUsageData: any[] = [];
if (breakdown && Array.isArray(breakdown)) {
for (let index = 0; index < breakdown.length; index += 1) { for (let index = 0; index < breakdown.length; index += 1) {
const element = breakdown[index]; const element = breakdown[index];
@ -195,6 +196,7 @@ export default function BillingContainer(): JSX.Element {
}, },
); );
} }
}
setData(formattedUsageData); setData(formattedUsageData);
setTotalBillAmount(total); setTotalBillAmount(total);

View File

@ -1,6 +1,6 @@
import './IngestionSettings.styles.scss'; import './IngestionSettings.styles.scss';
import { Table, Typography } from 'antd'; import { Skeleton, Table, Typography } from 'antd';
import type { ColumnsType } from 'antd/es/table'; import type { ColumnsType } from 'antd/es/table';
import getIngestionData from 'api/settings/getIngestionData'; import getIngestionData from 'api/settings/getIngestionData';
import { useQuery } from 'react-query'; import { useQuery } from 'react-query';
@ -12,7 +12,7 @@ import AppReducer from 'types/reducer/app';
export default function IngestionSettings(): JSX.Element { export default function IngestionSettings(): JSX.Element {
const { user } = useSelector<AppState, AppReducer>((state) => state.app); const { user } = useSelector<AppState, AppReducer>((state) => state.app);
const { data: ingestionData } = useQuery({ const { data: ingestionData, isFetching } = useQuery({
queryFn: getIngestionData, queryFn: getIngestionData,
queryKey: ['getIngestionData', user?.userId], queryKey: ['getIngestionData', user?.userId],
}); });
@ -25,11 +25,19 @@ export default function IngestionSettings(): JSX.Element {
render: (text): JSX.Element => <Typography.Text> {text} </Typography.Text>, render: (text): JSX.Element => <Typography.Text> {text} </Typography.Text>,
}, },
{ {
title: 'Value', title: '',
dataIndex: 'value', dataIndex: 'value',
key: 'value', key: 'value',
render: (text): JSX.Element => ( render: (text): JSX.Element => (
<Typography.Text copyable>{text}</Typography.Text> <div>
{isFetching ? (
<Skeleton.Input active style={{ height: 20 }} />
) : (
<Typography.Text copyable={!isFetching && text !== ''}>
{text}
</Typography.Text>
)}
</div>
), ),
}, },
]; ];

View File

@ -13,6 +13,7 @@ import { useLocation } from 'react-router-dom';
import { sideBarCollapse } from 'store/actions/app'; import { sideBarCollapse } from 'store/actions/app';
import { AppState } from 'store/reducers'; import { AppState } from 'store/reducers';
import AppReducer from 'types/reducer/app'; import AppReducer from 'types/reducer/app';
import { isCloudUser } from 'utils/app';
import { routeConfig, styles } from './config'; import { routeConfig, styles } from './config';
import { getQueryString } from './helper'; import { getQueryString } from './helper';
@ -50,8 +51,6 @@ function SideNav(): JSX.Element {
license.isCurrent && license.planKey === LICENSE_PLAN_KEY.BASIC_PLAN, license.isCurrent && license.planKey === LICENSE_PLAN_KEY.BASIC_PLAN,
) || data?.payload?.licenses === null; ) || data?.payload?.licenses === null;
const { hostname } = window.location;
const menuItems = useMemo( const menuItems = useMemo(
() => () =>
defaultMenuItems.filter((item) => { defaultMenuItems.filter((item) => {
@ -64,16 +63,13 @@ function SideNav(): JSX.Element {
return item.key !== ROUTES.BILLING; return item.key !== ROUTES.BILLING;
} }
if ( if (!isOnboardingEnabled || !isCloudUser()) {
!isOnboardingEnabled ||
!(hostname && hostname.endsWith('signoz.cloud'))
) {
return item.key !== ROUTES.GET_STARTED; return item.key !== ROUTES.GET_STARTED;
} }
return true; return true;
}), }),
[featureResponse.data, isOnBasicPlan, hostname, role], [featureResponse.data, isOnBasicPlan, role],
); );
const { pathname, search } = useLocation(); const { pathname, search } = useLocation();

View File

@ -19,6 +19,9 @@ export const commonRoutes = (t: TFunction): RouteTabProps['routes'] => [
route: ROUTES.ALL_CHANNELS, route: ROUTES.ALL_CHANNELS,
key: ROUTES.ALL_CHANNELS, key: ROUTES.ALL_CHANNELS,
}, },
];
export const ingestionSettings = (t: TFunction): RouteTabProps['routes'] => [
{ {
Component: IngestionSettings, Component: IngestionSettings,
name: t('routes:ingestion_settings').toString(), name: t('routes:ingestion_settings').toString(),

View File

@ -1,7 +1,12 @@
import { RouteTabProps } from 'components/RouteTab/types'; import { RouteTabProps } from 'components/RouteTab/types';
import { TFunction } from 'i18next'; import { TFunction } from 'i18next';
import { isCloudUser } from 'utils/app';
import { commonRoutes, organizationSettings } from './config'; import {
commonRoutes,
ingestionSettings,
organizationSettings,
} from './config';
export const getRoutes = ( export const getRoutes = (
isCurrentOrgSettings: boolean, isCurrentOrgSettings: boolean,
@ -13,5 +18,9 @@ export const getRoutes = (
common = [...common, ...organizationSettings(t)]; common = [...common, ...organizationSettings(t)];
} }
if (isCloudUser()) {
common = [...common, ...ingestionSettings(t)];
}
return common; return common;
}; };

View File

@ -17,6 +17,7 @@ import { useLocation } from 'react-router-dom';
import { SuccessResponse } from 'types/api'; import { SuccessResponse } from 'types/api';
import { PayloadProps } from 'types/api/user/getUser'; import { PayloadProps } from 'types/api/user/getUser';
import { PayloadProps as LoginPrecheckPayloadProps } from 'types/api/user/loginPrecheck'; import { PayloadProps as LoginPrecheckPayloadProps } from 'types/api/user/loginPrecheck';
import { isCloudUser } from 'utils/app';
import { trackEvent } from 'utils/segmentAnalytics'; import { trackEvent } from 'utils/segmentAnalytics';
import { import {
@ -233,8 +234,6 @@ function SignUp({ version }: SignUpProps): JSX.Element {
const handleSubmit = (): void => { const handleSubmit = (): void => {
(async (): Promise<void> => { (async (): Promise<void> => {
const { hostname } = window.location;
try { try {
const values = form.getFieldsValue(); const values = form.getFieldsValue();
setLoading(true); setLoading(true);
@ -260,11 +259,7 @@ function SignUp({ version }: SignUpProps): JSX.Element {
await commonHandler( await commonHandler(
values, values,
async (): Promise<void> => { async (): Promise<void> => {
if ( if (isOnboardingEnabled && isCloudUser()) {
isOnboardingEnabled &&
hostname &&
hostname.endsWith('signoz.cloud')
) {
history.push(ROUTES.GET_STARTED); history.push(ROUTES.GET_STARTED);
} else { } else {
history.push(ROUTES.APPLICATION); history.push(ROUTES.APPLICATION);

View File

@ -3,3 +3,17 @@ import { SKIP_ONBOARDING } from 'constants/onboarding';
export const isOnboardingSkipped = (): boolean => export const isOnboardingSkipped = (): boolean =>
getLocalStorage(SKIP_ONBOARDING) === 'true'; getLocalStorage(SKIP_ONBOARDING) === 'true';
export function extractDomain(email: string): string {
const emailParts = email.split('@');
if (emailParts.length !== 2) {
return email;
}
return emailParts[1];
}
export const isCloudUser = (): boolean => {
const { hostname } = window.location;
return hostname?.endsWith('signoz.cloud');
};