feat: enable billing and org-settings in workspace blocked state (#6761)

* feat: enable billing and org-settings in workspace blocked state

* feat: disable sidebar items in workspace blocked state
This commit is contained in:
Yunus M 2025-01-08 11:16:41 +05:30 committed by GitHub
parent 5c546e8efd
commit e92d055c30
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 96 additions and 6 deletions

View File

@ -11,6 +11,7 @@ import { useQuery } from 'react-query';
import { matchPath, useLocation } from 'react-router-dom';
import { LicenseState, LicenseStatus } from 'types/api/licensesV3/getActive';
import { Organization } from 'types/api/user/getOrganization';
import { USER_ROLES } from 'types/roles';
import { isCloudUser } from 'utils/app';
import { routePermission } from 'utils/permission';
@ -36,6 +37,8 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element {
activeLicenseV3,
isFetchingActiveLicenseV3,
} = useAppContext();
const isAdmin = user.role === USER_ROLES.ADMIN;
const mapRoutes = useMemo(
() =>
new Map(
@ -113,7 +116,17 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element {
const navigateToWorkSpaceBlocked = (route: any): void => {
const { path } = route;
if (path && path !== ROUTES.WORKSPACE_LOCKED) {
const isRouteEnabledForWorkspaceBlockedState =
isAdmin &&
(path === ROUTES.ORG_SETTINGS ||
path === ROUTES.BILLING ||
path === ROUTES.MY_SETTINGS);
if (
path &&
path !== ROUTES.WORKSPACE_LOCKED &&
!isRouteEnabledForWorkspaceBlockedState
) {
history.push(ROUTES.WORKSPACE_LOCKED);
}
};
@ -127,6 +140,7 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element {
navigateToWorkSpaceBlocked(currentRoute);
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isFetchingLicenses, licenses?.workSpaceBlock, mapRoutes, pathname]);
const navigateToWorkSpaceSuspended = (route: any): void => {

View File

@ -15,6 +15,13 @@
}
}
&.disabled {
.nav-item-data {
opacity: 0.5;
cursor: not-allowed;
}
}
&:hover {
cursor: pointer;

View File

@ -11,17 +11,28 @@ export default function NavItem({
item,
isActive,
onClick,
isDisabled,
}: {
item: SidebarItem;
isActive: boolean;
onClick: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
isDisabled: boolean;
}): JSX.Element {
const { label, icon, isBeta, isNew } = item;
return (
<div
className={cx('nav-item', isActive ? 'active' : '')}
onClick={(event): void => onClick(event)}
className={cx(
'nav-item',
isActive ? 'active' : '',
isDisabled ? 'disabled' : '',
)}
onClick={(event): void => {
if (isDisabled) {
return;
}
onClick(event);
}}
>
<div className="nav-item-active-marker" />
<div className={cx('nav-item-data', isBeta ? 'beta-tag' : '')}>

View File

@ -89,6 +89,8 @@ function SideNav(): JSX.Element {
const licenseStatus: string =
licenses?.licenses?.find((e: License) => e.isCurrent)?.status || '';
const isWorkspaceBlocked = licenses?.workSpaceBlock || false;
const isLicenseActive =
licenseStatus?.toLocaleLowerCase() ===
LICENSE_PLAN_STATUS.VALID.toLocaleLowerCase();
@ -351,7 +353,11 @@ function SideNav(): JSX.Element {
<div className="get-started-nav-items">
<Button
className="get-started-btn"
disabled={isWorkspaceBlocked}
onClick={(event: MouseEvent): void => {
if (isWorkspaceBlocked) {
return;
}
onClickGetStarted(event);
}}
>
@ -369,6 +375,11 @@ function SideNav(): JSX.Element {
key={item.key || index}
item={item}
isActive={activeMenuKey === item.key}
isDisabled={
isWorkspaceBlocked &&
item.key !== ROUTES.BILLING &&
item.key !== ROUTES.SETTINGS
}
onClick={(event): void => {
handleMenuItemClick(event, item);
}}
@ -380,6 +391,7 @@ function SideNav(): JSX.Element {
<NavItem
key="keyboardShortcuts"
item={shortcutMenuItem}
isDisabled={isWorkspaceBlocked}
isActive={false}
onClick={onClickShortcuts}
/>
@ -389,6 +401,7 @@ function SideNav(): JSX.Element {
key="trySignozCloud"
item={trySignozCloudMenuItem}
isActive={false}
isDisabled={isWorkspaceBlocked}
onClick={onClickSignozCloud}
/>
)}
@ -399,6 +412,7 @@ function SideNav(): JSX.Element {
key={item?.key || index}
item={item}
isActive={activeMenuKey === item?.key}
isDisabled={isWorkspaceBlocked}
onClick={(event: MouseEvent): void => {
handleUserManagentMenuItemClick(item?.key as string, event);
logEvent('Sidebar: Menu clicked', {
@ -415,6 +429,7 @@ function SideNav(): JSX.Element {
key={inviteMemberMenuItem.key}
item={inviteMemberMenuItem}
isActive={activeMenuKey === inviteMemberMenuItem?.key}
isDisabled={false}
onClick={(event: React.MouseEvent): void => {
if (isCtrlMetaKey(event)) {
openInNewTab(`${inviteMemberMenuItem.key}`);
@ -434,6 +449,7 @@ function SideNav(): JSX.Element {
key={ROUTES.MY_SETTINGS}
item={userSettingsMenuItem}
isActive={activeMenuKey === userSettingsMenuItem?.key}
isDisabled={false}
onClick={(event: MouseEvent): void => {
handleUserManagentMenuItemClick(
userSettingsMenuItem?.key as string,

View File

@ -11,7 +11,9 @@ import { getRoutes } from './utils';
function SettingsPage(): JSX.Element {
const { pathname } = useLocation();
const { user, featureFlags } = useAppContext();
const { user, featureFlags, licenses } = useAppContext();
const isWorkspaceBlocked = licenses?.workSpaceBlock || false;
const [isCurrentOrgSettings] = useComponentPermission(
['current_org_settings'],
@ -24,8 +26,15 @@ function SettingsPage(): JSX.Element {
?.active || false;
const routes = useMemo(
() => getRoutes(user.role, isCurrentOrgSettings, isGatewayEnabled, t),
[user.role, isCurrentOrgSettings, isGatewayEnabled, t],
() =>
getRoutes(
user.role,
isCurrentOrgSettings,
isGatewayEnabled,
isWorkspaceBlocked,
t,
),
[user.role, isCurrentOrgSettings, isGatewayEnabled, isWorkspaceBlocked, t],
);
return <RouteTab routes={routes} activeKey={pathname} history={history} />;

View File

@ -17,6 +17,7 @@ export const getRoutes = (
userRole: ROLES | null,
isCurrentOrgSettings: boolean,
isGatewayEnabled: boolean,
isWorkspaceBlocked: boolean,
t: TFunction,
): RouteTabProps['routes'] => {
const settings = [];
@ -27,6 +28,12 @@ export const getRoutes = (
const isAdmin = userRole === USER_ROLES.ADMIN;
const isEditor = userRole === USER_ROLES.EDITOR;
if (isWorkspaceBlocked && isAdmin) {
settings.push(...organizationSettings(t));
return settings;
}
settings.push(...generalSettings(t));
if (isCurrentOrgSettings) {

View File

@ -49,6 +49,14 @@ $dark-theme: 'darkMode';
display: flex;
align-items: center;
gap: 16px;
.ant-btn-link {
color: var(--text-vanilla-400);
.#{$light-theme} & {
color: var(--text-ink-200);
}
}
}
}
.ant-modal-content {

View File

@ -126,6 +126,12 @@ export default function WorkspaceBlocked(): JSX.Element {
});
};
const handleViewBilling = (): void => {
logEvent('Workspace Blocked: User Clicked View Billing', {});
history.push(ROUTES.BILLING);
};
const renderCustomerStories = (
filterCondition: (index: number) => boolean,
): JSX.Element[] =>
@ -276,6 +282,18 @@ export default function WorkspaceBlocked(): JSX.Element {
{t('trialPlanExpired')}
</span>
<span className="workspace-locked__modal__header__actions">
{isAdmin && (
<Button
className="workspace-locked__modal__header__actions__billing"
type="link"
size="small"
role="button"
onClick={handleViewBilling}
>
View Billing
</Button>
)}
<Typography.Text className="workspace-locked__modal__title">
Got Questions?
</Typography.Text>