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
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ test('all participant modes are properly listed and in the correct order', () =>
sid={'4b038eda-ddca-5533-9a49-3a34f133b5f4'}
clusterId={'test-cluster'}
participantModes={['moderator', 'peer', 'observer']}
showCTA={false}
/>
);

Expand All @@ -50,3 +51,28 @@ test('all participant modes are properly listed and in the correct order', () =>
expect(menuItems[1]).toHaveTextContent('As a Moderator');
expect(menuItems[2]).toHaveTextContent('As a Peer');
});

test('all possible participant modes are properly listed in the CTA without join links', () => {
render(
<SessionJoinBtn
sid={'4b038eda-ddca-5533-9a49-3a34f133b5f4'}
clusterId={'test-cluster'}
participantModes={['moderator', 'peer', 'observer']}
showCTA={true}
/>
);

const joinBtn = screen.queryByText(/Join/i);
expect(joinBtn).toBeInTheDocument();

fireEvent.click(joinBtn);

// Make sure that no link to join session is available when showCTA = true.
const menuItems = screen.queryByRole<HTMLAnchorElement>('link');
expect(menuItems).not.toBeInTheDocument();

const cta = screen.queryByText(
'Join Active Sessions with Teleport Enterprise'
);
expect(cta).toBeInTheDocument();
});
33 changes: 25 additions & 8 deletions web/packages/teleport/src/Sessions/SessionList/SessionJoinBtn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,36 @@ import { CarrotDown, Warning } from 'design/Icon';

import cfg from 'teleport/config';
import { ParticipantMode } from 'teleport/services/session';
import { ButtonLockedFeature } from 'teleport/components/ButtonLockedFeature';

export const SessionJoinBtn = ({
sid,
clusterId,
participantModes,
showCTA,
}: {
sid: string;
clusterId: string;
participantModes: ParticipantMode[];
showCTA: boolean;
}) => {
return (
<JoinMenu>
{showCTA && (
<Box mx="12px" my="3">
<ButtonLockedFeature noIcon>
Join Active Sessions with Teleport Enterprise
</ButtonLockedFeature>
</Box>
)}
<JoinMenuItem
title="As an Observer"
description={modeDescription.observer}
url={cfg.getSshSessionRoute({ sid, clusterId }, 'observer')}
hasAccess={participantModes.includes('observer')}
participantMode="observer"
key="observer"
showCTA={showCTA}
/>
<JoinMenuItem
title="As a Moderator"
Expand All @@ -48,6 +59,7 @@ export const SessionJoinBtn = ({
hasAccess={participantModes.includes('moderator')}
participantMode="moderator"
key="moderator"
showCTA={showCTA}
/>
<JoinMenuItem
title="As a Peer"
Expand All @@ -56,6 +68,7 @@ export const SessionJoinBtn = ({
hasAccess={participantModes.includes('peer')}
participantMode="peer"
key="peer"
showCTA={showCTA}
/>
</JoinMenu>
);
Expand All @@ -64,7 +77,7 @@ export const SessionJoinBtn = ({
function JoinMenu({ children }: { children: React.ReactNode }) {
const [anchorEl, setAnchorEl] = useState<HTMLElement>(null);

const handleClickListItem = event => {
const handleClickListItem = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};

Expand Down Expand Up @@ -103,14 +116,16 @@ function JoinMenuItem({
hasAccess,
participantMode,
url,
showCTA,
}: {
title: string;
description: string;
hasAccess: boolean;
participantMode: ParticipantMode;
url: string;
showCTA: boolean;
}) {
if (hasAccess) {
if (hasAccess && !showCTA) {
return (
<MenuItem
as="a"
Expand Down Expand Up @@ -151,12 +166,14 @@ function JoinMenuItem({
<Box height="fit-content" width="264px">
<Text typography="h6">{title}</Text>
<Text>{description}</Text>
<Box color="text.main" px={1} mt={1}>
<Text fontSize="10px" color="text.slightlyMuted">
<Warning color="error.main" mr={2} />
{modeWarningText[participantMode]}
</Text>
</Box>
{!showCTA && (
<Box color="text.main" px={1} mt={1}>
<Text fontSize="10px" color="text.slightlyMuted">
<Warning color="error.main" mr={2} />
{modeWarningText[participantMode]}
</Text>
</Box>
)}
</Box>
</MenuItem>
);
Expand Down
11 changes: 8 additions & 3 deletions web/packages/teleport/src/Sessions/SessionList/SessionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { Participant, Session, SessionKind } from 'teleport/services/session';
import { SessionJoinBtn } from './SessionJoinBtn';

export default function SessionList(props: Props) {
const { sessions, pageSize = 100 } = props;
const { sessions, pageSize = 100, showActiveSessionsCTA } = props;

return (
<StyledTable
Expand Down Expand Up @@ -59,7 +59,8 @@ export default function SessionList(props: Props) {
},
{
altKey: 'join-btn',
render: renderJoinCell,
render: session =>
renderJoinCell({ ...session, showActiveSessionsCTA }),
},
]}
emptyText="No Active Sessions Found"
Expand Down Expand Up @@ -102,12 +103,14 @@ const renderIconCell = (kind: SessionKind) => {
);
};

type renderJoinCellProps = Session & { showActiveSessionsCTA: boolean };
const renderJoinCell = ({
sid,
clusterId,
kind,
participantModes,
}: Session) => {
showActiveSessionsCTA,
}: renderJoinCellProps) => {
const { joinable } = kinds[kind];
if (!joinable || participantModes.length === 0) {
return <Cell align="right" height="26px" />;
Expand All @@ -119,6 +122,7 @@ const renderJoinCell = ({
sid={sid}
clusterId={clusterId}
participantModes={participantModes}
showCTA={showActiveSessionsCTA}
/>
</Cell>
);
Expand All @@ -132,6 +136,7 @@ function renderUsersCell({ parties }: Session) {
type Props = {
sessions: Session[];
pageSize?: number;
showActiveSessionsCTA: boolean;
};

function participantMatcher(
Expand Down
7 changes: 6 additions & 1 deletion web/packages/teleport/src/Sessions/Sessions.story.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@ import React from 'react';

import { render } from 'design/utils/testing';

import { Loaded } from './Sessions.story';
import { Loaded, LoadedWithCTA } from './Sessions.story';

test('loaded', () => {
const { container } = render(<Loaded />);
expect(container.firstChild).toMatchSnapshot();
});

test('loaded with CTA', () => {
const { container } = render(<LoadedWithCTA />);
expect(container.firstChild).toMatchSnapshot();
});
16 changes: 16 additions & 0 deletions web/packages/teleport/src/Sessions/Sessions.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ export function Loaded() {
isFailed: false,
message: '',
},
showActiveSessionsCTA: false,
};

return <Sessions {...props} />;
}

export function LoadedWithCTA() {
const props = {
sessions,
attempt: {
isSuccess: true,
isProcessing: false,
isFailed: false,
message: '',
},
showActiveSessionsCTA: true,
};

return <Sessions {...props} />;
Expand Down
20 changes: 17 additions & 3 deletions web/packages/teleport/src/Sessions/Sessions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import useTeleport from 'teleport/useTeleport';

import useStickerClusterId from 'teleport/useStickyClusterId';

import { ButtonLockedFeature } from 'teleport/components/ButtonLockedFeature';

import SessionList from './SessionList';
import useSessions from './useSessions';

Expand All @@ -38,19 +40,31 @@ export default function Container() {
}

export function Sessions(props: ReturnType<typeof useSessions>) {
const { attempt, sessions } = props;
const { attempt, sessions, showActiveSessionsCTA } = props;
return (
<FeatureBox>
<FeatureHeader alignItems="center">
<FeatureHeader alignItems="center" justifyContent="space-between">
<FeatureHeaderTitle>Active Sessions</FeatureHeaderTitle>
{showActiveSessionsCTA && (
<Box width="340px">
<ButtonLockedFeature height="36px">
Join Active Sessions With Teleport Enterprise
</ButtonLockedFeature>
</Box>
)}
</FeatureHeader>
{attempt.isFailed && <Danger>{attempt.message} </Danger>}
{attempt.isProcessing && (
<Box textAlign="center" m={10}>
<Indicator />
</Box>
)}
{attempt.isSuccess && <SessionList sessions={sessions} />}
{attempt.isSuccess && (
<SessionList
sessions={sessions}
showActiveSessionsCTA={showActiveSessionsCTA}
/>
)}
</FeatureBox>
);
}
Loading