Skip to content
Merged
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
84 changes: 84 additions & 0 deletions web/packages/design/src/Alert/Alert.controls.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* Teleport
* Copyright (C) 2025 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 { Meta } from '@storybook/react';

import { Alert, AlertKind, AlertProps } from './Alert';

type StoryProps = {
kind: AlertKind;
children: string;
details: string;
dismissible: boolean;
primaryAction: string;
secondaryAction: string;
alignItems: AlertProps['alignItems'];
};

const meta: Meta<StoryProps> = {
title: 'Design/Alerts/Controls',
component: Controls,
argTypes: {
kind: {
control: { type: 'select' },
options: [
'neutral',
'danger',
'info',
'warning',
'success',
'outline-danger',
'outline-info',
'outline-warn',
],
},
alignItems: {
control: { type: 'radio' },
options: ['center', 'flex-start'],
},
},
args: {
kind: 'neutral',
children: 'Lorem ipsum dolor sit amet',
details: 'Maecenas ut scelerisque nunc, blandit porta est.',
dismissible: true,
primaryAction: 'Primary Action',
secondaryAction: 'Secondary Action',
alignItems: 'center',
},
};
export default meta;

export function Controls(props: StoryProps) {
return (
<Alert
kind={props.kind}
details={props.details}
dismissible={props.dismissible}
primaryAction={
props.primaryAction ? { content: props.primaryAction } : undefined
}
secondaryAction={
props.secondaryAction ? { content: props.secondaryAction } : undefined
}
alignItems={props.alignItems}
>
{props.children}
</Alert>
);
}
27 changes: 18 additions & 9 deletions web/packages/design/src/Alert/Alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const linkColor = style({
key: 'colors',
});

type AlertKind =
export type AlertKind =
| 'neutral'
| 'danger'
| 'info'
Expand Down Expand Up @@ -80,7 +80,9 @@ const alertBorder = (
}
};

const backgroundColor = (props: ThemedAlertProps): { background: string } => {
const backgroundColor = (
props: Pick<ThemedAlertProps, 'kind' | 'theme'>
): { background: string } => {
const { kind, theme } = props;
switch (kind) {
case 'success':
Expand Down Expand Up @@ -124,6 +126,7 @@ interface Props<K> {
children?: React.ReactNode;
style?: React.CSSProperties;
onDismiss?: () => void;
alignItems?: 'center' | 'flex-start';
}

/**
Expand Down Expand Up @@ -176,6 +179,7 @@ export const Alert = ({
dismissible,
bg,
onDismiss,
alignItems = 'center',
...otherProps
}: AlertProps) => {
const alertIconSize = kind === 'neutral' ? 'large' : 'small';
Expand All @@ -192,7 +196,7 @@ export const Alert = ({

return (
<OuterContainer bg={bg} kind={kind} {...otherProps}>
<InnerContainer kind={kind}>
<InnerContainer kind={kind} alignItems={alignItems}>
<IconContainer kind={kind}>
<StatusIcon
kind={iconKind(kind)}
Expand Down Expand Up @@ -236,21 +240,26 @@ const OuterContainer = styled.div<AlertPropsWithRequiredKind>`

${space}
${width}
${alertBorder}
${color}
a {
color: ${({ theme }) => theme.colors.light};
${alertBorder}
${color}
a {
// Using the same color as Link (theme.solid.interactive.solid.accent) looks bad in the BBLP
// theme, so instead let's default to the color of the text and decorate links only with an
// underline.
color: inherit;
${linkColor}
}
`;

/** Renders a transparent color overlay. */
const InnerContainer = styled.div<AlertPropsWithRequiredKind>`
const InnerContainer = styled.div<
Pick<WithRequired<AlertProps, 'kind' | 'alignItems'>, 'kind' | 'alignItems'>
>`
padding: 12px 16px;
overflow: auto;
word-break: break-word;
display: flex;
align-items: center;
align-items: ${p => p.alignItems};

${backgroundColor}
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { Link } from 'react-router-dom';

import { Flex, H3, Subtitle3, Text } from 'design';
import { Alert, Box, Flex, H3, Subtitle3, Text } from 'design';
import { ButtonSecondary } from 'design/Button';
import * as Icons from 'design/Icon';
import { getPlatform } from 'design/platform';
Expand All @@ -32,17 +32,7 @@ import * as connectMyComputer from 'shared/connectMyComputer';
import { makeDeepLinkWithSafeInput } from 'shared/deepLinks';

import cfg from 'teleport/config';
import {
ActionButtons,
Header,
StyledBox,
TextIcon,
} from 'teleport/Discover/Shared';
import {
HintBox,
SuccessBox,
WaitingInfo,
} from 'teleport/Discover/Shared/HintBox';
import { ActionButtons, Header, StyledBox } from 'teleport/Discover/Shared';
import { usePoll } from 'teleport/Discover/Shared/usePoll';
import { Node } from 'teleport/services/nodes';
import useTeleport from 'teleport/useTeleport';
Expand Down Expand Up @@ -119,74 +109,75 @@ export function SetupConnect(

let pollingStatus: JSX.Element;
if (showHint && !node) {
pollingStatus = (
// Override max-width to match StyledBox's max-width.
<HintBox header="We're still looking for your computer" maxWidth="800px">
<Flex flexDirection="column" gap={3}>
<P>
There are a couple of possible reasons for why we haven't been able
to detect your computer.
</P>
const details = (
<Flex flexDirection="column" gap={3}>
<P>
There are a couple of possible reasons for why we haven&apos;t been
able to detect your computer.
</P>

<ul
css={`
margin: 0;
padding-left: ${p => p.theme.space[3]}px;
`}
>
<li>
<Text>
You did not start Connect My Computer in Teleport Connect yet.
</Text>
</li>
<li>
<Text>
The Teleport agent started by Teleport Connect could not join
this Teleport cluster. Check if the Connect My Computer tab in
Teleport Connect shows any error messages.
</Text>
</li>
<li>
<Text>
The computer you are trying to add has already joined the
Teleport cluster before you entered this page. If that's the
case, you can go back to{' '}
<Link to={cfg.getUnifiedResourcesRoute(clusterId)}>
the resources
</Link>{' '}
and connect to it.
</Text>
</li>
</ul>
<ul
css={`
margin: 0;
padding-left: ${p => p.theme.space[3]}px;
`}
>
<li>
<Text>
You did not start Connect My Computer in Teleport Connect yet.
</Text>
</li>
<li>
<Text>
The Teleport agent started by Teleport Connect could not join this
Teleport cluster. Check if the Connect My Computer tab in Teleport
Connect shows any error messages.
</Text>
</li>
<li>
<Text>
The computer you are trying to add has already joined the Teleport
cluster before you entered this page. If that&apos;s the case, you
can go back to the{' '}
<Link to={cfg.getUnifiedResourcesRoute(clusterId)}>
resources page
</Link>{' '}
and connect to it.
</Text>
</li>
</ul>

<P>
We'll continue to look for the computer whilst you diagnose the
issue.
</P>
</Flex>
</HintBox>
<P>
We&apos;ll continue to look for the computer while you diagnose the
issue.
</P>
</Flex>
);
pollingStatus = (
// Override max-width to match StyledBox's max-width.
<Box maxWidth="800px">
<Alert
alignItems="flex-start"
kind="warning"
dismissible={false}
details={details}
>
We&apos;re still looking for your computer
</Alert>
</Box>
);
} else if (node) {
pollingStatus = (
<SuccessBox>
<Text>
Your computer, <strong>{node.hostname}</strong>, has been detected!
</Text>
</SuccessBox>
<Alert kind="success" dismissible={false}>
Your computer, <strong>{node.hostname}</strong>, has been detected!
</Alert>
);
} else {
pollingStatus = (
<WaitingInfo>
<TextIcon
css={`
white-space: pre;
`}
>
<Icons.Restore size="medium" mr={2} />
</TextIcon>
<Alert kind="neutral" icon={Icons.Restore} dismissible={false}>
After your computer is connected to the cluster, we’ll automatically
detect it.
</WaitingInfo>
</Alert>
);
}

Expand Down
Loading