-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Show desktops in connection tracker #54668
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
Changes from all commits
d332897
9f88d44
9d2c92e
6d512f9
2a528db
1e7478d
22ea216
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,26 +16,28 @@ | |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| */ | ||
|
|
||
| import { useMemo, useState } from 'react'; | ||
| import { useCallback, useMemo, useState } from 'react'; | ||
|
|
||
| import { Text } from 'design'; | ||
| import { ACL } from 'gen-proto-ts/teleport/lib/teleterm/v1/cluster_pb'; | ||
| import { DesktopSession } from 'shared/components/DesktopSession'; | ||
| import { | ||
| Attempt, | ||
| makeProcessingAttempt, | ||
| makeSuccessAttempt, | ||
| } from 'shared/hooks/useAsync'; | ||
| import { BrowserFileSystem, TdpClient } from 'shared/libs/tdp'; | ||
| import { BrowserFileSystem, TdpClient, useListener } from 'shared/libs/tdp'; | ||
| import { TdpTransport } from 'shared/libs/tdp/client'; | ||
|
|
||
| import Logger from 'teleterm/logger'; | ||
| import { cloneAbortSignal, TshdClient } from 'teleterm/services/tshd'; | ||
| import { useAppContext } from 'teleterm/ui/appContextProvider'; | ||
| import Document from 'teleterm/ui/Document'; | ||
| import { useWorkspaceContext } from 'teleterm/ui/Documents'; | ||
| import { useWorkspaceLoggedInUser } from 'teleterm/ui/hooks/useLoggedInUser'; | ||
| import { useLogger } from 'teleterm/ui/hooks/useLogger'; | ||
| import * as types from 'teleterm/ui/services/workspacesService'; | ||
| import { routing, WindowsDesktopUri } from 'teleterm/ui/uri'; | ||
| import { DesktopUri, isWindowsDesktopUri, routing } from 'teleterm/ui/uri'; | ||
|
|
||
| // The check for another active session is disabled in Connect: | ||
| // 1. This protection was added to the Web UI to prevent a situation where a user could be tricked | ||
|
|
@@ -50,11 +52,12 @@ export function DocumentDesktopSession(props: { | |
| doc: types.DocumentDesktopSession; | ||
| }) { | ||
| const logger = useLogger('DocumentDesktopSession'); | ||
| const { desktopUri, login, origin } = props.doc; | ||
| const { desktopUri, login, origin, uri } = props.doc; | ||
| const appCtx = useAppContext(); | ||
| const { documentsService } = useWorkspaceContext(); | ||
| const loggedInUser = useWorkspaceLoggedInUser(); | ||
| const acl = useMemo<Attempt<ACL>>(() => { | ||
| if (!loggedInUser) { | ||
| if (!loggedInUser?.acl) { | ||
| return makeProcessingAttempt(); | ||
| } | ||
| return makeSuccessAttempt(loggedInUser.acl); | ||
|
|
@@ -83,8 +86,38 @@ export function DocumentDesktopSession(props: { | |
| }, new BrowserFileSystem()) | ||
| ); | ||
|
|
||
| return ( | ||
| <Document visible={props.visible}> | ||
| useListener( | ||
| client.onTransportOpen, | ||
| useCallback( | ||
| () => documentsService.update(uri, { status: 'connected' }), | ||
| [documentsService, uri] | ||
| ) | ||
| ); | ||
| useListener( | ||
| client.onTransportClose, | ||
| useCallback( | ||
| error => documentsService.update(uri, { status: error ? 'error' : '' }), | ||
| [documentsService, uri] | ||
| ) | ||
| ); | ||
| useListener( | ||
| client.onError, | ||
| useCallback( | ||
| () => documentsService.update(uri, { status: 'error' }), | ||
| [documentsService, uri] | ||
| ) | ||
| ); | ||
|
Comment on lines
+96
to
+109
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I should have combined these events while I was refactoring this, but well, I will keep it as is. |
||
|
|
||
| let content = ( | ||
| <Text m="auto" mt={10} textAlign="center"> | ||
| Cannot open a connection to "{desktopUri}". | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this always trips me up and i think its going to just print that instead of the |
||
| <br /> | ||
| Only Windows desktops are supported. | ||
| </Text> | ||
| ); | ||
|
|
||
| if (isWindowsDesktopUri(desktopUri)) { | ||
| content = ( | ||
| <DesktopSession | ||
| hasAnotherSession={noOtherSession} | ||
| desktop={ | ||
|
|
@@ -94,14 +127,16 @@ export function DocumentDesktopSession(props: { | |
| username={login} | ||
| aclAttempt={acl} | ||
| /> | ||
| </Document> | ||
| ); | ||
| ); | ||
| } | ||
|
|
||
| return <Document visible={props.visible}>{content}</Document>; | ||
| } | ||
|
|
||
| async function adaptGRPCStreamToTdpTransport( | ||
| stream: ReturnType<TshdClient['connectToDesktop']>, | ||
| targetDesktop: { | ||
| desktopUri: WindowsDesktopUri; | ||
| desktopUri: DesktopUri; | ||
| login: string; | ||
| }, | ||
| logger: Logger | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,10 +33,12 @@ import { assertUnreachable } from 'teleterm/ui/utils'; | |
| import { ImmutableStore } from '../immutableStore'; | ||
| import { TrackedConnectionOperationsFactory } from './trackedConnectionOperationsFactory'; | ||
| import { | ||
| createDesktopConnection, | ||
| createGatewayConnection, | ||
| createGatewayKubeConnection, | ||
| createKubeConnection, | ||
| createServerConnection, | ||
| getDesktopConnectionByDocument, | ||
| getGatewayConnectionByDocument, | ||
| getGatewayKubeConnectionByDocument, | ||
| getKubeConnectionByDocument, | ||
|
|
@@ -76,15 +78,27 @@ export class ConnectionTrackerService extends ImmutableStore<ConnectionTrackerSt | |
| } | ||
|
|
||
| getConnections(): ExtendedTrackedConnection[] { | ||
| return this.state.connections.map(connection => { | ||
| const { rootClusterUri, leafClusterUri } = | ||
| this._trackedConnectionOperationsFactory.create(connection); | ||
| const clusterUri = leafClusterUri || rootClusterUri; | ||
| const clusterName = | ||
| this._clusterService.findCluster(clusterUri)?.name || | ||
| routing.parseClusterName(clusterUri); | ||
| return { ...connection, clusterName }; | ||
| }); | ||
| return this.state.connections | ||
| .map(connection => { | ||
| const trackedConnection = | ||
| this._trackedConnectionOperationsFactory.create(connection); | ||
| // A connection is undefined when the state read from the disk | ||
| // contains a connection not supported by the given Connect version. | ||
| // | ||
| // For example, the user can open a desktop connection in Connect v18 | ||
| // and then downgrade to a version that doesn't support desktops. | ||
| // That connection should be shown as 'UNKNOWN' in the connection list. | ||
| if (!trackedConnection) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately, it turned out that we didn't properly handle unsupported connections in #37584. |
||
| return; | ||
| } | ||
| const { rootClusterUri, leafClusterUri } = trackedConnection; | ||
| const clusterUri = leafClusterUri || rootClusterUri; | ||
| const clusterName = | ||
| this._clusterService.findCluster(clusterUri)?.name || | ||
| routing.parseClusterName(clusterUri); | ||
| return { ...connection, clusterName }; | ||
| }) | ||
| .filter(Boolean); | ||
| } | ||
|
|
||
| async activateItem( | ||
|
|
@@ -123,6 +137,10 @@ export class ConnectionTrackerService extends ImmutableStore<ConnectionTrackerSt | |
| return this.state.connections.find( | ||
| getGatewayKubeConnectionByDocument(document) | ||
| ); | ||
| case 'doc.desktop_session': | ||
| return this.state.connections.find( | ||
| getDesktopConnectionByDocument(document) | ||
| ); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -180,6 +198,8 @@ export class ConnectionTrackerService extends ImmutableStore<ConnectionTrackerSt | |
| return s.targetUri === resourceUri; | ||
| case 'connection.kube': | ||
| return s.kubeUri === resourceUri; | ||
| case 'connection.desktop': | ||
| return s.desktopUri === resourceUri; | ||
| default: | ||
| return assertUnreachable(s); | ||
| } | ||
|
|
@@ -239,7 +259,8 @@ export class ConnectionTrackerService extends ImmutableStore<ConnectionTrackerSt | |
| d.kind === 'doc.gateway' || | ||
| d.kind === 'doc.gateway_kube' || | ||
| d.kind === 'doc.terminal_tsh_node' || | ||
| d.kind === 'doc.terminal_tsh_kube' | ||
| d.kind === 'doc.terminal_tsh_kube' || | ||
| d.kind === 'doc.desktop_session' | ||
| ); | ||
|
|
||
| if (!docs) { | ||
|
|
@@ -328,6 +349,19 @@ export class ConnectionTrackerService extends ImmutableStore<ConnectionTrackerSt | |
| } | ||
| break; | ||
| } | ||
| case 'doc.desktop_session': { | ||
| const desktopConn = draft.connections.find( | ||
| getDesktopConnectionByDocument(doc) | ||
| ); | ||
|
|
||
| if (desktopConn) { | ||
| desktopConn.connected = doc.status === 'connected'; | ||
| } else { | ||
| const newItem = createDesktopConnection(doc); | ||
| draft.connections.push(newItem); | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| }); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small issue that's unrelated to this PR: whenever I switch to a tab with a desktop session, there's a flicker as the client sends "[TDPClient] requesting screen spec from client 837 x 881", despite the window size staying the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This happens because of a resize observer. If you hide the tab, its size goes to 0x0 (we ignore that) and after it becomes visible, it reports the size change (837 x 881 in this case). To avoid this, we could store the last reported size and compare it with the new size. While this is a simple fix, I'm not sure if I'll find time for it 😅