Skip to content
This repository has been archived by the owner on Feb 8, 2024. It is now read-only.

Commit

Permalink
[v10] Add BannerList and Banner components to display cluster alerts …
Browse files Browse the repository at this point in the history
…on load (#1169) (#1199)

* Add BannerList and Banner components to display cluster alerts on load (#1169)

* Add BannerList and Banner components.

* Update e

* bump e
  • Loading branch information
hatched authored Sep 22, 2022
1 parent 5780233 commit 4ec6eb2
Show file tree
Hide file tree
Showing 21 changed files with 806 additions and 86 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
"private": true,
"resolutions": {
"**/minimist": "^1.2.5",
"**/node-gyp": "8.4.1"
"**/node-gyp": "8.4.1",
"**/@types/react": "^16.8.19"
},
"workspaces": {
"packages": [
Expand Down
1 change: 1 addition & 0 deletions packages/build/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@storybook/react": "^6.4.0",
"@testing-library/jest-dom": "^5.15.1",
"@testing-library/react": "^12.1.2",
"@testing-library/react-hooks": "^8.0.1",
"@types/jest": "^27.3.1",
"@types/lodash": "4.14.149",
"@types/node": "^16.11.10",
Expand Down
126 changes: 73 additions & 53 deletions packages/teleport/src/Discover/Discover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ import useTeleport from 'teleport/useTeleport';
import getFeatures from 'teleport/features';
import { UserMenuNav } from 'teleport/components/UserMenuNav';
import * as main from 'teleport/Main';
import { MainContainer } from 'teleport/Main/MainContainer';
import * as sideNav from 'teleport/SideNav';
import { TopBarContainer } from 'teleport/TopBar';
import { FeatureBox } from 'teleport/components/Layout';
import { BannerList } from 'teleport/components/BannerList';
import cfg from 'teleport/config';

import { useDiscover, State } from './useDiscover';
Expand All @@ -40,6 +42,7 @@ import { Finished } from './Finished';

import type { AgentKind } from './useDiscover';
import type { AgentStepComponent } from './types';
import type { BannerType } from 'teleport/components/BannerList/BannerList';

export const agentViews: Record<AgentKind, AgentStepComponent[]> = {
application: [SelectResource],
Expand Down Expand Up @@ -72,6 +75,9 @@ export default function Container() {
}

export function Discover({
alerts = [],
customBanners = [],
dismissAlert,
initAttempt,
userMenuItems,
username,
Expand All @@ -86,50 +92,74 @@ export function Discover({
AgentComponent = agentViews[selectedAgentKind][currentStep];
}

// The backend defines the severity as an integer value with the current
// pre-defined values: LOW: 0; MEDIUM: 5; HIGH: 10
const mapSeverity = (severity: number) => {
if (severity < 5) {
return 'info';
}
if (severity < 10) {
return 'warning';
}
return 'danger';
};

const banners: BannerType[] = alerts.map(alert => ({
message: alert.spec.message,
severity: mapSeverity(alert.spec.severity),
id: alert.metadata.name,
}));

return (
<MainContainer>
<Prompt
message={nextLocation => {
if (nextLocation.pathname === cfg.routes.discover) return true;
return 'Are you sure you want to exit the “Add New Resource” workflow? You’ll have to start from the beginning next time.';
}}
when={currentStep > 0}
/>
{initAttempt.status === 'processing' && (
<main.StyledIndicator>
<Indicator />
</main.StyledIndicator>
)}
{initAttempt.status === 'failed' && (
<Danger>{initAttempt.statusText}</Danger>
)}
{initAttempt.status === 'success' && (
<>
<SideNavAgentConnect
currentStep={currentStep}
// TODO: hack to not show titles for unfinished flows.
stepTitles={
agentViews[selectedAgentKind].length > 1 ? agentStepTitles : []
}
/>
<main.HorizontalSplit>
<TopBarContainer>
<Text typography="h5" bold>
Manage Access
</Text>
<UserMenuNav
navItems={userMenuItems}
logout={logout}
username={username}
/>
</TopBarContainer>
<FeatureBox pt={4}>
{AgentComponent && <AgentComponent {...agentProps} />}
</FeatureBox>
</main.HorizontalSplit>
</>
)}
</MainContainer>
<BannerList
banners={banners}
customBanners={customBanners}
onBannerDismiss={dismissAlert}
>
<MainContainer>
<Prompt
message={nextLocation => {
if (nextLocation.pathname === cfg.routes.discover) return true;
return 'Are you sure you want to exit the “Add New Resource” workflow? You’ll have to start from the beginning next time.';
}}
when={currentStep > 0}
/>
{initAttempt.status === 'processing' && (
<main.StyledIndicator>
<Indicator />
</main.StyledIndicator>
)}
{initAttempt.status === 'failed' && (
<Danger>{initAttempt.statusText}</Danger>
)}
{initAttempt.status === 'success' && (
<>
<SideNavAgentConnect
currentStep={currentStep}
// TODO: hack to not show titles for unfinished flows.
stepTitles={
agentViews[selectedAgentKind].length > 1 ? agentStepTitles : []
}
/>
<main.HorizontalSplit>
<TopBarContainer>
<Text typography="h5" bold>
Manage Access
</Text>
<UserMenuNav
navItems={userMenuItems}
logout={logout}
username={username}
/>
</TopBarContainer>
<FeatureBox pt={4}>
{AgentComponent && <AgentComponent {...agentProps} />}
</FeatureBox>
</main.HorizontalSplit>
</>
)}
</MainContainer>
</BannerList>
);
}

Expand Down Expand Up @@ -247,13 +277,3 @@ const StyledNav = styled(sideNav.Nav)`
const StyledNavContent = styled(sideNav.Content)`
padding: 20px 32px 32px 32px;
`;

// TODO (lisa) we should look into reducing this width.
// Any smaller than this will produce a double stacked horizontal scrollbar
// making navigation harder.
//
// Our SelectResource component is the widest and can use some space
// tightening. Also look into shrinking the side nav if possible.
const MainContainer = styled(main.MainContainer)`
min-width: 1460px;
`;
3 changes: 3 additions & 0 deletions packages/teleport/src/Discover/useDiscover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ export function useDiscover(ctx: TeleportContext, features: Feature[]) {
}

return {
alerts: initState.alerts,
customBanners: initState.customBanners,
dismissAlert: initState.dismissAlert,
initAttempt: { status: initState.status, statusText: initState.statusText },
userMenuItems: ctx.storeNav.getTopMenuItems(),
username: ctx.storeUser.getUsername(),
Expand Down
4 changes: 3 additions & 1 deletion packages/teleport/src/Main/Main.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export function OSS() {
<Flex my={-3} mx={-4}>
<ContextProvider ctx={state.ctx}>
<Router history={state.history}>
<Main {...state} />
<Main customBanners={[]} {...state} />
</Router>
</ContextProvider>
</Flex>
Expand Down Expand Up @@ -85,8 +85,10 @@ function useMainStory() {
const statusText = '';

return {
alerts: [],
history,
ctx,
dismissAlert: () => {},
status,
statusText,
};
Expand Down
61 changes: 43 additions & 18 deletions packages/teleport/src/Main/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,32 @@ import CatchError from 'teleport/components/CatchError';
import cfg from 'teleport/config';
import SideNav from 'teleport/SideNav';
import TopBar from 'teleport/TopBar';
import { BannerList } from 'teleport/components/BannerList';
import getFeatures from 'teleport/features';
import localStorage from 'teleport/services/localStorage';
import history from 'teleport/services/history';

import { MainContainer } from './MainContainer';
import { OnboardDiscover } from './OnboardDiscover';

import useMain, { State } from './useMain';

import type { BannerType } from 'teleport/components/BannerList/BannerList';

export default function Container() {
const [features] = React.useState(() => getFeatures());
const state = useMain(features);
return <Main {...state} />;
}

export function Main(props: State) {
const { status, statusText, ctx } = props;
const {
alerts = [],
customBanners = [],
dismissAlert,
status,
statusText,
ctx,
} = props;
const [showOnboardDiscover, setShowOnboardDiscover] = React.useState(true);

if (status === 'failed') {
Expand Down Expand Up @@ -90,6 +100,24 @@ export function Main(props: State) {
ctx.storeNav.getSideItems()[0]?.getLink(cfg.proxyCluster) ||
cfg.routes.support;

// The backend defines the severity as an integer value with the current
// pre-defined values: LOW: 0; MEDIUM: 5; HIGH: 10
const mapSeverity = (severity: number) => {
if (severity < 5) {
return 'info';
}
if (severity < 10) {
return 'warning';
}
return 'danger';
};

const banners: BannerType[] = alerts.map(alert => ({
message: alert.spec.message,
severity: mapSeverity(alert.spec.severity),
id: alert.metadata.name,
}));

const onboard = localStorage.getOnboardDiscover();
const requiresOnboarding =
onboard && !onboard.hasResource && !onboard.notified;
Expand All @@ -99,29 +127,26 @@ export function Main(props: State) {
<RouterDOM.Switch>
<Redirect exact={true} from={cfg.routes.root} to={indexRoute} />
</RouterDOM.Switch>
<MainContainer>
<SideNav />
<HorizontalSplit>
<TopBar />
<Switch>{$features}</Switch>
</HorizontalSplit>
</MainContainer>
<BannerList
banners={banners}
customBanners={customBanners}
onBannerDismiss={dismissAlert}
>
<MainContainer>
<SideNav />
<HorizontalSplit>
<TopBar />
<Switch>{$features}</Switch>
</HorizontalSplit>
</MainContainer>
</BannerList>
{requiresOnboarding && showOnboardDiscover && (
<OnboardDiscover onClose={handleOnClose} onOnboard={handleOnboard} />
)}
</>
);
}

export const MainContainer = styled.div`
width: 100%;
height: 100%;
display: flex;
flex: 1;
position: absolute;
min-width: 1000px;
`;

export const HorizontalSplit = styled.div`
display: flex;
flex-direction: column;
Expand Down
31 changes: 31 additions & 0 deletions packages/teleport/src/Main/MainContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
Copyright 2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import styled from 'styled-components';

// NOTE: This MainContainer component is imported in multiple places and then
// modified using styled-components. If it's exported from the Main/index.ts
// or included in the Main.tsx file there is a circular dependency that causes
// odd issues around the MainContainer component being available at certain
// times.
export const MainContainer = styled.div`
width: 100%;
height: 100%;
display: flex;
flex: 1;
position: absolute;
min-width: 1000px;
`;
4 changes: 2 additions & 2 deletions packages/teleport/src/Main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import Main, { MainContainer, HorizontalSplit, StyledIndicator } from './Main';
import Main, { HorizontalSplit, StyledIndicator } from './Main';

export { MainContainer, HorizontalSplit, StyledIndicator };
export { HorizontalSplit, StyledIndicator };
export default Main;
5 changes: 5 additions & 0 deletions packages/teleport/src/Main/useMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ import useAttempt from 'shared/hooks/useAttemptNext';

import useTeleport from 'teleport/useTeleport';
import { Feature } from 'teleport/types';
import { useAlerts } from 'teleport/components/BannerList/useAlerts';

export default function useMain(features: Feature[]) {
const ctx = useTeleport();
const { attempt, setAttempt, run } = useAttempt('processing');
const { alerts, dismissAlert } = useAlerts();

useEffect(() => {
// Two routes that uses this hook that can trigger this effect:
Expand All @@ -44,7 +46,10 @@ export default function useMain(features: Feature[]) {
}, []);

return {
alerts,
customBanners: [],
ctx,
dismissAlert,
status: attempt.status,
statusText: attempt.statusText,
};
Expand Down
Loading

0 comments on commit 4ec6eb2

Please sign in to comment.