diff --git a/frontend/src/assets/icons/pro-enterprise-feature-badge-light.svg b/frontend/src/assets/icons/pro-enterprise-feature-badge-light.svg index 0ff76c4709..9e21640ef0 100644 --- a/frontend/src/assets/icons/pro-enterprise-feature-badge-light.svg +++ b/frontend/src/assets/icons/pro-enterprise-feature-badge-light.svg @@ -1 +1,6 @@ - \ No newline at end of file + + + + diff --git a/frontend/src/assets/icons/pro-enterprise-feature-badge.svg b/frontend/src/assets/icons/pro-enterprise-feature-badge.svg index c180559714..46d73998ba 100644 --- a/frontend/src/assets/icons/pro-enterprise-feature-badge.svg +++ b/frontend/src/assets/icons/pro-enterprise-feature-badge.svg @@ -1,5 +1,7 @@ - - - + + + diff --git a/frontend/src/component/admin/Admin.tsx b/frontend/src/component/admin/Admin.tsx index f8dfb87bb5..be65ada320 100644 --- a/frontend/src/component/admin/Admin.tsx +++ b/frontend/src/component/admin/Admin.tsx @@ -20,8 +20,8 @@ import CreateUser from './users/CreateUser/CreateUser'; import EditUser from './users/EditUser/EditUser'; import { InviteLink } from './users/InviteLink/InviteLink'; import UsersAdmin from './users/UsersAdmin'; -import { EnterpriseFeatureUpgradePage } from 'component/common/EnterpriseFeatureUpgradePage/EnterpriseFeatureUpgradePage'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; +import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature'; export const Admin = () => { const { isEnterprise } = useUiConfig(); @@ -40,10 +40,7 @@ export const Admin = () => { isEnterprise() ? ( ) : ( - + ) } /> @@ -62,10 +59,7 @@ export const Admin = () => { isEnterprise() ? ( ) : ( - + ) } /> diff --git a/frontend/src/component/admin/menu/AdminTabsMenu.tsx b/frontend/src/component/admin/menu/AdminTabsMenu.tsx index 47663bf3f9..ab482bfc0b 100644 --- a/frontend/src/component/admin/menu/AdminTabsMenu.tsx +++ b/frontend/src/component/admin/menu/AdminTabsMenu.tsx @@ -1,5 +1,5 @@ import { useLocation } from 'react-router-dom'; -import { Box, Paper, styled, Tab, Tabs } from '@mui/material'; +import { Paper, styled, Tab, Tabs } from '@mui/material'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import { useInstanceStatus } from 'hooks/api/getters/useInstanceStatus/useInstanceStatus'; import { CenteredNavLink } from './CenteredNavLink'; @@ -43,7 +43,7 @@ export const AdminTabsMenu: VFC = () => { link: '/admin/service-accounts', condition: isEnterprise() || (isPro() && showEnterpriseFeaturesInPro), - showEnterpriseBadge: true, + showEnterpriseBadge: isPro(), }, { value: 'groups', @@ -57,7 +57,7 @@ export const AdminTabsMenu: VFC = () => { link: '/admin/roles', condition: isEnterprise() || (isPro() && showEnterpriseFeaturesInPro), - showEnterpriseBadge: true, + showEnterpriseBadge: isPro(), }, { value: 'api', diff --git a/frontend/src/component/common/BreadcrumbNav/BreadcrumbNav.tsx b/frontend/src/component/common/BreadcrumbNav/BreadcrumbNav.tsx index dc60d88274..01469ee457 100644 --- a/frontend/src/component/common/BreadcrumbNav/BreadcrumbNav.tsx +++ b/frontend/src/component/common/BreadcrumbNav/BreadcrumbNav.tsx @@ -83,6 +83,14 @@ const BreadcrumbNav = () => { } }); + if (index === 0 && path === 'admin') { + return ( + + {path} + + ); + } + return ( diff --git a/frontend/src/component/common/EnterpriseFeatureUpgradePage/EnterpriseFeatureUpgradePage.tsx b/frontend/src/component/common/EnterpriseFeatureUpgradePage/EnterpriseFeatureUpgradePage.tsx deleted file mode 100644 index 75aa26b91d..0000000000 --- a/frontend/src/component/common/EnterpriseFeatureUpgradePage/EnterpriseFeatureUpgradePage.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { VFC } from 'react'; -import { Box, Button, Typography, styled } from '@mui/material'; -import { EnterpriseBadge } from 'component/common/EnterpriseBadge/EnterpriseBadge'; -import { PageContent } from '../PageContent/PageContent'; -import { PageHeader } from '../PageHeader/PageHeader'; - -type EnterpriseFeatureUpgradePageProps = { - title: string; - link: string; -}; - -const StyledContainer = styled(Box)(({ theme }) => ({ - background: theme.palette.background.elevation2, - padding: theme.spacing(8, 2), - borderRadius: `${theme.shape.borderRadiusMedium}px`, - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - textAlign: 'center', -})); - -const StyledHeader = styled(Typography)(({ theme }) => ({ - marginBottom: theme.spacing(3), - display: 'flex', - alignItems: 'center', -})); - -const StyledBadgeContainer = styled('div')(({ theme }) => ({ - paddingRight: theme.spacing(1), - display: 'flex', - alignItems: 'center', -})); - -export const EnterpriseFeatureUpgradePage: VFC< - EnterpriseFeatureUpgradePageProps -> = ({ title, link }) => ( - }> - - - - - - Enterprise feature - - - {title} is a feature available for the - Enterprise plan. - - - You need to upgrade your plan if you want to use it. - - - - -); diff --git a/frontend/src/component/common/PremiumFeature/PremiumFeature.tsx b/frontend/src/component/common/PremiumFeature/PremiumFeature.tsx index 7259140ebc..4f4d08c31a 100644 --- a/frontend/src/component/common/PremiumFeature/PremiumFeature.tsx +++ b/frontend/src/component/common/PremiumFeature/PremiumFeature.tsx @@ -4,6 +4,8 @@ import { Box, Button, Link, styled, Typography } from '@mui/material'; import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender'; import { ThemeMode } from '../ThemeMode/ThemeMode'; +import { PageContent } from '../PageContent/PageContent'; +import { PageHeader } from '../PageHeader/PageHeader'; const PremiumFeatureWrapper = styled(Box, { shouldForwardProp: prop => prop !== 'tooltip', @@ -70,6 +72,21 @@ const PremiumFeatures = { url: 'https://docs.getunleash.io/reference/segments', label: 'Segments', }, + 'service-accounts': { + plan: FeaturePlan.ENTERPRISE, + url: 'https://docs.getunleash.io/reference/service-accounts', + label: 'Service Accounts', + }, + 'project-roles': { + plan: FeaturePlan.ENTERPRISE, + url: 'https://docs.getunleash.io/reference/rbac#custom-project-roles', + label: 'Project Roles', + }, + 'login-history': { + plan: FeaturePlan.ENTERPRISE, + url: 'https://docs.getunleash.io/reference/login-history', + label: 'Login history', + }, }; type PremiumFeatureType = keyof typeof PremiumFeatures; @@ -79,9 +96,14 @@ const UPGRADE_URL = 'https://www.getunleash.io/plans'; export interface PremiumFeatureProps { feature: PremiumFeatureType; tooltip?: boolean; + page?: boolean; } -export const PremiumFeature = ({ feature, tooltip }: PremiumFeatureProps) => { +export const PremiumFeature = ({ + feature, + tooltip, + page, +}: PremiumFeatureProps) => { const { url, plan, label } = PremiumFeatures[feature]; const tracker = usePlausibleTracker(); @@ -110,7 +132,7 @@ export const PremiumFeature = ({ feature, tooltip }: PremiumFeatureProps) => { const upgradeUrl = `${UPGRADE_URL}?feature=${feature}`; - return ( + const content = ( { /> ); + + if (page) { + return ( + }> + {content} + + ); + } + + return content; }; diff --git a/frontend/src/component/common/VerticalTabs/VerticalTab/VerticalTab.tsx b/frontend/src/component/common/VerticalTabs/VerticalTab/VerticalTab.tsx index ec86900ea6..aad19ad56c 100644 --- a/frontend/src/component/common/VerticalTabs/VerticalTab/VerticalTab.tsx +++ b/frontend/src/component/common/VerticalTabs/VerticalTab/VerticalTab.tsx @@ -45,12 +45,14 @@ interface IVerticalTabProps { label: string; selected?: boolean; onClick: () => void; + icon?: React.ReactNode; } export const VerticalTab = ({ label, selected, onClick, + icon, }: IVerticalTabProps) => ( {label} + {icon} ); diff --git a/frontend/src/component/common/VerticalTabs/VerticalTabs.tsx b/frontend/src/component/common/VerticalTabs/VerticalTabs.tsx index f321812748..bc4e03a20a 100644 --- a/frontend/src/component/common/VerticalTabs/VerticalTabs.tsx +++ b/frontend/src/component/common/VerticalTabs/VerticalTabs.tsx @@ -31,6 +31,7 @@ export interface ITab { label: string; path?: string; hidden?: boolean; + icon?: React.ReactNode; } interface IVerticalTabsProps { @@ -56,6 +57,7 @@ export const VerticalTabs = ({ label={tab.label} selected={tab.id === value} onClick={() => onChange(tab)} + icon={tab.icon} /> ))} diff --git a/frontend/src/component/loginHistory/LoginHistory.tsx b/frontend/src/component/loginHistory/LoginHistory.tsx index f1ce9f1a78..07f59f1be8 100644 --- a/frontend/src/component/loginHistory/LoginHistory.tsx +++ b/frontend/src/component/loginHistory/LoginHistory.tsx @@ -2,18 +2,13 @@ import { ADMIN } from 'component/providers/AccessProvider/permissions'; import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuard'; import { LoginHistoryTable } from './LoginHistoryTable/LoginHistoryTable'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; -import { EnterpriseFeatureUpgradePage } from 'component/common/EnterpriseFeatureUpgradePage/EnterpriseFeatureUpgradePage'; +import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature'; export const LoginHistory = () => { const { isEnterprise } = useUiConfig(); if (!isEnterprise()) { - return ( - - ); + return ; } return ( diff --git a/frontend/src/component/menu/Header/DrawerMenu/DrawerMenu.tsx b/frontend/src/component/menu/Header/DrawerMenu/DrawerMenu.tsx index 782b59d14c..1d773ef187 100644 --- a/frontend/src/component/menu/Header/DrawerMenu/DrawerMenu.tsx +++ b/frontend/src/component/menu/Header/DrawerMenu/DrawerMenu.tsx @@ -121,6 +121,7 @@ export const DrawerMenu: VFC = ({ path={item.path} text={item.title} key={item.path} + mode={item.menu?.mode} /> ))} diff --git a/frontend/src/component/menu/Header/Header.tsx b/frontend/src/component/menu/Header/Header.tsx index a8f1f338c6..44e6ff48d3 100644 --- a/frontend/src/component/menu/Header/Header.tsx +++ b/frontend/src/component/menu/Header/Header.tsx @@ -38,6 +38,8 @@ import { INavigationMenuItem } from 'interfaces/route'; import { ThemeMode } from 'component/common/ThemeMode/ThemeMode'; import { useThemeMode } from 'hooks/useThemeMode'; import { Notifications } from 'component/common/Notifications/Notifications'; +import { filterAdminRoutes } from './filterAdminRoutes'; +import { useInstanceStatus } from 'hooks/api/getters/useInstanceStatus/useInstanceStatus'; const StyledHeader = styled(AppBar)(({ theme }) => ({ backgroundColor: theme.palette.background.paper, @@ -121,9 +123,13 @@ const Header: VFC = () => { const [configRef, setConfigRef] = useState(null); const { uiConfig, isOss, isPro, isEnterprise } = useUiConfig(); + const { isBilling } = useInstanceStatus(); const smallScreen = useMediaQuery(theme.breakpoints.down('md')); const [openDrawer, setOpenDrawer] = useState(false); const showApiAccessInConfigure = !uiConfig?.flags?.frontendNavigationUpdate; + const showEnterpriseOptionsInPro = Boolean( + uiConfig?.flags?.frontendNavigationUpdate + ); const toggleDrawer = () => setOpenDrawer(prev => !prev); const onAdminClose = () => setAdminRef(null); @@ -131,26 +137,6 @@ const Header: VFC = () => { const routes = getRoutes(); - const filterByMode = (route: INavigationMenuItem): boolean => { - const { mode, showEnterpriseBadge } = route.menu; - - if (!mode) return true; - - if (isPro()) { - return ( - mode.includes('pro') || - (mode.includes('enterprise') && showEnterpriseBadge) || - false - ); - } - - if (isEnterprise()) { - return mode.includes('enterprise'); - } - - return false; - }; - const filteredMainRoutes = { mainNavRoutes: getCondensedRoutes(routes.mainNavRoutes) .concat( @@ -182,7 +168,17 @@ const Header: VFC = () => { .map(mapRouteLink), adminRoutes: adminMenuRoutes .filter(filterByConfig(uiConfig)) - .filter(filterByMode) + .filter(route => + filterAdminRoutes( + route?.menu, + { + enterprise: isEnterprise(), + pro: isPro(), + billing: isBilling, + }, + showEnterpriseOptionsInPro + ) + ) .map(mapRouteLink), }; diff --git a/frontend/src/component/menu/Header/NavigationLink/NavigationLink.tsx b/frontend/src/component/menu/Header/NavigationLink/NavigationLink.tsx index eaef608871..349275f928 100644 --- a/frontend/src/component/menu/Header/NavigationLink/NavigationLink.tsx +++ b/frontend/src/component/menu/Header/NavigationLink/NavigationLink.tsx @@ -1,9 +1,14 @@ import { ListItem, Link, styled } from '@mui/material'; +import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; +import { EnterpriseBadge } from 'component/common/EnterpriseBadge/EnterpriseBadge'; +import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; +import { INavigationMenuItem } from 'interfaces/route'; import { Link as RouterLink } from 'react-router-dom'; interface INavigationLinkProps { path: string; text: string; handleClose: () => void; + mode?: INavigationMenuItem['menu']['mode']; } const StyledListItem = styled(ListItem)({ @@ -37,7 +42,25 @@ const StyledSpan = styled('span')(({ theme }) => ({ borderRadius: '2px', })); -const NavigationLink = ({ path, text, handleClose }: INavigationLinkProps) => { +const StyledBadgeContainer = styled('div')(({ theme }) => ({ + marginLeft: 'auto', + paddingLeft: theme.spacing(2), + display: 'flex', +})); + +const NavigationLink = ({ + path, + text, + handleClose, + ...props +}: INavigationLinkProps) => { + const { uiConfig, isPro } = useUiConfig(); + const showEnterpriseBadgeToPro = Boolean( + uiConfig?.flags?.frontendNavigationUpdate && + isPro() && + props.mode?.includes('enterprise') + ); + return ( { @@ -52,6 +75,15 @@ const NavigationLink = ({ path, text, handleClose }: INavigationLinkProps) => { > {text} + + + + + } + /> ); diff --git a/frontend/src/component/menu/Header/NavigationMenu/NavigationMenu.tsx b/frontend/src/component/menu/Header/NavigationMenu/NavigationMenu.tsx index 8ad66515b3..0fe73ba8cc 100644 --- a/frontend/src/component/menu/Header/NavigationMenu/NavigationMenu.tsx +++ b/frontend/src/component/menu/Header/NavigationMenu/NavigationMenu.tsx @@ -5,6 +5,7 @@ import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import { INavigationMenuItem } from 'interfaces/route'; import { Link } from 'react-router-dom'; import { EnterpriseBadge } from '../../../common/EnterpriseBadge/EnterpriseBadge'; +import { useCallback } from 'react'; interface INavigationMenuProps { options: INavigationMenuItem[]; @@ -49,9 +50,25 @@ export const NavigationMenu = ({ anchorEl, style, }: INavigationMenuProps) => { - const { uiConfig } = useUiConfig(); + const { uiConfig, isPro } = useUiConfig(); const showUpdatedMenu = uiConfig?.flags?.frontendNavigationUpdate; + const showBadge = useCallback( + (mode?: INavigationMenuItem['menu']['mode']) => { + if ( + isPro() && + !mode?.includes('pro') && + mode?.includes('enterprise') && + showUpdatedMenu + ) { + return true; + } + + return false; + }, + [isPro, showUpdatedMenu] + ); + return ( {options - .map((option, i) => [ - } - elseShow={null} - />, - - - {option.title} - - - - } - /> - , - ]) + .map((option, i) => { + const previousGroup = options[i - 1]?.group; + const addDivider = + showUpdatedMenu && + previousGroup && + previousGroup !== option.group; + + return [ + addDivider ? ( + + ) : null, + + + {option.title} + + + + } + /> + , + ]; + }) .flat() .filter(Boolean)} diff --git a/frontend/src/component/menu/Header/filterAdminRoutes.test.ts b/frontend/src/component/menu/Header/filterAdminRoutes.test.ts new file mode 100644 index 0000000000..d74e5df1bd --- /dev/null +++ b/frontend/src/component/menu/Header/filterAdminRoutes.test.ts @@ -0,0 +1,103 @@ +import { filterAdminRoutes } from './filterAdminRoutes'; + +describe('filterAdminRoutes - open souce routes', () => { + test('open source - should show menu item if mode paid plan mode is not defined', () => { + expect( + filterAdminRoutes( + {}, + { + pro: false, + enterprise: false, + billing: false, + } + ) + ).toBe(true); + }); + + test('open source - should not show menu item from paid plans', () => { + const state = { + pro: false, + enterprise: false, + billing: false, + }; + + expect(filterAdminRoutes({ mode: ['pro'] }, state)).toBe(false); + expect(filterAdminRoutes({ mode: ['enterprise'] }, state)).toBe(false); + expect(filterAdminRoutes({ mode: ['pro', 'enterprise'] }, state)).toBe( + false + ); + expect(filterAdminRoutes({ billing: true }, state)).toBe(false); + }); + + test('pro - should show menu item for pro customers', () => { + const state = { + pro: true, + enterprise: false, + billing: false, + }; + + expect(filterAdminRoutes({ mode: ['pro'] }, state)).toBe(true); + expect(filterAdminRoutes({ mode: ['pro', 'enterprise'] }, state)).toBe( + true + ); + // This is to show enterprise badge in pro mode + expect(filterAdminRoutes({ mode: ['enterprise'] }, state)).toBe(true); + }); + + test('enterprise - should show menu item if mode enterprise is defined or mode is undefined', () => { + const state = { + pro: false, + enterprise: true, + billing: false, + }; + + expect(filterAdminRoutes({ mode: ['enterprise'] }, state)).toBe(true); + expect(filterAdminRoutes({ mode: ['pro', 'enterprise'] }, state)).toBe( + true + ); + expect(filterAdminRoutes({ mode: ['pro'] }, state)).toBe(false); + }); + + test('billing - should show menu item if billing is defined', () => { + expect( + filterAdminRoutes( + { mode: ['pro'], billing: true }, + { + pro: true, + enterprise: false, + billing: true, + } + ) + ).toBe(true); + expect( + filterAdminRoutes( + { mode: ['enterprise'], billing: true }, + { + pro: false, + enterprise: true, + billing: true, + } + ) + ).toBe(true); + expect( + filterAdminRoutes( + { mode: ['pro', 'enterprise'], billing: true }, + { + pro: true, + enterprise: false, + billing: true, + } + ) + ).toBe(true); + expect( + filterAdminRoutes( + { mode: ['pro'], billing: true }, + { + pro: false, + enterprise: false, + billing: true, + } + ) + ).toBe(false); + }); +}); diff --git a/frontend/src/component/menu/Header/filterAdminRoutes.ts b/frontend/src/component/menu/Header/filterAdminRoutes.ts new file mode 100644 index 0000000000..0caaf29150 --- /dev/null +++ b/frontend/src/component/menu/Header/filterAdminRoutes.ts @@ -0,0 +1,34 @@ +import { INavigationMenuItem } from 'interfaces/route'; + +export const filterAdminRoutes = ( + menu: INavigationMenuItem['menu'], + { + pro, + enterprise, + billing, + }: { pro?: boolean; enterprise?: boolean; billing?: boolean }, + showEnterpriseOptionsInPro = true +): boolean => { + const mode = menu?.mode; + if (menu?.billing && !billing) return false; + + if (!mode || mode.length === 0) { + return true; + } + + if (pro) { + if (mode.includes('pro')) { + return true; + } + + if (showEnterpriseOptionsInPro && mode.includes('enterprise')) { + return true; + } + } + + if (enterprise && mode.includes('enterprise')) { + return true; + } + + return false; +}; diff --git a/frontend/src/component/menu/routes.ts b/frontend/src/component/menu/routes.ts index 96095573f0..7fc5c341a3 100644 --- a/frontend/src/component/menu/routes.ts +++ b/frontend/src/component/menu/routes.ts @@ -465,7 +465,6 @@ export const adminMenuRoutes: INavigationMenuItem[] = [ menu: { adminSettings: true, mode: ['enterprise'], - showEnterpriseBadge: true, }, group: 'users', }, @@ -475,7 +474,6 @@ export const adminMenuRoutes: INavigationMenuItem[] = [ menu: { adminSettings: true, mode: ['enterprise'], - showEnterpriseBadge: true, }, flag: UG, group: 'users', @@ -486,7 +484,6 @@ export const adminMenuRoutes: INavigationMenuItem[] = [ menu: { adminSettings: true, mode: ['enterprise'], - showEnterpriseBadge: true, }, group: 'users', }, @@ -538,7 +535,7 @@ export const adminMenuRoutes: INavigationMenuItem[] = [ { path: '/admin/admin-invoices', title: 'Billing & invoices', - menu: { adminSettings: true, mode: ['pro'] }, + menu: { adminSettings: true, mode: ['pro'], billing: true }, group: 'instance', }, { @@ -547,7 +544,6 @@ export const adminMenuRoutes: INavigationMenuItem[] = [ menu: { adminSettings: true, mode: ['enterprise'], - showEnterpriseBadge: true, }, group: 'log', }, diff --git a/frontend/src/component/project/Project/Project.tsx b/frontend/src/component/project/Project/Project.tsx index f2b3704992..5b5e050696 100644 --- a/frontend/src/component/project/Project/Project.tsx +++ b/frontend/src/component/project/Project/Project.tsx @@ -14,7 +14,7 @@ import { StyledTabContainer, StyledTopRow, } from './Project.styles'; -import { Paper, Tabs, Typography } from '@mui/material'; +import { Box, Paper, Tabs, Typography } from '@mui/material'; import { Delete, Edit, FileUpload } from '@mui/icons-material'; import useToast from 'hooks/useToast'; import useQueryParams from 'hooks/useQueryParams'; @@ -40,6 +40,7 @@ import { ProjectSettings } from './ProjectSettings/ProjectSettings'; import { useFavoriteProjectsApi } from 'hooks/api/actions/useFavoriteProjectsApi/useFavoriteProjectsApi'; import { ImportModal } from './Import/ImportModal'; import { IMPORT_BUTTON } from 'utils/testIds'; +import { EnterpriseBadge } from 'component/common/EnterpriseBadge/EnterpriseBadge'; const NAVIGATE_TO_EDIT_PROJECT = 'NAVIGATE_TO_EDIT_PROJECT'; @@ -52,13 +53,15 @@ export const Project = () => { const [modalOpen, setModalOpen] = useState(false); const navigate = useNavigate(); const { pathname } = useLocation(); - const { isOss, uiConfig } = useUiConfig(); + const { isOss, uiConfig, isPro } = useUiConfig(); const basePath = `/projects/${projectId}`; const projectName = project?.name || projectId; const { favorite, unfavorite } = useFavoriteProjectsApi(); const [showDelDialog, setShowDelDialog] = useState(false); + const updatedNavigation = uiConfig?.flags?.frontendNavigationUpdate; + const tabs = [ { title: 'Overview', @@ -79,18 +82,34 @@ export const Project = () => { title: 'Change requests', path: `${basePath}/change-requests`, name: 'change-request', + isEnterprise: true, }, - { - title: 'Project settings', - path: `${basePath}/settings`, - name: 'settings', - }, - { - title: 'Event log', - path: `${basePath}/logs`, - name: 'logs', - }, - ]; + ...(updatedNavigation + ? [ + { + title: 'Event log', + path: `${basePath}/logs`, + name: 'logs', + }, + { + title: 'Project settings', + path: `${basePath}/settings`, + name: 'settings', + }, + ] + : [ + { + title: 'Project settings', + path: `${basePath}/settings`, + name: 'settings', + }, + { + title: 'Event log', + path: `${basePath}/logs`, + name: 'logs', + }, + ]), + ].filter(tab => !updatedNavigation || !(isOss() && tab.isEnterprise)); const activeTab = [...tabs] .reverse() @@ -130,6 +149,17 @@ export const Project = () => { refetch(); }; + const enterpriseIcon = ( + ({ + marginLeft: theme.spacing(1), + display: 'flex', + })} + > + + + ); + return (
@@ -227,6 +257,16 @@ export const Project = () => { value={tab.path} onClick={() => navigate(tab.path)} data-testid={`TAB_${tab.title}`} + iconPosition={ + tab.isEnterprise ? 'end' : undefined + } + icon={ + tab.isEnterprise && + isPro() && + updatedNavigation + ? enterpriseIcon + : undefined + } /> ))} diff --git a/frontend/src/component/project/Project/ProjectSettings/ProjectSettings.tsx b/frontend/src/component/project/Project/ProjectSettings/ProjectSettings.tsx index a484abb09a..f30ba76097 100644 --- a/frontend/src/component/project/Project/ProjectSettings/ProjectSettings.tsx +++ b/frontend/src/component/project/Project/ProjectSettings/ProjectSettings.tsx @@ -14,12 +14,16 @@ import { ProjectSegments } from './ProjectSegments/ProjectSegments'; import { ProjectDefaultStrategySettings } from './ProjectDefaultStrategySettings/ProjectDefaultStrategySettings'; import { Settings } from './Settings/Settings'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; +import { EnterpriseBadge } from 'component/common/EnterpriseBadge/EnterpriseBadge'; +import { Box } from '@mui/material'; export const ProjectSettings = () => { const location = useLocation(); - const { uiConfig } = useUiConfig(); + const { uiConfig, isPro, isEnterprise } = useUiConfig(); const navigate = useNavigate(); + const updatedNavigation = uiConfig.flags?.frontendNavigationUpdate; + const tabs: ITab[] = [ ...(uiConfig.flags.newProjectLayout ? [ @@ -33,18 +37,28 @@ export const ProjectSettings = () => { id: 'environments', label: 'Environments', }, - { - id: 'access', - label: 'Access', - }, - { - id: 'segments', - label: 'Segments', - }, - { - id: 'change-requests', - label: 'Change request configuration', - }, + ...(!updatedNavigation || isPro() || isEnterprise() + ? [ + { + id: 'access', + label: 'Access', + }, + { + id: 'segments', + label: 'Segments', + }, + { + id: 'change-requests', + label: 'Change request configuration', + icon: + isPro() && updatedNavigation ? ( + + + + ) : undefined, + }, + ] + : []), { id: 'api-access', label: 'API access', diff --git a/frontend/src/interfaces/route.ts b/frontend/src/interfaces/route.ts index 772a2096b5..8755f81553 100644 --- a/frontend/src/interfaces/route.ts +++ b/frontend/src/interfaces/route.ts @@ -30,5 +30,5 @@ interface IRouteMenu { advanced?: boolean; adminSettings?: boolean; mode?: Array<'pro' | 'enterprise'>; - showEnterpriseBadge?: boolean; + billing?: boolean; }