0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-02-17 22:04:19 -05:00

feat(console): control console content by tenant env tag (#4830)

This commit is contained in:
Xiao Yijun 2023-11-07 12:05:03 +08:00 committed by GitHub
parent c65dcb9552
commit 65d8444988
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 77 additions and 29 deletions

View file

@ -155,7 +155,7 @@ function CreateConnectorForm({ onClose, isOpen: isFormOpen, type }: Props) {
<>
<div className={styles.standardLabel}>
<DynamicT forKey="connectors.standard_connectors" />
{isStandardConnectorDisabled && <ProTag />}
<ProTag isVisibleInProdTenant={isStandardConnectorDisabled} />
</div>
<ConnectorRadioGroup
name="group"

View file

@ -75,7 +75,9 @@ function GuideCard({ data, onClick, hasBorder, hasButton }: Props) {
<div className={styles.infoWrapper}>
<div className={styles.flexRow}>
<div className={styles.name}>{name}</div>
{isSubscriptionRequired && <ProTag />}
{target === ApplicationType.MachineToMachine && (
<ProTag isVisibleInProdTenant={isSubscriptionRequired} />
)}
</div>
<div className={styles.description} title={description}>
{description}

View file

@ -1,19 +1,25 @@
import classNames from 'classnames';
import { useContext } from 'react';
import { isCloud, isDevFeaturesEnabled } from '@/consts/env';
import { TenantsContext } from '@/contexts/TenantsProvider';
import DynamicT from '@/ds-components/DynamicT';
import * as styles from './index.module.scss';
type Props = {
isVisibleInProdTenant: boolean;
className?: string;
};
function ProTag({ className }: Props) {
return (
function ProTag({ isVisibleInProdTenant, className }: Props) {
const { isDevTenant } = useContext(TenantsContext);
return isCloud && ((isDevFeaturesEnabled && isDevTenant) || isVisibleInProdTenant) ? (
<div className={classNames(styles.tag, className)}>
<DynamicT forKey="upsell.pro_tag" />
</div>
);
) : null;
}
export default ProTag;

View file

@ -0,0 +1,26 @@
import { useContext } from 'react';
import MauExceededModal from '@/components/MauExceededModal';
import PaymentOverdueModal from '@/components/PaymentOverdueModal';
import { isCloud, isDevFeaturesEnabled } from '@/consts/env';
import { TenantsContext } from '@/contexts/TenantsProvider';
function TenantNotificationContainer() {
const { currentTenant, isDevTenant } = useContext(TenantsContext);
const isTenantSuspended = currentTenant?.isSuspended;
// Todo @xiaoyijun remove isDevFeaturesEnabled when the dev tenant feature is ready
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
if (!isCloud || isTenantSuspended || (isDevFeaturesEnabled && isDevTenant)) {
return null;
}
return (
<>
<MauExceededModal />
<PaymentOverdueModal />
</>
);
}
export default TenantNotificationContainer;

View file

@ -3,8 +3,6 @@ import { useContext, useRef } from 'react';
import { Navigate, Outlet, useParams } from 'react-router-dom';
import AppLoading from '@/components/AppLoading';
import MauExceededModal from '@/components/MauExceededModal';
import PaymentOverdueModal from '@/components/PaymentOverdueModal';
import Topbar from '@/components/Topbar';
import { isCloud } from '@/consts/env';
import { TenantsContext } from '@/contexts/TenantsProvider';
@ -14,6 +12,7 @@ import useUserPreferences from '@/hooks/use-user-preferences';
import { getPath } from '../ConsoleContent/Sidebar';
import { useSidebarMenuItems } from '../ConsoleContent/Sidebar/hook';
import TenantNotificationContainer from './TenantNotificationContainer';
import TenantSuspendedPage from './TenantSuspendedPage';
import * as styles from './index.module.scss';
import { type AppContentOutletContext } from './types';
@ -22,7 +21,6 @@ export default function AppContent() {
const { isLoading } = useUserPreferences();
const { currentTenant } = useContext(TenantsContext);
const isTenantSuspended = isCloud && currentTenant?.isSuspended;
const shouldCheckSubscriptionState = isCloud && !currentTenant?.isSuspended;
const scrollableContent = useRef<HTMLDivElement>(null);
const { scrollTop } = useScroll(scrollableContent.current);
@ -40,12 +38,7 @@ export default function AppContent() {
<Outlet context={{ scrollableContent } satisfies AppContentOutletContext} />
)}
</div>
{shouldCheckSubscriptionState && (
<>
<MauExceededModal />
<PaymentOverdueModal />
</>
)}
<TenantNotificationContainer />
</>
);
}

View file

@ -1,3 +1,4 @@
import { useContext } from 'react';
import { Navigate, Route, Routes, useOutletContext } from 'react-router-dom';
import {
@ -10,6 +11,7 @@ import {
ApplicationDetailsTabs,
} from '@/consts';
import { isCloud, isDevFeaturesEnabled } from '@/consts/env';
import { TenantsContext } from '@/contexts/TenantsProvider';
import OverlayScrollbar from '@/ds-components/OverlayScrollbar';
import useUserPreferences from '@/hooks/use-user-preferences';
import ApiResourceDetails from '@/pages/ApiResourceDetails';
@ -67,6 +69,7 @@ function ConsoleContent() {
const {
data: { getStartedHidden },
} = useUserPreferences();
const { isDevTenant } = useContext(TenantsContext);
return (
<div className={styles.content}>
@ -177,8 +180,12 @@ function ConsoleContent() {
<Route index element={<Navigate replace to={TenantSettingsTabs.Settings} />} />
<Route path={TenantSettingsTabs.Settings} element={<TenantBasicSettings />} />
<Route path={TenantSettingsTabs.Domains} element={<TenantDomainSettings />} />
<Route path={TenantSettingsTabs.Subscription} element={<Subscription />} />
<Route path={TenantSettingsTabs.BillingHistory} element={<BillingHistory />} />
{(!isDevFeaturesEnabled || !isDevTenant) && (
<>
<Route path={TenantSettingsTabs.Subscription} element={<Subscription />} />
<Route path={TenantSettingsTabs.BillingHistory} element={<BillingHistory />} />
</>
)}
</Route>
)}
</Routes>

View file

@ -101,7 +101,10 @@ function GuideLibrary({ className, hasCardBorder, hasCardButton, hasFilters }: P
setFilterCategories(sortedValue);
}}
/>
{isM2mDisabledForCurrentPlan && <ProTag className={styles.proTag} />}
<ProTag
className={styles.proTag}
isVisibleInProdTenant={isM2mDisabledForCurrentPlan}
/>
</div>
</div>
</div>

View file

@ -31,7 +31,7 @@ function TypeDescription({
<div className={styles.description}>{description}</div>
{hasProTag && (
<div className={styles.proTag}>
<ProTag />
<ProTag isVisibleInProdTenant />
</div>
)}
</div>

View file

@ -1,4 +1,3 @@
import { conditional } from '@silverhand/essentials';
import { useContext, type ReactNode } from 'react';
import PageMeta from '@/components/PageMeta';
@ -24,7 +23,7 @@ function PageWrapper({ children }: Props) {
<PageMeta titleKey="mfa.title" />
<CardTitle
title="mfa.title"
titleTag={conditional(!isMfaEnabled && <ProTag />)}
titleTag={<ProTag isVisibleInProdTenant={!isMfaEnabled} />}
subtitle="mfa.description"
className={styles.cardTitle}
/>

View file

@ -222,8 +222,12 @@ function CreateRoleForm({ totalRoleCount, onClose }: Props) {
title={<DynamicT forKey={key} />}
value={value}
trailingIcon={
proTagCheck &&
isM2mDisabledForCurrentPlan && <ProTag className={styles.proTag} />
proTagCheck && (
<ProTag
isVisibleInProdTenant={isM2mDisabledForCurrentPlan}
className={styles.proTag}
/>
)
}
/>
))}

View file

@ -47,7 +47,7 @@ function TenantDomainSettings() {
<PageMeta titleKey={['tenants.tabs.domains', 'tenants.title']} />
<FormCard
title="domain.custom.custom_domain"
tag={!customDomainEnabled && <ProTag />}
tag={<ProTag isVisibleInProdTenant={!customDomainEnabled} />}
description="domain.custom.custom_domain_description"
learnMoreLink={getDocumentationUrl('docs/recipes/custom-domain')}
>

View file

@ -1,6 +1,9 @@
import { useContext } from 'react';
import { Outlet } from 'react-router-dom';
import { TenantSettingsTabs } from '@/consts';
import { isDevFeaturesEnabled } from '@/consts/env';
import { TenantsContext } from '@/contexts/TenantsProvider';
import CardTitle from '@/ds-components/CardTitle';
import DynamicT from '@/ds-components/DynamicT';
import TabNav, { TabNavItem } from '@/ds-components/TabNav';
@ -8,6 +11,7 @@ import TabNav, { TabNavItem } from '@/ds-components/TabNav';
import * as styles from './index.module.scss';
function TenantSettings() {
const { isDevTenant } = useContext(TenantsContext);
return (
<div className={styles.container}>
<CardTitle
@ -22,12 +26,16 @@ function TenantSettings() {
<TabNavItem href={`/tenant-settings/${TenantSettingsTabs.Domains}`}>
<DynamicT forKey="tenants.tabs.domains" />
</TabNavItem>
<TabNavItem href={`/tenant-settings/${TenantSettingsTabs.Subscription}`}>
<DynamicT forKey="tenants.tabs.subscription" />
</TabNavItem>
<TabNavItem href={`/tenant-settings/${TenantSettingsTabs.BillingHistory}`}>
<DynamicT forKey="tenants.tabs.billing_history" />
</TabNavItem>
{(!isDevFeaturesEnabled || !isDevTenant) && (
<>
<TabNavItem href={`/tenant-settings/${TenantSettingsTabs.Subscription}`}>
<DynamicT forKey="tenants.tabs.subscription" />
</TabNavItem>
<TabNavItem href={`/tenant-settings/${TenantSettingsTabs.BillingHistory}`}>
<DynamicT forKey="tenants.tabs.billing_history" />
</TabNavItem>
</>
)}
</TabNav>
<Outlet />
</div>