mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-13 04:29:04 +08:00
fix: licenses in community edition & improve messaging (#7456)
Enhance platform to handle cloud, self-hosted, community, and enterprise user types with tailored routing, error handling, and feature access.
This commit is contained in:
parent
07a244f569
commit
597752a4bc
@ -1,3 +1,4 @@
|
|||||||
|
import * as Sentry from '@sentry/react';
|
||||||
import { ConfigProvider } from 'antd';
|
import { ConfigProvider } from 'antd';
|
||||||
import getLocalStorageApi from 'api/browser/localstorage/get';
|
import getLocalStorageApi from 'api/browser/localstorage/get';
|
||||||
import setLocalStorageApi from 'api/browser/localstorage/set';
|
import setLocalStorageApi from 'api/browser/localstorage/set';
|
||||||
@ -15,6 +16,7 @@ import { LICENSE_PLAN_KEY } from 'hooks/useLicense';
|
|||||||
import { NotificationProvider } from 'hooks/useNotifications';
|
import { NotificationProvider } from 'hooks/useNotifications';
|
||||||
import { ResourceProvider } from 'hooks/useResourceAttribute';
|
import { ResourceProvider } from 'hooks/useResourceAttribute';
|
||||||
import history from 'lib/history';
|
import history from 'lib/history';
|
||||||
|
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
|
||||||
import posthog from 'posthog-js';
|
import posthog from 'posthog-js';
|
||||||
import AlertRuleProvider from 'providers/Alert';
|
import AlertRuleProvider from 'providers/Alert';
|
||||||
import { useAppContext } from 'providers/App/App';
|
import { useAppContext } from 'providers/App/App';
|
||||||
@ -46,7 +48,6 @@ function App(): JSX.Element {
|
|||||||
activeLicenseV3,
|
activeLicenseV3,
|
||||||
isFetchingActiveLicenseV3,
|
isFetchingActiveLicenseV3,
|
||||||
userFetchError,
|
userFetchError,
|
||||||
licensesFetchError,
|
|
||||||
featureFlagsFetchError,
|
featureFlagsFetchError,
|
||||||
isLoggedIn: isLoggedInState,
|
isLoggedIn: isLoggedInState,
|
||||||
featureFlags,
|
featureFlags,
|
||||||
@ -56,10 +57,7 @@ function App(): JSX.Element {
|
|||||||
|
|
||||||
const { hostname, pathname } = window.location;
|
const { hostname, pathname } = window.location;
|
||||||
|
|
||||||
const {
|
const { isCloudUser, isEnterpriseSelfHostedUser } = useGetTenantLicense();
|
||||||
isCloudUser: isCloudUserVal,
|
|
||||||
isEECloudUser: isEECloudUserVal,
|
|
||||||
} = useGetTenantLicense();
|
|
||||||
|
|
||||||
const enableAnalytics = useCallback(
|
const enableAnalytics = useCallback(
|
||||||
(user: IUser): void => {
|
(user: IUser): void => {
|
||||||
@ -169,7 +167,7 @@ function App(): JSX.Element {
|
|||||||
|
|
||||||
let updatedRoutes = defaultRoutes;
|
let updatedRoutes = defaultRoutes;
|
||||||
// if the user is a cloud user
|
// if the user is a cloud user
|
||||||
if (isCloudUserVal || isEECloudUserVal) {
|
if (isCloudUser || isEnterpriseSelfHostedUser) {
|
||||||
// if the user is on basic plan then remove billing
|
// if the user is on basic plan then remove billing
|
||||||
if (isOnBasicPlan) {
|
if (isOnBasicPlan) {
|
||||||
updatedRoutes = updatedRoutes.filter(
|
updatedRoutes = updatedRoutes.filter(
|
||||||
@ -191,10 +189,10 @@ function App(): JSX.Element {
|
|||||||
isLoggedInState,
|
isLoggedInState,
|
||||||
user,
|
user,
|
||||||
licenses,
|
licenses,
|
||||||
isCloudUserVal,
|
isCloudUser,
|
||||||
|
isEnterpriseSelfHostedUser,
|
||||||
isFetchingLicenses,
|
isFetchingLicenses,
|
||||||
isFetchingUser,
|
isFetchingUser,
|
||||||
isEECloudUserVal,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -209,6 +207,7 @@ function App(): JSX.Element {
|
|||||||
}
|
}
|
||||||
}, [pathname]);
|
}, [pathname]);
|
||||||
|
|
||||||
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// feature flag shouldn't be loading and featureFlags or fetchError any one of this should be true indicating that req is complete
|
// 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
|
// 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 =
|
const showAddCreditCardModal =
|
||||||
!isPremiumSupportEnabled && !trialInfo?.trialConvertedToSubscription;
|
!isPremiumSupportEnabled && !trialInfo?.trialConvertedToSubscription;
|
||||||
|
|
||||||
if (isLoggedInState && isChatSupportEnabled && !showAddCreditCardModal) {
|
if (
|
||||||
|
isLoggedInState &&
|
||||||
|
isChatSupportEnabled &&
|
||||||
|
!showAddCreditCardModal &&
|
||||||
|
(isCloudUser || isEnterpriseSelfHostedUser)
|
||||||
|
) {
|
||||||
window.Intercom('boot', {
|
window.Intercom('boot', {
|
||||||
app_id: process.env.INTERCOM_APP_ID,
|
app_id: process.env.INTERCOM_APP_ID,
|
||||||
email: user?.email || '',
|
email: user?.email || '',
|
||||||
@ -253,13 +257,53 @@ function App(): JSX.Element {
|
|||||||
licenses,
|
licenses,
|
||||||
activeLicenseV3,
|
activeLicenseV3,
|
||||||
trialInfo,
|
trialInfo,
|
||||||
|
isCloudUser,
|
||||||
|
isEnterpriseSelfHostedUser,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isFetchingUser && isCloudUserVal && user && user.email) {
|
if (!isFetchingUser && isCloudUser && user && user.email) {
|
||||||
enableAnalytics(user);
|
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 the user is in logged in state
|
||||||
if (isLoggedInState) {
|
if (isLoggedInState) {
|
||||||
@ -271,24 +315,18 @@ function App(): JSX.Element {
|
|||||||
// if the required calls fails then return a something went wrong error
|
// 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
|
// 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
|
// move to indefinitive loading
|
||||||
if (
|
if (userFetchError && pathname !== ROUTES.SOMETHING_WENT_WRONG) {
|
||||||
(userFetchError || licensesFetchError) &&
|
|
||||||
pathname !== ROUTES.SOMETHING_WENT_WRONG
|
|
||||||
) {
|
|
||||||
history.replace(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 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 (
|
if ((!licenses || !user.email || !featureFlags) && !userFetchError) {
|
||||||
(!licenses || !user.email || !featureFlags) &&
|
|
||||||
!userFetchError &&
|
|
||||||
!licensesFetchError
|
|
||||||
) {
|
|
||||||
return <Spinner tip="Loading..." />;
|
return <Spinner tip="Loading..." />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<Sentry.ErrorBoundary fallback={<ErrorBoundaryFallback />}>
|
||||||
<ConfigProvider theme={themeConfig}>
|
<ConfigProvider theme={themeConfig}>
|
||||||
<Router history={history}>
|
<Router history={history}>
|
||||||
<CompatRouter>
|
<CompatRouter>
|
||||||
@ -310,7 +348,6 @@ function App(): JSX.Element {
|
|||||||
component={component}
|
component={component}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<Route exact path="/" component={Home} />
|
<Route exact path="/" component={Home} />
|
||||||
<Route path="*" component={NotFound} />
|
<Route path="*" component={NotFound} />
|
||||||
</Switch>
|
</Switch>
|
||||||
@ -326,6 +363,7 @@ function App(): JSX.Element {
|
|||||||
</CompatRouter>
|
</CompatRouter>
|
||||||
</Router>
|
</Router>
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
|
</Sentry.ErrorBoundary>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ export default function CustomDomainSettings(): JSX.Element {
|
|||||||
isLoading: isLoadingDeploymentsData,
|
isLoading: isLoadingDeploymentsData,
|
||||||
isFetching: isFetchingDeploymentsData,
|
isFetching: isFetchingDeploymentsData,
|
||||||
refetch: refetchDeploymentsData,
|
refetch: refetchDeploymentsData,
|
||||||
} = useGetDeploymentsData();
|
} = useGetDeploymentsData(true);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
mutate: updateSubDomain,
|
mutate: updateSubDomain,
|
||||||
|
@ -23,10 +23,13 @@ function DataSourceInfo({
|
|||||||
|
|
||||||
const notSendingData = !dataSentToSigNoz;
|
const notSendingData = !dataSentToSigNoz;
|
||||||
|
|
||||||
|
const isEnabled =
|
||||||
|
activeLicenseV3 && activeLicenseV3.platform === LicensePlatform.CLOUD;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: deploymentsData,
|
data: deploymentsData,
|
||||||
isError: isErrorDeploymentsData,
|
isError: isErrorDeploymentsData,
|
||||||
} = useGetDeploymentsData();
|
} = useGetDeploymentsData(isEnabled || false);
|
||||||
|
|
||||||
const [region, setRegion] = useState<string>('');
|
const [region, setRegion] = useState<string>('');
|
||||||
const [url, setUrl] = useState<string>('');
|
const [url, setUrl] = useState<string>('');
|
||||||
|
@ -293,7 +293,7 @@ function MultiIngestionSettings(): JSX.Element {
|
|||||||
isLoading: isLoadingDeploymentsData,
|
isLoading: isLoadingDeploymentsData,
|
||||||
isFetching: isFetchingDeploymentsData,
|
isFetching: isFetchingDeploymentsData,
|
||||||
isError: isErrorDeploymentsData,
|
isError: isErrorDeploymentsData,
|
||||||
} = useGetDeploymentsData();
|
} = useGetDeploymentsData(true);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
mutate: createIngestionKey,
|
mutate: createIngestionKey,
|
||||||
|
@ -63,7 +63,7 @@ export default function OnboardingIngestionDetails(): JSX.Element {
|
|||||||
isLoading: isLoadingDeploymentsData,
|
isLoading: isLoadingDeploymentsData,
|
||||||
isFetching: isFetchingDeploymentsData,
|
isFetching: isFetchingDeploymentsData,
|
||||||
isError: isDeploymentsDataError,
|
isError: isDeploymentsDataError,
|
||||||
} = useGetDeploymentsData();
|
} = useGetDeploymentsData(true);
|
||||||
|
|
||||||
const handleCopyKey = (text: string): void => {
|
const handleCopyKey = (text: string): void => {
|
||||||
handleCopyToClipboard(text);
|
handleCopyToClipboard(text);
|
||||||
|
@ -69,6 +69,12 @@
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: all 0.2s;
|
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 {
|
.dockBtn {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
import './SideNav.styles.scss';
|
import './SideNav.styles.scss';
|
||||||
|
|
||||||
import { Color } from '@signozhq/design-tokens';
|
import { Color } from '@signozhq/design-tokens';
|
||||||
import { Button } from 'antd';
|
import { Button, Tooltip } from 'antd';
|
||||||
import logEvent from 'api/common/logEvent';
|
import logEvent from 'api/common/logEvent';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import { FeatureKeys } from 'constants/features';
|
import { FeatureKeys } from 'constants/features';
|
||||||
@ -75,7 +75,7 @@ function SideNav(): JSX.Element {
|
|||||||
|
|
||||||
const [userManagementMenuItems, setUserManagementMenuItems] = useState<
|
const [userManagementMenuItems, setUserManagementMenuItems] = useState<
|
||||||
UserManagementMenuItems[]
|
UserManagementMenuItems[]
|
||||||
>([manageLicenseMenuItem]);
|
>([]);
|
||||||
|
|
||||||
const onClickSlackHandler = (): void => {
|
const onClickSlackHandler = (): void => {
|
||||||
window.open('https://signoz.io/slack', '_blank');
|
window.open('https://signoz.io/slack', '_blank');
|
||||||
@ -88,8 +88,10 @@ function SideNav(): JSX.Element {
|
|||||||
const { registerShortcut, deregisterShortcut } = useKeyboardHotkeys();
|
const { registerShortcut, deregisterShortcut } = useKeyboardHotkeys();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isCloudUser: isCloudUserVal,
|
isCloudUser,
|
||||||
isEECloudUser: isEECloudUserVal,
|
isEnterpriseSelfHostedUser,
|
||||||
|
isCommunityUser,
|
||||||
|
isCommunityEnterpriseUser,
|
||||||
} = useGetTenantLicense();
|
} = useGetTenantLicense();
|
||||||
|
|
||||||
const { t } = useTranslation('');
|
const { t } = useTranslation('');
|
||||||
@ -103,11 +105,6 @@ function SideNav(): JSX.Element {
|
|||||||
licenseStatus?.toLocaleLowerCase() ===
|
licenseStatus?.toLocaleLowerCase() ===
|
||||||
LICENSE_PLAN_STATUS.VALID.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 => {
|
const onClickSignozCloud = (): void => {
|
||||||
window.open(
|
window.open(
|
||||||
'https://signoz.io/oss-to-cloud/?utm_source=product_navbar&utm_medium=frontend&utm_campaign=oss_users',
|
'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(() => {
|
useEffect(() => {
|
||||||
if (isCloudUserVal) {
|
if (isCloudUser) {
|
||||||
setLicenseTag('Cloud');
|
setLicenseTag('Cloud');
|
||||||
} else if (isEnterprise) {
|
} else if (isEnterpriseSelfHostedUser) {
|
||||||
setLicenseTag('Enterprise');
|
setLicenseTag('Enterprise');
|
||||||
} else {
|
} else if (isCommunityEnterpriseUser) {
|
||||||
setLicenseTag('Free');
|
setLicenseTag('Enterprise');
|
||||||
|
} else if (isCommunityUser) {
|
||||||
|
setLicenseTag('Community');
|
||||||
}
|
}
|
||||||
}, [isCloudUserVal, isEnterprise]);
|
}, [
|
||||||
|
isCloudUser,
|
||||||
|
isEnterpriseSelfHostedUser,
|
||||||
|
isCommunityEnterpriseUser,
|
||||||
|
isCommunityUser,
|
||||||
|
]);
|
||||||
|
|
||||||
const [isCurrentOrgSettings] = useComponentPermission(
|
const [isCurrentOrgSettings] = useComponentPermission(
|
||||||
['current_org_settings'],
|
['current_org_settings'],
|
||||||
@ -290,7 +294,7 @@ function SideNav(): JSX.Element {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCloudUserVal || isEECloudUserVal) {
|
if (isCloudUser || isEnterpriseSelfHostedUser) {
|
||||||
const isOnboardingEnabled =
|
const isOnboardingEnabled =
|
||||||
featureFlags?.find((feature) => feature.name === FeatureKeys.ONBOARDING)
|
featureFlags?.find((feature) => feature.name === FeatureKeys.ONBOARDING)
|
||||||
?.active || false;
|
?.active || false;
|
||||||
@ -317,6 +321,11 @@ function SideNav(): JSX.Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updatedUserManagementItems = [helpSupportMenuItem];
|
updatedUserManagementItems = [helpSupportMenuItem];
|
||||||
|
|
||||||
|
// Show manage license menu item for EE cloud users with a active license
|
||||||
|
if (isEnterpriseSelfHostedUser) {
|
||||||
|
updatedUserManagementItems.push(manageLicenseMenuItem);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
updatedMenuItems = updatedMenuItems.filter(
|
updatedMenuItems = updatedMenuItems.filter(
|
||||||
(item) => item.key !== ROUTES.INTEGRATIONS && item.key !== ROUTES.BILLING,
|
(item) => item.key !== ROUTES.INTEGRATIONS && item.key !== ROUTES.BILLING,
|
||||||
@ -332,20 +341,21 @@ function SideNav(): JSX.Element {
|
|||||||
onClick: onClickVersionHandler,
|
onClick: onClickVersionHandler,
|
||||||
};
|
};
|
||||||
|
|
||||||
updatedUserManagementItems = [
|
updatedUserManagementItems = [versionMenuItem, slackSupportMenuItem];
|
||||||
versionMenuItem,
|
|
||||||
slackSupportMenuItem,
|
if (isCommunityEnterpriseUser) {
|
||||||
manageLicenseMenuItem,
|
updatedUserManagementItems.push(manageLicenseMenuItem);
|
||||||
];
|
}
|
||||||
}
|
}
|
||||||
setMenuItems(updatedMenuItems);
|
setMenuItems(updatedMenuItems);
|
||||||
setUserManagementMenuItems(updatedUserManagementItems);
|
setUserManagementMenuItems(updatedUserManagementItems);
|
||||||
}, [
|
}, [
|
||||||
|
isCommunityEnterpriseUser,
|
||||||
currentVersion,
|
currentVersion,
|
||||||
featureFlags,
|
featureFlags,
|
||||||
isCloudUserVal,
|
isCloudUser,
|
||||||
|
isEnterpriseSelfHostedUser,
|
||||||
isCurrentVersionError,
|
isCurrentVersionError,
|
||||||
isEECloudUserVal,
|
|
||||||
isLatestVersion,
|
isLatestVersion,
|
||||||
licenses?.licenses,
|
licenses?.licenses,
|
||||||
onClickVersionHandler,
|
onClickVersionHandler,
|
||||||
@ -372,12 +382,31 @@ function SideNav(): JSX.Element {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{licenseTag && (
|
{licenseTag && (
|
||||||
<div className="license tag nav-item-label">{licenseTag}</div>
|
<Tooltip
|
||||||
|
title={
|
||||||
|
// eslint-disable-next-line no-nested-ternary
|
||||||
|
isCommunityUser
|
||||||
|
? 'You are running the community version of SigNoz. You have to install the Enterprise edition in order enable Enterprise features.'
|
||||||
|
: isCommunityEnterpriseUser
|
||||||
|
? 'You do not have an active license present. Add an active license to enable Enterprise features.'
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
placement="bottomRight"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={cx(
|
||||||
|
'license tag nav-item-label',
|
||||||
|
isCommunityEnterpriseUser && 'community-enterprise-user',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{licenseTag}
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isCloudUserVal && user?.role !== USER_ROLES.VIEWER && (
|
{isCloudUser && user?.role !== USER_ROLES.VIEWER && (
|
||||||
<div className="get-started-nav-items">
|
<div className="get-started-nav-items">
|
||||||
<Button
|
<Button
|
||||||
className="get-started-btn"
|
className="get-started-btn"
|
||||||
@ -396,7 +425,7 @@ function SideNav(): JSX.Element {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className={cx(`nav-wrapper`, isCloudUserVal && 'nav-wrapper-cloud')}>
|
<div className={cx(`nav-wrapper`, isCloudUser && 'nav-wrapper-cloud')}>
|
||||||
<div className="primary-nav-items">
|
<div className="primary-nav-items">
|
||||||
{menuItems.map((item, index) => (
|
{menuItems.map((item, index) => (
|
||||||
<NavItem
|
<NavItem
|
||||||
|
@ -3,11 +3,11 @@ import { AxiosError, AxiosResponse } from 'axios';
|
|||||||
import { useQuery, UseQueryResult } from 'react-query';
|
import { useQuery, UseQueryResult } from 'react-query';
|
||||||
import { DeploymentsDataProps } from 'types/api/customDomain/types';
|
import { DeploymentsDataProps } from 'types/api/customDomain/types';
|
||||||
|
|
||||||
export const useGetDeploymentsData = (): UseQueryResult<
|
export const useGetDeploymentsData = (
|
||||||
AxiosResponse<DeploymentsDataProps>,
|
isEnabled: boolean,
|
||||||
AxiosError
|
): UseQueryResult<AxiosResponse<DeploymentsDataProps>, AxiosError> =>
|
||||||
> =>
|
|
||||||
useQuery<AxiosResponse<DeploymentsDataProps>, AxiosError>({
|
useQuery<AxiosResponse<DeploymentsDataProps>, AxiosError>({
|
||||||
queryKey: ['getDeploymentsData'],
|
queryKey: ['getDeploymentsData'],
|
||||||
queryFn: () => getDeploymentsData(),
|
queryFn: () => getDeploymentsData(),
|
||||||
|
enabled: isEnabled,
|
||||||
});
|
});
|
||||||
|
@ -1,15 +1,36 @@
|
|||||||
|
import { AxiosError } from 'axios';
|
||||||
import { useAppContext } from 'providers/App/App';
|
import { useAppContext } from 'providers/App/App';
|
||||||
import { LicensePlatform } from 'types/api/licensesV3/getActive';
|
import { LicensePlatform } from 'types/api/licensesV3/getActive';
|
||||||
|
|
||||||
export const useGetTenantLicense = (): {
|
export const useGetTenantLicense = (): {
|
||||||
isCloudUser: boolean;
|
isCloudUser: boolean;
|
||||||
isEECloudUser: boolean;
|
isEnterpriseSelfHostedUser: boolean;
|
||||||
|
isCommunityUser: boolean;
|
||||||
|
isCommunityEnterpriseUser: boolean;
|
||||||
} => {
|
} => {
|
||||||
const { activeLicenseV3 } = useAppContext();
|
const { activeLicenseV3, activeLicenseV3FetchError } = useAppContext();
|
||||||
|
|
||||||
return {
|
const responsePayload = {
|
||||||
isCloudUser: activeLicenseV3?.platform === LicensePlatform.CLOUD || false,
|
isCloudUser: activeLicenseV3?.platform === LicensePlatform.CLOUD || false,
|
||||||
isEECloudUser:
|
isEnterpriseSelfHostedUser:
|
||||||
activeLicenseV3?.platform === LicensePlatform.SELF_HOSTED || false,
|
activeLicenseV3?.platform === LicensePlatform.SELF_HOSTED || false,
|
||||||
|
isCommunityUser: false,
|
||||||
|
isCommunityEnterpriseUser: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (
|
||||||
|
activeLicenseV3FetchError &&
|
||||||
|
(activeLicenseV3FetchError as AxiosError)?.response?.status === 404
|
||||||
|
) {
|
||||||
|
responsePayload.isCommunityEnterpriseUser = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
activeLicenseV3FetchError &&
|
||||||
|
(activeLicenseV3FetchError as AxiosError)?.response?.status === 501
|
||||||
|
) {
|
||||||
|
responsePayload.isCommunityUser = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return responsePayload;
|
||||||
};
|
};
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
import './ReactI18';
|
import './ReactI18';
|
||||||
import 'styles.scss';
|
import 'styles.scss';
|
||||||
|
|
||||||
import * as Sentry from '@sentry/react';
|
|
||||||
import AppRoutes from 'AppRoutes';
|
import AppRoutes from 'AppRoutes';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import { ThemeProvider } from 'hooks/useDarkMode';
|
import { ThemeProvider } from 'hooks/useDarkMode';
|
||||||
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
|
|
||||||
import posthog from 'posthog-js';
|
|
||||||
import { AppProvider } from 'providers/App/App';
|
import { AppProvider } from 'providers/App/App';
|
||||||
import TimezoneProvider from 'providers/Timezone';
|
import TimezoneProvider from 'providers/Timezone';
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
@ -37,38 +34,10 @@ const queryClient = new QueryClient({
|
|||||||
|
|
||||||
const container = document.getElementById('root');
|
const container = document.getElementById('root');
|
||||||
|
|
||||||
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.
|
|
||||||
});
|
|
||||||
|
|
||||||
if (container) {
|
if (container) {
|
||||||
const root = createRoot(container);
|
const root = createRoot(container);
|
||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
<Sentry.ErrorBoundary fallback={<ErrorBoundaryFallback />}>
|
|
||||||
<HelmetProvider>
|
<HelmetProvider>
|
||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
<TimezoneProvider>
|
<TimezoneProvider>
|
||||||
@ -84,7 +53,6 @@ if (container) {
|
|||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
</TimezoneProvider>
|
</TimezoneProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</HelmetProvider>
|
</HelmetProvider>,
|
||||||
</Sentry.ErrorBoundary>,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,7 @@ import { getRoutes } from './utils';
|
|||||||
function SettingsPage(): JSX.Element {
|
function SettingsPage(): JSX.Element {
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
const { user, featureFlags, trialInfo } = useAppContext();
|
const { user, featureFlags, trialInfo } = useAppContext();
|
||||||
const {
|
const { isCloudUser, isEnterpriseSelfHostedUser } = useGetTenantLicense();
|
||||||
isCloudUser: isCloudAccount,
|
|
||||||
isEECloudUser: isEECloudAccount,
|
|
||||||
} = useGetTenantLicense();
|
|
||||||
|
|
||||||
const isWorkspaceBlocked = trialInfo?.workSpaceBlock || false;
|
const isWorkspaceBlocked = trialInfo?.workSpaceBlock || false;
|
||||||
|
|
||||||
@ -37,8 +34,8 @@ function SettingsPage(): JSX.Element {
|
|||||||
isCurrentOrgSettings,
|
isCurrentOrgSettings,
|
||||||
isGatewayEnabled,
|
isGatewayEnabled,
|
||||||
isWorkspaceBlocked,
|
isWorkspaceBlocked,
|
||||||
isCloudAccount,
|
isCloudUser,
|
||||||
isEECloudAccount,
|
isEnterpriseSelfHostedUser,
|
||||||
t,
|
t,
|
||||||
),
|
),
|
||||||
[
|
[
|
||||||
@ -46,8 +43,8 @@ function SettingsPage(): JSX.Element {
|
|||||||
isCurrentOrgSettings,
|
isCurrentOrgSettings,
|
||||||
isGatewayEnabled,
|
isGatewayEnabled,
|
||||||
isWorkspaceBlocked,
|
isWorkspaceBlocked,
|
||||||
isCloudAccount,
|
isCloudUser,
|
||||||
isEECloudAccount,
|
isEnterpriseSelfHostedUser,
|
||||||
t,
|
t,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -17,8 +17,8 @@ export const getRoutes = (
|
|||||||
isCurrentOrgSettings: boolean,
|
isCurrentOrgSettings: boolean,
|
||||||
isGatewayEnabled: boolean,
|
isGatewayEnabled: boolean,
|
||||||
isWorkspaceBlocked: boolean,
|
isWorkspaceBlocked: boolean,
|
||||||
isCloudAccount: boolean,
|
isCloudUser: boolean,
|
||||||
isEECloudAccount: boolean,
|
isEnterpriseSelfHostedUser: boolean,
|
||||||
t: TFunction,
|
t: TFunction,
|
||||||
): RouteTabProps['routes'] => {
|
): RouteTabProps['routes'] => {
|
||||||
const settings = [];
|
const settings = [];
|
||||||
@ -42,17 +42,17 @@ export const getRoutes = (
|
|||||||
settings.push(...multiIngestionSettings(t));
|
settings.push(...multiIngestionSettings(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCloudAccount && !isGatewayEnabled) {
|
if (isCloudUser && !isGatewayEnabled) {
|
||||||
settings.push(...ingestionSettings(t));
|
settings.push(...ingestionSettings(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.push(...alertChannels(t));
|
settings.push(...alertChannels(t));
|
||||||
|
|
||||||
if ((isCloudAccount || isEECloudAccount) && isAdmin) {
|
if ((isCloudUser || isEnterpriseSelfHostedUser) && isAdmin) {
|
||||||
settings.push(...apiKeys(t));
|
settings.push(...apiKeys(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCloudAccount && isAdmin) {
|
if (isCloudUser && isAdmin) {
|
||||||
settings.push(...customDomainSettings(t));
|
settings.push(...customDomainSettings(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +56,8 @@ func Error(rw http.ResponseWriter, cause error) {
|
|||||||
httpCode = http.StatusConflict
|
httpCode = http.StatusConflict
|
||||||
case errors.TypeUnauthenticated:
|
case errors.TypeUnauthenticated:
|
||||||
httpCode = http.StatusUnauthorized
|
httpCode = http.StatusUnauthorized
|
||||||
|
case errors.TypeUnsupported:
|
||||||
|
httpCode = http.StatusNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
rea := make([]responseerroradditional, len(a))
|
rea := make([]responseerroradditional, len(a))
|
||||||
|
@ -614,6 +614,13 @@ func (aH *APIHandler) RegisterRoutes(router *mux.Router, am *AuthMiddleware) {
|
|||||||
router.HandleFunc("/api/v1/getResetPasswordToken/{id}", am.AdminAccess(aH.getResetPasswordToken)).Methods(http.MethodGet)
|
router.HandleFunc("/api/v1/getResetPasswordToken/{id}", am.AdminAccess(aH.getResetPasswordToken)).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/api/v1/resetPassword", am.OpenAccess(aH.resetPassword)).Methods(http.MethodPost)
|
router.HandleFunc("/api/v1/resetPassword", am.OpenAccess(aH.resetPassword)).Methods(http.MethodPost)
|
||||||
router.HandleFunc("/api/v1/changePassword/{id}", am.SelfAccess(aH.changePassword)).Methods(http.MethodPost)
|
router.HandleFunc("/api/v1/changePassword/{id}", am.SelfAccess(aH.changePassword)).Methods(http.MethodPost)
|
||||||
|
|
||||||
|
router.HandleFunc("/api/v3/licenses", am.ViewAccess(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
render.Success(rw, http.StatusOK, []any{})
|
||||||
|
})).Methods(http.MethodGet)
|
||||||
|
router.HandleFunc("/api/v3/licenses/active", am.ViewAccess(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
render.Error(rw, errorsV2.New(errorsV2.TypeUnsupported, errorsV2.CodeUnsupported, "not implemented"))
|
||||||
|
})).Methods(http.MethodGet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ah *APIHandler) MetricExplorerRoutes(router *mux.Router, am *AuthMiddleware) {
|
func (ah *APIHandler) MetricExplorerRoutes(router *mux.Router, am *AuthMiddleware) {
|
||||||
|
@ -113,8 +113,6 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
// initiate feature manager
|
// initiate feature manager
|
||||||
fm := featureManager.StartManager()
|
fm := featureManager.StartManager()
|
||||||
|
|
||||||
readerReady := make(chan bool)
|
|
||||||
|
|
||||||
fluxIntervalForTraceDetail, err := time.ParseDuration(serverOptions.FluxIntervalForTraceDetail)
|
fluxIntervalForTraceDetail, err := time.ParseDuration(serverOptions.FluxIntervalForTraceDetail)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -150,7 +148,6 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
c = cache.NewCache(cacheOpts)
|
c = cache.NewCache(cacheOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
<-readerReady
|
|
||||||
rm, err := makeRulesManager(
|
rm, err := makeRulesManager(
|
||||||
serverOptions.RuleRepoURL,
|
serverOptions.RuleRepoURL,
|
||||||
serverOptions.SigNoz.SQLStore.SQLxDB(),
|
serverOptions.SigNoz.SQLStore.SQLxDB(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user