diff --git a/frontend/src/AppRoutes/index.tsx b/frontend/src/AppRoutes/index.tsx index d4278803bf..c588f28a45 100644 --- a/frontend/src/AppRoutes/index.tsx +++ b/frontend/src/AppRoutes/index.tsx @@ -1,3 +1,4 @@ +import * as Sentry from '@sentry/react'; import { ConfigProvider } from 'antd'; import getLocalStorageApi from 'api/browser/localstorage/get'; import setLocalStorageApi from 'api/browser/localstorage/set'; @@ -15,6 +16,7 @@ import { LICENSE_PLAN_KEY } from 'hooks/useLicense'; import { NotificationProvider } from 'hooks/useNotifications'; import { ResourceProvider } from 'hooks/useResourceAttribute'; import history from 'lib/history'; +import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback'; import posthog from 'posthog-js'; import AlertRuleProvider from 'providers/Alert'; import { useAppContext } from 'providers/App/App'; @@ -46,7 +48,6 @@ function App(): JSX.Element { activeLicenseV3, isFetchingActiveLicenseV3, userFetchError, - licensesFetchError, featureFlagsFetchError, isLoggedIn: isLoggedInState, featureFlags, @@ -56,10 +57,7 @@ function App(): JSX.Element { const { hostname, pathname } = window.location; - const { - isCloudUser: isCloudUserVal, - isEECloudUser: isEECloudUserVal, - } = useGetTenantLicense(); + const { isCloudUser, isEnterpriseSelfHostedUser } = useGetTenantLicense(); const enableAnalytics = useCallback( (user: IUser): void => { @@ -169,7 +167,7 @@ function App(): JSX.Element { let updatedRoutes = defaultRoutes; // if the user is a cloud user - if (isCloudUserVal || isEECloudUserVal) { + if (isCloudUser || isEnterpriseSelfHostedUser) { // if the user is on basic plan then remove billing if (isOnBasicPlan) { updatedRoutes = updatedRoutes.filter( @@ -191,10 +189,10 @@ function App(): JSX.Element { isLoggedInState, user, licenses, - isCloudUserVal, + isCloudUser, + isEnterpriseSelfHostedUser, isFetchingLicenses, isFetchingUser, - isEECloudUserVal, ]); useEffect(() => { @@ -209,6 +207,7 @@ function App(): JSX.Element { } }, [pathname]); + // eslint-disable-next-line sonarjs/cognitive-complexity useEffect(() => { // feature flag shouldn't be loading and featureFlags or fetchError any one of this should be true indicating that req is complete // licenses should also be present. there is no check for licenses for loading and error as that is mandatory if not present then routing @@ -234,7 +233,12 @@ function App(): JSX.Element { const showAddCreditCardModal = !isPremiumSupportEnabled && !trialInfo?.trialConvertedToSubscription; - if (isLoggedInState && isChatSupportEnabled && !showAddCreditCardModal) { + if ( + isLoggedInState && + isChatSupportEnabled && + !showAddCreditCardModal && + (isCloudUser || isEnterpriseSelfHostedUser) + ) { window.Intercom('boot', { app_id: process.env.INTERCOM_APP_ID, email: user?.email || '', @@ -253,13 +257,53 @@ function App(): JSX.Element { licenses, activeLicenseV3, trialInfo, + isCloudUser, + isEnterpriseSelfHostedUser, ]); useEffect(() => { - if (!isFetchingUser && isCloudUserVal && user && user.email) { + if (!isFetchingUser && isCloudUser && user && user.email) { enableAnalytics(user); } - }, [user, isFetchingUser, isCloudUserVal, enableAnalytics]); + }, [user, isFetchingUser, isCloudUser, enableAnalytics]); + + useEffect(() => { + if (isCloudUser || isEnterpriseSelfHostedUser) { + if (process.env.POSTHOG_KEY) { + posthog.init(process.env.POSTHOG_KEY, { + api_host: 'https://us.i.posthog.com', + person_profiles: 'identified_only', // or 'always' to create profiles for anonymous users as well + }); + } + + Sentry.init({ + dsn: process.env.SENTRY_DSN, + tunnel: process.env.TUNNEL_URL, + environment: 'production', + integrations: [ + Sentry.browserTracingIntegration(), + Sentry.replayIntegration({ + maskAllText: false, + blockAllMedia: false, + }), + ], + // Performance Monitoring + tracesSampleRate: 1.0, // Capture 100% of the transactions + // Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled + tracePropagationTargets: [], + // Session Replay + replaysSessionSampleRate: 0.1, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production. + replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur. + }); + } else { + posthog.reset(); + Sentry.close(); + + if (window.cioanalytics && typeof window.cioanalytics.reset === 'function') { + window.cioanalytics.reset(); + } + } + }, [isCloudUser, isEnterpriseSelfHostedUser]); // if the user is in logged in state if (isLoggedInState) { @@ -271,61 +315,55 @@ function App(): JSX.Element { // if the required calls fails then return a something went wrong error // this needs to be on top of data missing error because if there is an error, data will never be loaded and it will // move to indefinitive loading - if ( - (userFetchError || licensesFetchError) && - pathname !== ROUTES.SOMETHING_WENT_WRONG - ) { + if (userFetchError && pathname !== ROUTES.SOMETHING_WENT_WRONG) { history.replace(ROUTES.SOMETHING_WENT_WRONG); } // if all of the data is not set then return a spinner, this is required because there is some gap between loading states and data setting - if ( - (!licenses || !user.email || !featureFlags) && - !userFetchError && - !licensesFetchError - ) { + if ((!licenses || !user.email || !featureFlags) && !userFetchError) { return ; } } return ( - - - - - - - - - - - - }> - - {routes.map(({ path, component, exact }) => ( - - ))} - - - - - - - - - - - - - - - - + }> + + + + + + + + + + + + }> + + {routes.map(({ path, component, exact }) => ( + + ))} + + + + + + + + + + + + + + + + ); } diff --git a/frontend/src/container/CustomDomainSettings/CustomDomainSettings.tsx b/frontend/src/container/CustomDomainSettings/CustomDomainSettings.tsx index cf8f67de57..a4aec25c61 100644 --- a/frontend/src/container/CustomDomainSettings/CustomDomainSettings.tsx +++ b/frontend/src/container/CustomDomainSettings/CustomDomainSettings.tsx @@ -61,7 +61,7 @@ export default function CustomDomainSettings(): JSX.Element { isLoading: isLoadingDeploymentsData, isFetching: isFetchingDeploymentsData, refetch: refetchDeploymentsData, - } = useGetDeploymentsData(); + } = useGetDeploymentsData(true); const { mutate: updateSubDomain, diff --git a/frontend/src/container/Home/DataSourceInfo/DataSourceInfo.tsx b/frontend/src/container/Home/DataSourceInfo/DataSourceInfo.tsx index 115bc85946..82a94f4c75 100644 --- a/frontend/src/container/Home/DataSourceInfo/DataSourceInfo.tsx +++ b/frontend/src/container/Home/DataSourceInfo/DataSourceInfo.tsx @@ -23,10 +23,13 @@ function DataSourceInfo({ const notSendingData = !dataSentToSigNoz; + const isEnabled = + activeLicenseV3 && activeLicenseV3.platform === LicensePlatform.CLOUD; + const { data: deploymentsData, isError: isErrorDeploymentsData, - } = useGetDeploymentsData(); + } = useGetDeploymentsData(isEnabled || false); const [region, setRegion] = useState(''); const [url, setUrl] = useState(''); diff --git a/frontend/src/container/IngestionSettings/MultiIngestionSettings.tsx b/frontend/src/container/IngestionSettings/MultiIngestionSettings.tsx index a01d890a3d..9df261f1da 100644 --- a/frontend/src/container/IngestionSettings/MultiIngestionSettings.tsx +++ b/frontend/src/container/IngestionSettings/MultiIngestionSettings.tsx @@ -293,7 +293,7 @@ function MultiIngestionSettings(): JSX.Element { isLoading: isLoadingDeploymentsData, isFetching: isFetchingDeploymentsData, isError: isErrorDeploymentsData, - } = useGetDeploymentsData(); + } = useGetDeploymentsData(true); const { mutate: createIngestionKey, diff --git a/frontend/src/container/OnboardingV2Container/IngestionDetails/IngestionDetails.tsx b/frontend/src/container/OnboardingV2Container/IngestionDetails/IngestionDetails.tsx index 35a854a320..0866211043 100644 --- a/frontend/src/container/OnboardingV2Container/IngestionDetails/IngestionDetails.tsx +++ b/frontend/src/container/OnboardingV2Container/IngestionDetails/IngestionDetails.tsx @@ -63,7 +63,7 @@ export default function OnboardingIngestionDetails(): JSX.Element { isLoading: isLoadingDeploymentsData, isFetching: isFetchingDeploymentsData, isError: isDeploymentsDataError, - } = useGetDeploymentsData(); + } = useGetDeploymentsData(true); const handleCopyKey = (text: string): void => { handleCopyToClipboard(text); diff --git a/frontend/src/container/SideNav/SideNav.styles.scss b/frontend/src/container/SideNav/SideNav.styles.scss index 21263ed063..640c296b93 100644 --- a/frontend/src/container/SideNav/SideNav.styles.scss +++ b/frontend/src/container/SideNav/SideNav.styles.scss @@ -69,6 +69,12 @@ opacity: 1; transition: all 0.2s; } + + &.community-enterprise-user { + color: var(--bg-sakura-500); + background: rgba(255, 113, 113, 0.1); + border: 1px solid var(--bg-sakura-500); + } } .dockBtn { diff --git a/frontend/src/container/SideNav/SideNav.tsx b/frontend/src/container/SideNav/SideNav.tsx index 1bb0b8eec8..f8a7261562 100644 --- a/frontend/src/container/SideNav/SideNav.tsx +++ b/frontend/src/container/SideNav/SideNav.tsx @@ -3,7 +3,7 @@ import './SideNav.styles.scss'; import { Color } from '@signozhq/design-tokens'; -import { Button } from 'antd'; +import { Button, Tooltip } from 'antd'; import logEvent from 'api/common/logEvent'; import cx from 'classnames'; import { FeatureKeys } from 'constants/features'; @@ -75,7 +75,7 @@ function SideNav(): JSX.Element { const [userManagementMenuItems, setUserManagementMenuItems] = useState< UserManagementMenuItems[] - >([manageLicenseMenuItem]); + >([]); const onClickSlackHandler = (): void => { window.open('https://signoz.io/slack', '_blank'); @@ -88,8 +88,10 @@ function SideNav(): JSX.Element { const { registerShortcut, deregisterShortcut } = useKeyboardHotkeys(); const { - isCloudUser: isCloudUserVal, - isEECloudUser: isEECloudUserVal, + isCloudUser, + isEnterpriseSelfHostedUser, + isCommunityUser, + isCommunityEnterpriseUser, } = useGetTenantLicense(); const { t } = useTranslation(''); @@ -103,11 +105,6 @@ function SideNav(): JSX.Element { licenseStatus?.toLocaleLowerCase() === LICENSE_PLAN_STATUS.VALID.toLocaleLowerCase(); - const isEnterprise = licenses?.licenses?.some( - (license: License) => - license.isCurrent && license.planKey === LICENSE_PLAN_KEY.ENTERPRISE_PLAN, - ); - const onClickSignozCloud = (): void => { window.open( 'https://signoz.io/oss-to-cloud/?utm_source=product_navbar&utm_medium=frontend&utm_campaign=oss_users', @@ -201,14 +198,21 @@ function SideNav(): JSX.Element { }; useEffect(() => { - if (isCloudUserVal) { + if (isCloudUser) { setLicenseTag('Cloud'); - } else if (isEnterprise) { + } else if (isEnterpriseSelfHostedUser) { setLicenseTag('Enterprise'); - } else { - setLicenseTag('Free'); + } else if (isCommunityEnterpriseUser) { + setLicenseTag('Enterprise'); + } else if (isCommunityUser) { + setLicenseTag('Community'); } - }, [isCloudUserVal, isEnterprise]); + }, [ + isCloudUser, + isEnterpriseSelfHostedUser, + isCommunityEnterpriseUser, + isCommunityUser, + ]); const [isCurrentOrgSettings] = useComponentPermission( ['current_org_settings'], @@ -290,7 +294,7 @@ function SideNav(): JSX.Element { ); } - if (isCloudUserVal || isEECloudUserVal) { + if (isCloudUser || isEnterpriseSelfHostedUser) { const isOnboardingEnabled = featureFlags?.find((feature) => feature.name === FeatureKeys.ONBOARDING) ?.active || false; @@ -317,6 +321,11 @@ function SideNav(): JSX.Element { } updatedUserManagementItems = [helpSupportMenuItem]; + + // Show manage license menu item for EE cloud users with a active license + if (isEnterpriseSelfHostedUser) { + updatedUserManagementItems.push(manageLicenseMenuItem); + } } else { updatedMenuItems = updatedMenuItems.filter( (item) => item.key !== ROUTES.INTEGRATIONS && item.key !== ROUTES.BILLING, @@ -332,20 +341,21 @@ function SideNav(): JSX.Element { onClick: onClickVersionHandler, }; - updatedUserManagementItems = [ - versionMenuItem, - slackSupportMenuItem, - manageLicenseMenuItem, - ]; + updatedUserManagementItems = [versionMenuItem, slackSupportMenuItem]; + + if (isCommunityEnterpriseUser) { + updatedUserManagementItems.push(manageLicenseMenuItem); + } } setMenuItems(updatedMenuItems); setUserManagementMenuItems(updatedUserManagementItems); }, [ + isCommunityEnterpriseUser, currentVersion, featureFlags, - isCloudUserVal, + isCloudUser, + isEnterpriseSelfHostedUser, isCurrentVersionError, - isEECloudUserVal, isLatestVersion, licenses?.licenses, onClickVersionHandler, @@ -372,12 +382,31 @@ function SideNav(): JSX.Element { {licenseTag && ( -
{licenseTag}
+ +
+ {licenseTag} +
+
)} - {isCloudUserVal && user?.role !== USER_ROLES.VIEWER && ( + {isCloudUser && user?.role !== USER_ROLES.VIEWER && (