fix(license): OSS UI build failing due to restrictive active license check (#7345)

* fix: ui breaking due to licenses issue

* feat: handle navigations in case of oss in homepage (#7347)

* feat: handle navigations in case of oss in homepage

* fix: skip datasource and redirect to get-started from services table

---------

Co-authored-by: makeavish <makeavish786@gmail.com>

---------

Co-authored-by: makeavish <makeavish786@gmail.com>
This commit is contained in:
Yunus M 2025-03-18 14:24:26 +05:30 committed by GitHub
parent 7118829107
commit f992ba9106
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 161 additions and 73 deletions

View File

@ -44,7 +44,6 @@ function App(): JSX.Element {
trialInfo,
activeLicenseV3,
isFetchingActiveLicenseV3,
activeLicenseV3FetchError,
userFetchError,
licensesFetchError,
featureFlagsFetchError,
@ -264,12 +263,7 @@ function App(): JSX.Element {
// if the user is in logged in state
if (isLoggedInState) {
// if the setup calls are loading then return a spinner
if (
isFetchingLicenses ||
isFetchingUser ||
isFetchingFeatureFlags ||
isFetchingActiveLicenseV3
) {
if (isFetchingLicenses || isFetchingUser || isFetchingFeatureFlags) {
return <Spinner tip="Loading..." />;
}
@ -277,7 +271,7 @@ function App(): JSX.Element {
// 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 || activeLicenseV3FetchError) &&
(userFetchError || licensesFetchError) &&
pathname !== ROUTES.SOMETHING_WENT_WRONG
) {
history.replace(ROUTES.SOMETHING_WENT_WRONG);
@ -287,8 +281,7 @@ function App(): JSX.Element {
if (
(!licenses || !user.email || !featureFlags) &&
!userFetchError &&
!licensesFetchError &&
!activeLicenseV3FetchError
!licensesFetchError
) {
return <Spinner tip="Loading..." />;
}

View File

@ -6,7 +6,11 @@ import { useGetDeploymentsData } from 'hooks/CustomDomain/useGetDeploymentsData'
import history from 'lib/history';
import { Globe, Link2 } from 'lucide-react';
import Card from 'periscope/components/Card/Card';
import { useAppContext } from 'providers/App/App';
import { useEffect, useState } from 'react';
import { LicensePlatform } from 'types/api/licensesV3/getActive';
import { DOCS_LINKS } from '../constants';
function DataSourceInfo({
dataSentToSigNoz,
@ -15,6 +19,8 @@ function DataSourceInfo({
dataSentToSigNoz: boolean;
isLoading: boolean;
}): JSX.Element {
const { activeLicenseV3 } = useAppContext();
const notSendingData = !dataSentToSigNoz;
const {
@ -77,12 +83,36 @@ function DataSourceInfo({
tabIndex={0}
onClick={(): void => {
logEvent('Homepage: Connect dataSource clicked', {});
history.push(ROUTES.GET_STARTED);
if (
activeLicenseV3 &&
activeLicenseV3.platform === LicensePlatform.CLOUD
) {
history.push(ROUTES.GET_STARTED_WITH_CLOUD);
} else {
window?.open(
DOCS_LINKS.ADD_DATA_SOURCE,
'_blank',
'noopener noreferrer',
);
}
}}
onKeyDown={(e): void => {
if (e.key === 'Enter') {
logEvent('Homepage: Connect dataSource clicked', {});
history.push(ROUTES.GET_STARTED);
if (
activeLicenseV3 &&
activeLicenseV3.platform === LicensePlatform.CLOUD
) {
history.push(ROUTES.GET_STARTED_WITH_CLOUD);
} else {
window?.open(
DOCS_LINKS.ADD_DATA_SOURCE,
'_blank',
'noopener noreferrer',
);
}
}
}}
>

View File

@ -1,11 +1,14 @@
/* eslint-disable sonarjs/cognitive-complexity */
import './HomeChecklist.styles.scss';
import { Button } from 'antd';
import logEvent from 'api/common/logEvent';
import ROUTES from 'constants/routes';
import history from 'lib/history';
import { ArrowRight, ArrowRightToLine, BookOpenText } from 'lucide-react';
import { useAppContext } from 'providers/App/App';
import { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import { LicensePlatform } from 'types/api/licensesV3/getActive';
import { USER_ROLES } from 'types/roles';
export type ChecklistItem = {
@ -14,6 +17,7 @@ export type ChecklistItem = {
description: string;
completed: boolean;
isSkipped: boolean;
isSkippable?: boolean;
skippedPreferenceKey?: string;
toRoute?: string;
docsLink?: string;
@ -28,7 +32,7 @@ function HomeChecklist({
onSkip: (item: ChecklistItem) => void;
isLoading: boolean;
}): JSX.Element {
const { user } = useAppContext();
const { user, activeLicenseV3 } = useAppContext();
const [completedChecklistItems, setCompletedChecklistItems] = useState<
ChecklistItem[]
@ -79,19 +83,32 @@ function HomeChecklist({
{user?.role !== USER_ROLES.VIEWER && (
<div className="whats-next-checklist-item-action-buttons">
<div className="whats-next-checklist-item-action-buttons-container">
<Link to={item.toRoute || ''}>
<Button
type="default"
className="periscope-btn secondary"
onClick={(): void => {
logEvent('Welcome Checklist: Get started clicked', {
step: item.id,
});
}}
>
Get Started &nbsp; <ArrowRight size={16} />
</Button>
</Link>
<Button
type="default"
className="periscope-btn secondary"
onClick={(): void => {
logEvent('Welcome Checklist: Get started clicked', {
step: item.id,
});
if (item.toRoute !== ROUTES.GET_STARTED_WITH_CLOUD) {
history.push(item.toRoute || '');
} else if (
activeLicenseV3 &&
activeLicenseV3.platform === LicensePlatform.CLOUD
) {
history.push(item.toRoute || '');
} else {
window?.open(
item.docsLink || '',
'_blank',
'noopener noreferrer',
);
}
}}
>
Get Started &nbsp; <ArrowRight size={16} />
</Button>
{item.docsLink && (
<Button
@ -102,7 +119,7 @@ function HomeChecklist({
step: item.id,
});
window?.open(item.docsLink, '_blank');
window?.open(item.docsLink, '_blank', 'noopener noreferrer');
}}
>
<BookOpenText size={16} />
@ -110,7 +127,7 @@ function HomeChecklist({
)}
</div>
{!item.isSkipped && (
{!item.isSkipped && item.isSkippable && (
<div className="whats-next-checklist-item-action-buttons-container">
<Button
type="link"

View File

@ -11,6 +11,7 @@ import useGetTopLevelOperations from 'hooks/useGetTopLevelOperations';
import useResourceAttribute from 'hooks/useResourceAttribute';
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils';
import { useSafeNavigate } from 'hooks/useSafeNavigate';
import history from 'lib/history';
import { ArrowRight, ArrowUpRight } from 'lucide-react';
import Card from 'periscope/components/Card/Card';
import { useAppContext } from 'providers/App/App';
@ -20,18 +21,29 @@ import { QueryKey } from 'react-query';
import { useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import { AppState } from 'store/reducers';
import {
LicensePlatform,
LicenseV3ResModel,
} from 'types/api/licensesV3/getActive';
import { ServicesList } from 'types/api/metrics/getService';
import { GlobalReducer } from 'types/reducer/globalTime';
import { Tags } from 'types/reducer/trace';
import { USER_ROLES } from 'types/roles';
import { DOCS_LINKS } from '../constants';
import { columns, TIME_PICKER_OPTIONS } from './constants';
const homeInterval = 30 * 60 * 1000;
// Extracted EmptyState component
const EmptyState = memo(
({ user }: { user: IUser }): JSX.Element => (
({
user,
activeLicenseV3,
}: {
user: IUser;
activeLicenseV3: LicenseV3ResModel | null;
}): JSX.Element => (
<div className="empty-state-container">
<div className="empty-state-content-container">
<div className="empty-state-content">
@ -48,19 +60,31 @@ const EmptyState = memo(
{user?.role !== USER_ROLES.VIEWER && (
<div className="empty-actions-container">
<Link to={ROUTES.GET_STARTED}>
<Button
type="default"
className="periscope-btn secondary"
onClick={(): void => {
logEvent('Homepage: Get Started clicked', {
source: 'Service Metrics',
});
}}
>
Get Started &nbsp; <ArrowRight size={16} />
</Button>
</Link>
<Button
type="default"
className="periscope-btn secondary"
onClick={(): void => {
logEvent('Homepage: Get Started clicked', {
source: 'Service Metrics',
});
if (
activeLicenseV3 &&
activeLicenseV3.platform === LicensePlatform.CLOUD
) {
history.push(ROUTES.GET_STARTED_WITH_CLOUD);
} else {
window?.open(
DOCS_LINKS.ADD_DATA_SOURCE,
'_blank',
'noopener noreferrer',
);
}
}}
>
Get Started &nbsp; <ArrowRight size={16} />
</Button>
<Button
type="link"
className="learn-more-link"
@ -122,7 +146,7 @@ function ServiceMetrics({
GlobalReducer
>((state) => state.globalTime);
const { user } = useAppContext();
const { user, activeLicenseV3 } = useAppContext();
const [timeRange, setTimeRange] = useState(() => {
const now = new Date().getTime();
@ -311,7 +335,7 @@ function ServiceMetrics({
{servicesExist ? (
<ServicesListTable services={top5Services} onRowClick={handleRowClick} />
) : (
<EmptyState user={user} />
<EmptyState user={user} activeLicenseV3={activeLicenseV3} />
)}
</Card.Content>

View File

@ -3,6 +3,7 @@ import logEvent from 'api/common/logEvent';
import ROUTES from 'constants/routes';
import { useQueryService } from 'hooks/useQueryService';
import { useSafeNavigate } from 'hooks/useSafeNavigate';
import history from 'lib/history';
import { ArrowRight, ArrowUpRight } from 'lucide-react';
import Card from 'periscope/components/Card/Card';
import { useAppContext } from 'providers/App/App';
@ -10,10 +11,12 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
import { useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import { AppState } from 'store/reducers';
import { LicensePlatform } from 'types/api/licensesV3/getActive';
import { ServicesList } from 'types/api/metrics/getService';
import { GlobalReducer } from 'types/reducer/globalTime';
import { USER_ROLES } from 'types/roles';
import { DOCS_LINKS } from '../constants';
import { columns, TIME_PICKER_OPTIONS } from './constants';
const homeInterval = 30 * 60 * 1000;
@ -29,7 +32,7 @@ export default function ServiceTraces({
(state) => state.globalTime,
);
const { user } = useAppContext();
const { user, activeLicenseV3 } = useAppContext();
const now = new Date().getTime();
const [timeRange, setTimeRange] = useState({
@ -112,19 +115,30 @@ export default function ServiceTraces({
{user?.role !== USER_ROLES.VIEWER && (
<div className="empty-actions-container">
<Link to={ROUTES.GET_STARTED}>
<Button
type="default"
className="periscope-btn secondary"
onClick={(): void => {
logEvent('Homepage: Get Started clicked', {
source: 'Service Traces',
});
}}
>
Get Started &nbsp; <ArrowRight size={16} />
</Button>
</Link>
<Button
type="default"
className="periscope-btn secondary"
onClick={(): void => {
logEvent('Homepage: Get Started clicked', {
source: 'Service Traces',
});
if (
activeLicenseV3 &&
activeLicenseV3.platform === LicensePlatform.CLOUD
) {
history.push(ROUTES.GET_STARTED_WITH_CLOUD);
} else {
window?.open(
DOCS_LINKS.ADD_DATA_SOURCE,
'_blank',
'noopener noreferrer',
);
}
}}
>
Get Started &nbsp; <ArrowRight size={16} />
</Button>
<Button
type="link"
@ -146,7 +160,7 @@ export default function ServiceTraces({
</div>
</div>
),
[user?.role],
[user?.role, activeLicenseV3],
);
const renderDashboardsList = useCallback(

View File

@ -15,6 +15,7 @@ export const checkListStepToPreferenceKeyMap = {
};
export const DOCS_LINKS = {
ADD_DATA_SOURCE: 'https://signoz.io/docs/instrumentation/overview/',
SEND_LOGS: 'https://signoz.io/docs/userguide/logs/',
SEND_TRACES: 'https://signoz.io/docs/userguide/traces/',
SEND_INFRA_METRICS:
@ -32,6 +33,7 @@ export const defaultChecklistItemsState: ChecklistItem[] = [
description: '',
completed: true,
isSkipped: false,
isSkippable: false,
skippedPreferenceKey: checkListStepToPreferenceKeyMap.SETUP_WORKSPACE,
},
{
@ -41,7 +43,9 @@ export const defaultChecklistItemsState: ChecklistItem[] = [
completed: false,
isSkipped: false,
skippedPreferenceKey: checkListStepToPreferenceKeyMap.ADD_DATA_SOURCE,
toRoute: ROUTES.GET_STARTED,
toRoute: ROUTES.GET_STARTED_WITH_CLOUD,
docsLink: DOCS_LINKS.ADD_DATA_SOURCE,
isSkippable: false,
},
{
id: 'SEND_LOGS',
@ -50,8 +54,9 @@ export const defaultChecklistItemsState: ChecklistItem[] = [
'Send your logs to SigNoz to get more visibility into how your resources interact.',
completed: false,
isSkipped: false,
isSkippable: true,
skippedPreferenceKey: checkListStepToPreferenceKeyMap.SEND_LOGS,
toRoute: ROUTES.GET_STARTED,
toRoute: ROUTES.GET_STARTED_WITH_CLOUD,
docsLink: DOCS_LINKS.SEND_LOGS,
},
{
@ -61,8 +66,9 @@ export const defaultChecklistItemsState: ChecklistItem[] = [
'Send your traces to SigNoz to get more visibility into how your resources interact.',
completed: false,
isSkipped: false,
isSkippable: true,
skippedPreferenceKey: checkListStepToPreferenceKeyMap.SEND_TRACES,
toRoute: ROUTES.GET_STARTED,
toRoute: ROUTES.GET_STARTED_WITH_CLOUD,
docsLink: DOCS_LINKS.SEND_TRACES,
},
{
@ -72,8 +78,9 @@ export const defaultChecklistItemsState: ChecklistItem[] = [
'Send your infra metrics to SigNoz to get more visibility into your infrastructure.',
completed: false,
isSkipped: false,
isSkippable: true,
skippedPreferenceKey: checkListStepToPreferenceKeyMap.SEND_INFRA_METRICS,
toRoute: ROUTES.GET_STARTED,
toRoute: ROUTES.GET_STARTED_WITH_CLOUD,
docsLink: DOCS_LINKS.SEND_INFRA_METRICS,
},
{
@ -83,6 +90,7 @@ export const defaultChecklistItemsState: ChecklistItem[] = [
'Setup alerts to get notified when your resources are not performing as expected.',
completed: false,
isSkipped: false,
isSkippable: true,
skippedPreferenceKey: checkListStepToPreferenceKeyMap.SETUP_ALERTS,
toRoute: ROUTES.ALERTS_NEW,
docsLink: DOCS_LINKS.SETUP_ALERTS,
@ -94,6 +102,7 @@ export const defaultChecklistItemsState: ChecklistItem[] = [
'Save your views to get a quick overview of your data and share it with your team.',
completed: false,
isSkipped: false,
isSkippable: true,
skippedPreferenceKey: checkListStepToPreferenceKeyMap.SETUP_SAVED_VIEWS,
toRoute: ROUTES.LOGS_EXPLORER,
docsLink: DOCS_LINKS.SETUP_SAVED_VIEWS,
@ -105,6 +114,7 @@ export const defaultChecklistItemsState: ChecklistItem[] = [
'Create dashboards to visualize your data and share it with your team.',
completed: false,
isSkipped: false,
isSkippable: true,
skippedPreferenceKey: checkListStepToPreferenceKeyMap.SETUP_DASHBOARDS,
toRoute: ROUTES.ALL_DASHBOARD,
docsLink: DOCS_LINKS.SETUP_DASHBOARDS,

View File

@ -11,10 +11,10 @@ function WorkspaceAccessRestricted(): JSX.Element {
const { activeLicenseV3, isFetchingActiveLicenseV3 } = useAppContext();
useEffect(() => {
if (!isFetchingActiveLicenseV3 && activeLicenseV3) {
const isTerminated = activeLicenseV3.state === LicenseState.TERMINATED;
const isExpired = activeLicenseV3.state === LicenseState.EXPIRED;
const isCancelled = activeLicenseV3.state === LicenseState.CANCELLED;
if (!isFetchingActiveLicenseV3) {
const isTerminated = activeLicenseV3?.state === LicenseState.TERMINATED;
const isExpired = activeLicenseV3?.state === LicenseState.EXPIRED;
const isCancelled = activeLicenseV3?.state === LicenseState.CANCELLED;
const isWorkspaceAccessRestricted = isTerminated || isExpired || isCancelled;
@ -22,7 +22,7 @@ function WorkspaceAccessRestricted(): JSX.Element {
!isWorkspaceAccessRestricted ||
activeLicenseV3.platform === LicensePlatform.SELF_HOSTED
) {
history.push(ROUTES.APPLICATION);
history.push(ROUTES.HOME);
}
}
}, [isFetchingActiveLicenseV3, activeLicenseV3]);

View File

@ -77,7 +77,7 @@ export default function WorkspaceBlocked(): JSX.Element {
!shouldBlockWorkspace ||
activeLicenseV3?.platform === LicensePlatform.SELF_HOSTED
) {
history.push(ROUTES.APPLICATION);
history.push(ROUTES.HOME);
}
}
}, [

View File

@ -56,15 +56,15 @@ function WorkspaceSuspended(): JSX.Element {
}, [manageCreditCard]);
useEffect(() => {
if (!isFetchingActiveLicenseV3 && activeLicenseV3) {
if (!isFetchingActiveLicenseV3) {
const shouldSuspendWorkspace =
activeLicenseV3.state === LicenseState.DEFAULTED;
activeLicenseV3?.state === LicenseState.DEFAULTED;
if (
!shouldSuspendWorkspace ||
activeLicenseV3?.platform === LicensePlatform.SELF_HOSTED
) {
history.push(ROUTES.APPLICATION);
history.push(ROUTES.HOME);
}
}
}, [isFetchingActiveLicenseV3, activeLicenseV3]);