diff --git a/web/packages/teleterm/src/ui/TopBar/Connections/Connections.story.tsx b/web/packages/teleterm/src/ui/TopBar/Connections/Connections.story.tsx
index 0ac27b0e8372a..2e639260c77c0 100644
--- a/web/packages/teleterm/src/ui/TopBar/Connections/Connections.story.tsx
+++ b/web/packages/teleterm/src/ui/TopBar/Connections/Connections.story.tsx
@@ -21,6 +21,8 @@ import AppContextProvider from 'teleterm/ui/appContextProvider';
import { MockAppContext } from 'teleterm/ui/fixtures/mocks';
import { ExtendedTrackedConnection } from 'teleterm/ui/services/connectionTracker';
+import { makeRootCluster } from 'teleterm/services/tshd/testHelpers';
+
import { Connections } from './Connections';
export default {
@@ -34,6 +36,8 @@ export default {
],
};
+const rootClusterUri = '/clusters/foo';
+
export function Story() {
const appContext = new MockAppContext();
prepareAppContext(appContext);
@@ -45,6 +49,41 @@ export function Story() {
);
}
+export function MultipleClusters() {
+ const appContext = new MockAppContext();
+ prepareAppContext(appContext);
+ appContext.clustersService.setState(draft => {
+ const rootCluster1 = makeRootCluster({
+ uri: rootClusterUri,
+ name: 'teleport.example.sh',
+ });
+ const rootCluster2 = makeRootCluster({
+ uri: '/clusters/bar',
+ name: 'bar.example.com',
+ });
+ draft.clusters.set(rootCluster1.uri, rootCluster1);
+ draft.clusters.set(rootCluster2.uri, rootCluster2);
+ });
+ appContext.connectionTracker.getConnections = () => [
+ ...makeConnections(),
+ {
+ connected: true,
+ kind: 'connection.server' as const,
+ title: 'runner-prod',
+ id: 'ed23ded1',
+ serverUri: '/clusters/bar/servers/ed23ded1',
+ login: 'alice',
+ clusterName: 'bar.example.com',
+ },
+ ];
+
+ return (
+
+
+
+ );
+}
+
export function WithScroll() {
const appContext = new MockAppContext();
prepareAppContext(appContext);
diff --git a/web/packages/teleterm/src/ui/TopBar/Connections/ConnectionsFilterableList/ConnectionItem.tsx b/web/packages/teleterm/src/ui/TopBar/Connections/ConnectionsFilterableList/ConnectionItem.tsx
index d0b0b3bcec9f6..81d95a98d620f 100644
--- a/web/packages/teleterm/src/ui/TopBar/Connections/ConnectionsFilterableList/ConnectionItem.tsx
+++ b/web/packages/teleterm/src/ui/TopBar/Connections/ConnectionsFilterableList/ConnectionItem.tsx
@@ -26,18 +26,14 @@ import { useKeyboardArrowsNavigation } from 'teleterm/ui/components/KeyboardArro
import { ConnectionStatusIndicator } from './ConnectionStatusIndicator';
-interface ConnectionItemProps {
+export function ConnectionItem(props: {
index: number;
item: ExtendedTrackedConnection;
-
+ showClusterName: boolean;
onActivate(): void;
-
onRemove(): void;
-
onDisconnect(): void;
-}
-
-export function ConnectionItem(props: ConnectionItemProps) {
+}) {
const offline = !props.item.connected;
const { isActive, scrollIntoViewIfActive } = useKeyboardArrowsNavigation({
index: props.index,
@@ -69,8 +65,13 @@ export function ConnectionItem(props: ConnectionItemProps) {
onClick={props.onActivate}
isActive={isActive}
ref={ref}
+ $showClusterName={props.showClusterName}
css={`
- padding: 6px 8px;
+ padding: ${props => props.theme.space[1]}px
+ ${props => props.theme.space[2]}px;
+ // Space out items more if there are two lines of text to show inside a single item.
+ margin-block-start: ${props =>
+ props.$showClusterName ? props.theme.space[1] : 0}px;
height: unset;
`}
>
@@ -98,6 +99,7 @@ export function ConnectionItem(props: ConnectionItemProps) {
color="text.main"
title={props.item.title}
css={`
+ // Needed to condense a single item when the cluster name is displayed.
line-height: 16px;
`}
>
@@ -121,13 +123,16 @@ export function ConnectionItem(props: ConnectionItemProps) {
{props.item.title}
-
- {props.item.clusterName}
-
+
+ {props.showClusterName && (
+
+ {props.item.clusterName}
+
+ )}
i.clusterName));
+ // showClusterNames is based on two values, as there are two cases we need to account for:
+ //
+ // 1. If there's only a single cluster a user has access to, they don't care about its name.
+ // However, the moment there's an extra leaf cluster or just another profile, the user might want
+ // to know the name of a cluster for the given connection, even if the connection list currently
+ // shows connections only from a single cluster.
+ //
+ // 2. The connection list might include a connection to a leaf cluster resource even after that
+ // leaf is no longer available and there's only a single cluster in clustersService. As such, we
+ // have to look at the number of clusters in connections as well.
+ const showClusterName =
+ clustersService.getClustersCount() > 1 || clustersInConnections.size > 1;
return (
@@ -54,6 +61,7 @@ export function ConnectionsFilterableList(
props.onActivateItem(item.id)}
onRemove={() => props.onRemoveItem(item.id)}
onDisconnect={() => props.onDisconnectItem(item.id)}
diff --git a/web/packages/teleterm/src/ui/services/clusters/clustersService.ts b/web/packages/teleterm/src/ui/services/clusters/clustersService.ts
index 507165a5776b5..d011ee498884e 100644
--- a/web/packages/teleterm/src/ui/services/clusters/clustersService.ts
+++ b/web/packages/teleterm/src/ui/services/clusters/clustersService.ts
@@ -486,6 +486,10 @@ export class ClustersService extends ImmutableStore
return [...this.state.clusters.values()];
}
+ getClustersCount() {
+ return this.state.clusters.size;
+ }
+
getRootClusters() {
return this.getClusters().filter(c => !c.leaf);
}