diff --git a/frontend/src/AppRoutes/index.tsx b/frontend/src/AppRoutes/index.tsx index a2330d1aeb..9367ed1624 100644 --- a/frontend/src/AppRoutes/index.tsx +++ b/frontend/src/AppRoutes/index.tsx @@ -22,7 +22,8 @@ import { Dispatch } from 'redux'; import { AppState } from 'store/reducers'; import AppActions from 'types/actions'; 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 PrivateRoute from './Private'; @@ -32,7 +33,7 @@ function App(): JSX.Element { const themeConfig = useThemeConfig(); const { data } = useLicense(); const [routes, setRoutes] = useState(defaultRoutes); - const { role, isLoggedIn: isLoggedInState, user } = useSelector< + const { role, isLoggedIn: isLoggedInState, user, org } = useSelector< AppState, AppReducer >((state) => state.app); @@ -41,6 +42,8 @@ function App(): JSX.Element { const { hostname, pathname } = window.location; + const isCloudUserVal = isCloudUser(); + const featureResponse = useGetFeatureFlag((allFlags) => { const isOnboardingEnabled = allFlags.find((flag) => flag.name === FeatureKeys.ONBOARDING)?.active || @@ -58,10 +61,7 @@ function App(): JSX.Element { }, }); - if ( - !isOnboardingEnabled || - !(hostname && hostname.endsWith('signoz.cloud')) - ) { + if (!isOnboardingEnabled || !isCloudUserVal) { const newRoutes = routes.filter( (route) => route?.path !== ROUTES.GET_STARTED, ); @@ -86,6 +86,35 @@ function App(): JSX.Element { license.isCurrent && license.planKey === LICENSE_PLAN_KEY.BASIC_PLAN, ) || 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(() => { const isIdentifiedUser = getLocalStorageApi(LOCALSTORAGE.IS_IDENTIFIED_USER); @@ -98,12 +127,9 @@ function App(): JSX.Element { ) { setLocalStorageApi(LOCALSTORAGE.IS_IDENTIFIED_USER, 'true'); - window.analytics.identify(user?.email, { - email: user?.email, - name: user?.name, - }); - - window.clarity('identify', user.email, user.name); + if (isCloudUserVal) { + enableAnalytics(user); + } } if (isOnBasicPlan || (isLoggedInState && role && role !== 'ADMIN')) { diff --git a/frontend/src/container/BillingContainer/BillingContainer.tsx b/frontend/src/container/BillingContainer/BillingContainer.tsx index aa674e780a..f47af4ac0a 100644 --- a/frontend/src/container/BillingContainer/BillingContainer.tsx +++ b/frontend/src/container/BillingContainer/BillingContainer.tsx @@ -176,24 +176,26 @@ export default function BillingContainer(): JSX.Element { } = data?.payload || {}; const formattedUsageData: any[] = []; - for (let index = 0; index < breakdown.length; index += 1) { - const element = breakdown[index]; + if (breakdown && Array.isArray(breakdown)) { + for (let index = 0; index < breakdown.length; index += 1) { + const element = breakdown[index]; - element?.tiers.forEach( - ( - tier: { quantity: number; unitPrice: number; tierCost: number }, - i: number, - ) => { - formattedUsageData.push({ - key: `${index}${i}`, - name: i === 0 ? element?.type : '', - unit: element?.unit, - dataIngested: tier.quantity, - pricePerUnit: tier.unitPrice, - cost: `$ ${tier.tierCost}`, - }); - }, - ); + element?.tiers.forEach( + ( + tier: { quantity: number; unitPrice: number; tierCost: number }, + i: number, + ) => { + formattedUsageData.push({ + key: `${index}${i}`, + name: i === 0 ? element?.type : '', + unit: element?.unit, + dataIngested: tier.quantity, + pricePerUnit: tier.unitPrice, + cost: `$ ${tier.tierCost}`, + }); + }, + ); + } } setData(formattedUsageData); diff --git a/frontend/src/container/IngestionSettings/IngestionSettings.tsx b/frontend/src/container/IngestionSettings/IngestionSettings.tsx index 0971ecc960..354ce155ff 100644 --- a/frontend/src/container/IngestionSettings/IngestionSettings.tsx +++ b/frontend/src/container/IngestionSettings/IngestionSettings.tsx @@ -1,6 +1,6 @@ import './IngestionSettings.styles.scss'; -import { Table, Typography } from 'antd'; +import { Skeleton, Table, Typography } from 'antd'; import type { ColumnsType } from 'antd/es/table'; import getIngestionData from 'api/settings/getIngestionData'; import { useQuery } from 'react-query'; @@ -12,7 +12,7 @@ import AppReducer from 'types/reducer/app'; export default function IngestionSettings(): JSX.Element { const { user } = useSelector((state) => state.app); - const { data: ingestionData } = useQuery({ + const { data: ingestionData, isFetching } = useQuery({ queryFn: getIngestionData, queryKey: ['getIngestionData', user?.userId], }); @@ -25,11 +25,19 @@ export default function IngestionSettings(): JSX.Element { render: (text): JSX.Element => {text} , }, { - title: 'Value', + title: '', dataIndex: 'value', key: 'value', render: (text): JSX.Element => ( - {text} +
+ {isFetching ? ( + + ) : ( + + {text} + + )} +
), }, ]; diff --git a/frontend/src/container/SideNav/SideNav.tsx b/frontend/src/container/SideNav/SideNav.tsx index 85ca6295ee..e0d32f8606 100644 --- a/frontend/src/container/SideNav/SideNav.tsx +++ b/frontend/src/container/SideNav/SideNav.tsx @@ -13,6 +13,7 @@ import { useLocation } from 'react-router-dom'; import { sideBarCollapse } from 'store/actions/app'; import { AppState } from 'store/reducers'; import AppReducer from 'types/reducer/app'; +import { isCloudUser } from 'utils/app'; import { routeConfig, styles } from './config'; import { getQueryString } from './helper'; @@ -50,8 +51,6 @@ function SideNav(): JSX.Element { license.isCurrent && license.planKey === LICENSE_PLAN_KEY.BASIC_PLAN, ) || data?.payload?.licenses === null; - const { hostname } = window.location; - const menuItems = useMemo( () => defaultMenuItems.filter((item) => { @@ -64,16 +63,13 @@ function SideNav(): JSX.Element { return item.key !== ROUTES.BILLING; } - if ( - !isOnboardingEnabled || - !(hostname && hostname.endsWith('signoz.cloud')) - ) { + if (!isOnboardingEnabled || !isCloudUser()) { return item.key !== ROUTES.GET_STARTED; } return true; }), - [featureResponse.data, isOnBasicPlan, hostname, role], + [featureResponse.data, isOnBasicPlan, role], ); const { pathname, search } = useLocation(); diff --git a/frontend/src/pages/Settings/config.ts b/frontend/src/pages/Settings/config.ts index a24a3a5097..26fb1805fa 100644 --- a/frontend/src/pages/Settings/config.ts +++ b/frontend/src/pages/Settings/config.ts @@ -19,6 +19,9 @@ export const commonRoutes = (t: TFunction): RouteTabProps['routes'] => [ route: ROUTES.ALL_CHANNELS, key: ROUTES.ALL_CHANNELS, }, +]; + +export const ingestionSettings = (t: TFunction): RouteTabProps['routes'] => [ { Component: IngestionSettings, name: t('routes:ingestion_settings').toString(), diff --git a/frontend/src/pages/Settings/utils.ts b/frontend/src/pages/Settings/utils.ts index 8c965b0040..862ee0adb9 100644 --- a/frontend/src/pages/Settings/utils.ts +++ b/frontend/src/pages/Settings/utils.ts @@ -1,7 +1,12 @@ import { RouteTabProps } from 'components/RouteTab/types'; import { TFunction } from 'i18next'; +import { isCloudUser } from 'utils/app'; -import { commonRoutes, organizationSettings } from './config'; +import { + commonRoutes, + ingestionSettings, + organizationSettings, +} from './config'; export const getRoutes = ( isCurrentOrgSettings: boolean, @@ -13,5 +18,9 @@ export const getRoutes = ( common = [...common, ...organizationSettings(t)]; } + if (isCloudUser()) { + common = [...common, ...ingestionSettings(t)]; + } + return common; }; diff --git a/frontend/src/pages/SignUp/SignUp.tsx b/frontend/src/pages/SignUp/SignUp.tsx index 910ff91b63..4a5a3e8cc6 100644 --- a/frontend/src/pages/SignUp/SignUp.tsx +++ b/frontend/src/pages/SignUp/SignUp.tsx @@ -17,6 +17,7 @@ import { useLocation } from 'react-router-dom'; import { SuccessResponse } from 'types/api'; import { PayloadProps } from 'types/api/user/getUser'; import { PayloadProps as LoginPrecheckPayloadProps } from 'types/api/user/loginPrecheck'; +import { isCloudUser } from 'utils/app'; import { trackEvent } from 'utils/segmentAnalytics'; import { @@ -233,8 +234,6 @@ function SignUp({ version }: SignUpProps): JSX.Element { const handleSubmit = (): void => { (async (): Promise => { - const { hostname } = window.location; - try { const values = form.getFieldsValue(); setLoading(true); @@ -260,11 +259,7 @@ function SignUp({ version }: SignUpProps): JSX.Element { await commonHandler( values, async (): Promise => { - if ( - isOnboardingEnabled && - hostname && - hostname.endsWith('signoz.cloud') - ) { + if (isOnboardingEnabled && isCloudUser()) { history.push(ROUTES.GET_STARTED); } else { history.push(ROUTES.APPLICATION); diff --git a/frontend/src/utils/app.ts b/frontend/src/utils/app.ts index 890fd64602..b87212ea69 100644 --- a/frontend/src/utils/app.ts +++ b/frontend/src/utils/app.ts @@ -3,3 +3,17 @@ import { SKIP_ONBOARDING } from 'constants/onboarding'; export const isOnboardingSkipped = (): boolean => 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'); +};