diff --git a/web/packages/design/src/Icon/Icons.story.tsx b/web/packages/design/src/Icon/Icons.story.tsx index 2ed73fe824242..21e7ca38bfacf 100644 --- a/web/packages/design/src/Icon/Icons.story.tsx +++ b/web/packages/design/src/Icon/Icons.story.tsx @@ -130,6 +130,7 @@ export const Icons = () => ( + diff --git a/web/packages/design/src/Icon/Icons/Keyboard.tsx b/web/packages/design/src/Icon/Icons/Keyboard.tsx new file mode 100644 index 0000000000000..b795702d86606 --- /dev/null +++ b/web/packages/design/src/Icon/Icons/Keyboard.tsx @@ -0,0 +1,73 @@ +/** + * Teleport + * Copyright (C) 2023 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 . + */ + +/* MIT License + +Copyright (c) 2020 Phosphor Icons + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +import React from 'react'; + +import { Icon, IconProps } from '../Icon'; + +/* + +THIS FILE IS GENERATED. DO NOT EDIT. + +*/ + +export function Keyboard({ size = 24, color, ...otherProps }: IconProps) { + return ( + + + + + + + + + ); +} diff --git a/web/packages/design/src/Icon/assets/Keyboard.svg b/web/packages/design/src/Icon/assets/Keyboard.svg new file mode 100644 index 0000000000000..18bc069dd79bb --- /dev/null +++ b/web/packages/design/src/Icon/assets/Keyboard.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/web/packages/design/src/Icon/index.ts b/web/packages/design/src/Icon/index.ts index c47538b992fb5..920ba5bb9d60d 100644 --- a/web/packages/design/src/Icon/index.ts +++ b/web/packages/design/src/Icon/index.ts @@ -118,6 +118,7 @@ export { Info } from './Icons/Info'; export { Integrations } from './Icons/Integrations'; export { Invoices } from './Icons/Invoices'; export { Key } from './Icons/Key'; +export { Keyboard } from './Icons/Keyboard'; export { Keypair } from './Icons/Keypair'; export { Kubernetes } from './Icons/Kubernetes'; export { Label } from './Icons/Label'; diff --git a/web/packages/teleport/src/DesktopSession/ActionMenu.tsx b/web/packages/teleport/src/DesktopSession/ActionMenu.tsx index a23bc54ca9a99..aea014ba522b7 100644 --- a/web/packages/teleport/src/DesktopSession/ActionMenu.tsx +++ b/web/packages/teleport/src/DesktopSession/ActionMenu.tsx @@ -22,7 +22,8 @@ import * as Icons from 'design/Icon'; import { Flex } from 'design'; export default function ActionMenu(props: Props) { - const { showShareDirectory, onShareDirectory, onDisconnect } = props; + const { showShareDirectory, onShareDirectory, onDisconnect, onCtrlAltDel } = + props; return ( @@ -41,6 +42,10 @@ export default function ActionMenu(props: Props) { Share Directory )} + + + Send Ctrl+Alt+Del + Disconnect @@ -54,6 +59,7 @@ type Props = { showShareDirectory: boolean; onShareDirectory: VoidFunction; onDisconnect: VoidFunction; + onCtrlAltDel: VoidFunction; }; const menuListCss = () => ` diff --git a/web/packages/teleport/src/DesktopSession/DesktopSession.story.tsx b/web/packages/teleport/src/DesktopSession/DesktopSession.story.tsx index 7be8f174c74a1..4df1728c274c8 100644 --- a/web/packages/teleport/src/DesktopSession/DesktopSession.story.tsx +++ b/web/packages/teleport/src/DesktopSession/DesktopSession.story.tsx @@ -63,6 +63,7 @@ const props: State = { }, setDirectorySharingState: () => {}, onShareDirectory: () => {}, + onCtrlAltDel: () => {}, clientOnPngFrame: () => {}, clientOnBitmapFrame: () => {}, clientOnClientScreenSpec: () => {}, diff --git a/web/packages/teleport/src/DesktopSession/DesktopSession.tsx b/web/packages/teleport/src/DesktopSession/DesktopSession.tsx index 1c7054a2ff01a..a3a9a6f9eb39f 100644 --- a/web/packages/teleport/src/DesktopSession/DesktopSession.tsx +++ b/web/packages/teleport/src/DesktopSession/DesktopSession.tsx @@ -81,6 +81,7 @@ export function DesktopSession(props: State) { clientScreenSpecToRequest, clipboardSharingState, onShareDirectory, + onCtrlAltDel, warnings, onRemoveWarning, fetchAttempt, @@ -133,6 +134,7 @@ export function DesktopSession(props: State) { isSharingDirectory={isSharingDirectory(directorySharingState)} isSharingClipboard={isSharingClipboard(clipboardSharingState)} onShareDirectory={onShareDirectory} + onCtrlAltDel={onCtrlAltDel} warnings={warnings} onRemoveWarning={onRemoveWarning} /> diff --git a/web/packages/teleport/src/DesktopSession/TopBar.tsx b/web/packages/teleport/src/DesktopSession/TopBar.tsx index b9cb9f8fa0701..b2797d6df314e 100644 --- a/web/packages/teleport/src/DesktopSession/TopBar.tsx +++ b/web/packages/teleport/src/DesktopSession/TopBar.tsx @@ -36,6 +36,7 @@ export default function TopBar(props: Props) { canShareDirectory, isSharingDirectory, onShareDirectory, + onCtrlAltDel, warnings, onRemoveWarning, } = props; @@ -91,6 +92,7 @@ export default function TopBar(props: Props) { onDisconnect={onDisconnect} showShareDirectory={canShareDirectory && !isSharingDirectory} onShareDirectory={onShareDirectory} + onCtrlAltDel={onCtrlAltDel} /> @@ -119,6 +121,7 @@ type Props = { isSharingDirectory: boolean; onDisconnect: VoidFunction; onShareDirectory: VoidFunction; + onCtrlAltDel: VoidFunction; warnings: NotificationItem[]; onRemoveWarning(id: string): void; }; diff --git a/web/packages/teleport/src/DesktopSession/useDesktopSession.tsx b/web/packages/teleport/src/DesktopSession/useDesktopSession.tsx index 2871105a51f15..a1cf2b32797be 100644 --- a/web/packages/teleport/src/DesktopSession/useDesktopSession.tsx +++ b/web/packages/teleport/src/DesktopSession/useDesktopSession.tsx @@ -21,6 +21,7 @@ import { useParams } from 'react-router'; import useAttempt from 'shared/hooks/useAttemptNext'; +import { ButtonState } from 'teleport/lib/tdp'; import useWebAuthn from 'teleport/lib/useWebAuthn'; import desktopService from 'teleport/services/desktops'; import userService from 'teleport/services/user'; @@ -185,6 +186,15 @@ export default function useDesktopSession() { } }; + const onCtrlAltDel = () => { + if (!tdpClient) { + return; + } + tdpClient.sendKeyboardInput('ControlLeft', ButtonState.DOWN); + tdpClient.sendKeyboardInput('AltLeft', ButtonState.DOWN); + tdpClient.sendKeyboardInput('Delete', ButtonState.DOWN); + }; + return { hostname, username, @@ -200,6 +210,7 @@ export default function useDesktopSession() { showAnotherSessionActiveDialog, setShowAnotherSessionActiveDialog, onShareDirectory, + onCtrlAltDel, warnings, onRemoveWarning, ...clientCanvasProps,