Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Web] Implement basic sidenav #46334

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 18 additions & 35 deletions web/packages/teleport/src/Main/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,21 @@ import React, {
useState,
} from 'react';
import styled from 'styled-components';
import { Box, Indicator } from 'design';
import { Box, Flex, Indicator } from 'design';
import { Failed } from 'design/CardError';

import useAttempt from 'shared/hooks/useAttemptNext';

import { matchPath, useHistory } from 'react-router';

import Dialog from 'design/Dialog';
import { sharedStyles } from 'design/theme/themes/sharedStyles';

import { Redirect, Route, Switch } from 'teleport/components/Router';
import { CatchError } from 'teleport/components/CatchError';
import cfg from 'teleport/config';
import useTeleport from 'teleport/useTeleport';
import { TopBar } from 'teleport/TopBar';
import { TopBar as TopBarSideNav } from 'teleport/TopBar/TopBarSideNav';
import { BannerList } from 'teleport/components/BannerList';
import { storageService } from 'teleport/services/storageService';
import {
Expand All @@ -51,11 +51,9 @@ import {
} from 'teleport/services/alerts/alerts';
import { useAlerts } from 'teleport/components/BannerList/useAlerts';
import { FeaturesContextProvider, useFeatures } from 'teleport/FeaturesContext';
import {
getFirstRouteForCategory,
Navigation,
} from 'teleport/Navigation/Navigation';
import { NavigationCategory } from 'teleport/Navigation/categories';

import { Navigation as SideNavigation } from 'teleport/Navigation/SideNavigation/Navigation';
import { Navigation } from 'teleport/Navigation';
import { TopBarProps } from 'teleport/TopBar/TopBar';
import { useUser } from 'teleport/User/UserContext';
import { QuestionnaireProps } from 'teleport/Welcome/NewCredentials';
Expand Down Expand Up @@ -84,6 +82,10 @@ export function Main(props: MainProps) {

const { preferences } = useUser();

const isTopBarView = storageService.getIsTopBarView();
const TopBarComponent = isTopBarView ? TopBar : TopBarSideNav;
const NavigationComponent = isTopBarView ? Navigation : SideNavigation;

useEffect(() => {
if (ctx.storeUser.state) {
setAttempt({ status: 'success' });
Expand All @@ -99,14 +101,6 @@ export function Main(props: MainProps) {
() => props.features.filter(feature => feature.hasAccess(featureFlags)),
[featureFlags, props.features]
);
const feature = features
.filter(feature => Boolean(feature.route))
.find(f =>
matchPath(history.location.pathname, {
path: f.route.path,
exact: f.route.exact ?? false,
})
);

const { alerts, dismissAlert } = useAlerts(props.initialAlerts);

Expand Down Expand Up @@ -168,7 +162,7 @@ export function Main(props: MainProps) {

const indexRoute = cfg.isDashboard
? cfg.routes.downloadCenter
: getFirstRouteForCategory(features, NavigationCategory.Resources);
: cfg.getUnifiedResourcesRoute(cfg.proxyCluster);

return <Redirect to={indexRoute} />;
}
Expand Down Expand Up @@ -197,13 +191,10 @@ export function Main(props: MainProps) {
const requiresOnboarding =
onboard && !onboard.hasResource && !onboard.notified;
const displayOnboardDiscover = requiresOnboarding && showOnboardDiscover;
const hasSidebar =
feature?.category === NavigationCategory.Management &&
!feature?.hideNavigation;

return (
<FeaturesContextProvider value={features}>
<TopBar
<TopBarComponent
CustomLogo={
props.topBarProps?.showPoweredByLogo
? props.topBarProps.CustomLogo
Expand All @@ -212,8 +203,8 @@ export function Main(props: MainProps) {
/>
<Wrapper>
<MainContainer>
<Navigation />
<HorizontalSplit hasSidebar={hasSidebar}>
<NavigationComponent />
<ContentWrapper>
<ContentMinWidth>
<BannerList
banners={banners}
Expand All @@ -225,7 +216,7 @@ export function Main(props: MainProps) {
<FeatureRoutes lockedFeatures={ctx.lockedFeatures} />
</Suspense>
</ContentMinWidth>
</HorizontalSplit>
</ContentWrapper>
</MainContainer>
</Wrapper>
{displayOnboardDiscover && (
Expand Down Expand Up @@ -351,23 +342,15 @@ export const ContentMinWidth = ({ children }: { children: ReactNode }) => {
);
};

function getWidth(hasSidebar?: boolean) {
const { sidebarWidth } = sharedStyles;
if (hasSidebar) {
return `max-width: calc(100% - ${sidebarWidth}px);`;
}
return 'max-width: 100%;';
}

export const HorizontalSplit = styled.div<{ hasSidebar?: boolean }>`
export const ContentWrapper = styled.div`
display: flex;
flex-direction: column;
flex: 1;
${props => getWidth(props.hasSidebar)}
overflow-x: auto;
max-width: 100%;
`;

export const StyledIndicator = styled(HorizontalSplit)`
export const StyledIndicator = styled(Flex)`
align-items: center;
justify-content: center;
position: absolute;
Expand All @@ -380,5 +363,5 @@ const Wrapper = styled(Box)`
display: flex;
height: 100vh;
flex-direction: column;
width: 100vw;
max-width: 100vw;
`;
3 changes: 2 additions & 1 deletion web/packages/teleport/src/Main/MainContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ import styled from 'styled-components';
export const MainContainer = styled.div`
display: flex;
flex: 1;
min-height: 0;
--sidebar-width: 256px;
--sidenav-width: 76px;
--sidenav-panel-width: 224px;
margin-top: ${p => p.theme.topBarHeight[0]}px;
@media screen and (min-width: ${p => p.theme.breakpoints.small}px) {
margin-top: ${p => p.theme.topBarHeight[1]}px;
Expand Down
2 changes: 1 addition & 1 deletion web/packages/teleport/src/Main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

export { zIndexMap } from './zIndexMap';
export {
Main,
useContentMinWidthContext,
useNoMinWidth,
HorizontalSplit,
StyledIndicator,
} from './Main';
export { MainContainer } from './MainContainer';
23 changes: 23 additions & 0 deletions web/packages/teleport/src/Main/zIndexMap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

export const zIndexMap = {
topBar: 22,
sideNavContainer: 21,
sideNavExpandedPanel: 20,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import React from 'react';

import * as Icons from 'design/Icon';

import { NavigationCategory } from './categories';

export function CategoryIcon({ category }: { category: NavigationCategory }) {
switch (category) {
case NavigationCategory.Resources:
return <Icons.Server />;
case NavigationCategory.Access:
return <Icons.Lock />;
case NavigationCategory.Identity:
return <Icons.FingerprintSimple />;
case NavigationCategory.Policy:
return <Icons.ShieldCheck />;
case NavigationCategory.Audit:
return <Icons.ListMagnifyingGlass />;
case NavigationCategory.AddNew:
return <Icons.AddCircle />;
default:
return null;
}
}
Loading
Loading