diff --git a/packages/shared/components/MenuSshLogin/MenuSshLogin.tsx b/packages/shared/components/MenuSshLogin/MenuSshLogin.tsx index e34cf59b1..dc2e7e4c8 100644 --- a/packages/shared/components/MenuSshLogin/MenuSshLogin.tsx +++ b/packages/shared/components/MenuSshLogin/MenuSshLogin.tsx @@ -20,7 +20,7 @@ import { NavLink } from 'react-router-dom'; import Menu, { MenuItem } from 'design/Menu'; import { space } from 'design/system'; import { MenuSshLoginProps } from './types'; -import { ButtonBorder } from 'design'; +import { ButtonBorder, Flex } from 'design'; import { CarrotDown } from 'design/Icon'; class MenuSshLogin extends React.Component { @@ -100,7 +100,7 @@ export const LoginItemList = ({ logins, onClick, onKeyPress }) => { key={key} px="2" mx="2" - as={NavLink} + as={url ? NavLink : StyledButton} to={url} onClick={(e: Event) => { onClick(e, login); @@ -112,7 +112,7 @@ export const LoginItemList = ({ logins, onClick, onKeyPress }) => { }); return ( - + { autoComplete="off" /> {$menuItems} - + ); }; +const StyledButton = styled.button` + color: inherit; + border: none; + flex: 1; +`; + const StyledMenuItem = styled(MenuItem)( ({ theme }) => ` color: ${theme.colors.grey[400]}; @@ -150,7 +156,7 @@ const Input = styled.input( border: 1px solid ${theme.colors.subtle}; border-radius: 4px; box-sizing: border-box; - color: #263238; + color: ${theme.colors.grey[900]}; height: 32px; outline: none; diff --git a/packages/teleterm/src/ui/DocumentCluster/ClusterResources/Servers/MenuSshLoginTheme.tsx b/packages/teleterm/src/ui/DocumentCluster/ClusterResources/Servers/MenuSshLoginTheme.tsx new file mode 100644 index 000000000..34289f682 --- /dev/null +++ b/packages/teleterm/src/ui/DocumentCluster/ClusterResources/Servers/MenuSshLoginTheme.tsx @@ -0,0 +1,21 @@ +import React, { FC } from 'react'; +import { ThemeProvider } from 'styled-components'; +import theme from 'teleterm/ui/ThemeProvider/theme'; + +const menuSshLoginTheme = { + ...theme, + colors: { + ...theme.colors, + subtle:theme.colors.primary.lighter, + light: theme.colors.primary.dark, + grey: { + [50]: 'rgba(255,255,255,0.05)', + [900]: theme.colors.text.primary, + }, + link: theme.colors.text.primary, + }, +}; + +export const MenuSshLoginTheme: FC = props => ( + +); diff --git a/packages/teleterm/src/ui/DocumentCluster/ClusterResources/Servers/Servers.tsx b/packages/teleterm/src/ui/DocumentCluster/ClusterResources/Servers/Servers.tsx index 8043b9204..bd09dc077 100644 --- a/packages/teleterm/src/ui/DocumentCluster/ClusterResources/Servers/Servers.tsx +++ b/packages/teleterm/src/ui/DocumentCluster/ClusterResources/Servers/Servers.tsx @@ -18,8 +18,9 @@ import React from 'react'; import { useServers, State } from './useServers'; import * as types from 'teleterm/ui/services/clusters/types'; import Table, { Cell } from 'design/DataTable'; -import { ButtonBorder } from 'design'; import { renderLabelCell } from '../renderLabelCell'; +import MenuSshLogin from 'shared/components/MenuSshLogin'; +import { MenuSshLoginTheme } from './MenuSshLoginTheme'; export default function Container() { const state = useServers(); @@ -27,7 +28,7 @@ export default function Container() { } function ServerList(props: State) { - const { servers = [], connect } = props; + const { servers = [], getSshLogins, connect } = props; return ( renderConnectCell(server.uri, connect), + render: server => + renderConnectCell( + () => getSshLogins(server.uri), + login => connect(server.uri, login) + ), }, ]} emptyText="No Nodes Found" @@ -60,19 +65,25 @@ function ServerList(props: State) { } const renderConnectCell = ( - serverUri: string, - connect: (serverUri: string) => void + getSshLogins: () => string[], + onConnect: (login: string) => void ) => { return ( - { - connect(serverUri); - }} - > - Connect - + + getSshLogins().map(login => ({ login, url: '' }))} + onSelect={(e, login) => onConnect(login)} + transformOrigin={{ + vertical: 'top', + horizontal: 'right', + }} + anchorOrigin={{ + vertical: 'center', + horizontal: 'right', + }} + /> + ); }; @@ -87,4 +98,4 @@ const renderAddressCell = ({ addr, tunnel }: types.Server) => ( )} {!tunnel && addr} -); +); \ No newline at end of file diff --git a/packages/teleterm/src/ui/DocumentCluster/ClusterResources/Servers/useServers.ts b/packages/teleterm/src/ui/DocumentCluster/ClusterResources/Servers/useServers.ts index b845e2416..832ee9083 100644 --- a/packages/teleterm/src/ui/DocumentCluster/ClusterResources/Servers/useServers.ts +++ b/packages/teleterm/src/ui/DocumentCluster/ClusterResources/Servers/useServers.ts @@ -15,16 +15,39 @@ limitations under the License. */ import { useClusterContext } from 'teleterm/ui/DocumentCluster/clusterContext'; +import { useAppContext } from 'teleterm/ui/appContextProvider'; export function useServers() { - const ctx = useClusterContext(); - const servers = ctx.getServers(); - const syncStatus = ctx.getSyncStatus().servers; + const appContext = useAppContext(); + const clusterContext = useClusterContext(); + const servers = clusterContext.getServers(); + const syncStatus = clusterContext.getSyncStatus().servers; + + function getSshLogins(serverUri: string): string[] { + const cluster = appContext.clustersService.findClusterByResource(serverUri); + return cluster?.loggedInUser?.sshLoginsList || []; + } + + function connect(serverUri: string, login: string): void { + const server = appContext.clustersService.getServer(serverUri); + + const rootCluster = + appContext.clustersService.findRootClusterByResource(serverUri); + const documentsService = + appContext.workspacesService.getWorkspaceDocumentService(rootCluster.uri); + const doc = documentsService.createTshNodeDocument(serverUri); + doc.title = `${login}@${server.hostname}`; + doc.login = login; + + documentsService.add(doc); + documentsService.setLocation(doc.uri); + } return { - connect: ctx.connectServer, servers, syncStatus, + getSshLogins, + connect, }; } diff --git a/packages/teleterm/src/ui/DocumentCluster/clusterContext.tsx b/packages/teleterm/src/ui/DocumentCluster/clusterContext.tsx index 1620c6199..1ff554cfb 100644 --- a/packages/teleterm/src/ui/DocumentCluster/clusterContext.tsx +++ b/packages/teleterm/src/ui/DocumentCluster/clusterContext.tsx @@ -71,10 +71,6 @@ class ClusterContext extends Store { this.appCtx.commandLauncher.executeCommand('kube-connect', { kubeUri }); }; - connectServer = (serverUri: string) => { - this.appCtx.commandLauncher.executeCommand('ssh', { serverUri }); - }; - connectDb = (dbUri: string) => { this.appCtx.commandLauncher.executeCommand('proxy-db', { dbUri }); }; diff --git a/packages/teleterm/src/ui/ModalsHost/ModalsHost.tsx b/packages/teleterm/src/ui/ModalsHost/ModalsHost.tsx index 7eb80e950..5cc9d9b13 100644 --- a/packages/teleterm/src/ui/ModalsHost/ModalsHost.tsx +++ b/packages/teleterm/src/ui/ModalsHost/ModalsHost.tsx @@ -17,7 +17,6 @@ import React from 'react'; import { useAppContext } from 'teleterm/ui/appContextProvider'; import GatewayCreate from 'teleterm/ui/GatewayCreate'; -import ServerConnect from 'teleterm/ui/ServerConnect'; import ClusterRemove from '../ClusterRemove/ClusterRemove'; import { ClusterConnect } from 'teleterm/ui/ClusterConnect'; @@ -51,9 +50,5 @@ export default function ModalsHost() { return ; } - if (dialog.kind === 'server-connect') { - return ; - } - return null; } diff --git a/packages/teleterm/src/ui/ServerConnect/ServerConnect.story.tsx b/packages/teleterm/src/ui/ServerConnect/ServerConnect.story.tsx deleted file mode 100644 index e94138819..000000000 --- a/packages/teleterm/src/ui/ServerConnect/ServerConnect.story.tsx +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright 2020 Gravitational, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React from 'react'; -import { Server } from 'teleterm/services/tshd/types'; -import { ServerConnect } from './ServerConnect'; -import { State } from './useServerConnect'; - -export default { - title: 'Teleterm/ServerConnect', -}; - -export const Story = () => { - const server: Server = { - uri: 'clusters/localhost/servers/hostname3', - tunnel: false, - name: 'server1', - hostname: 'hostname3', - addr: '123.12.12.12', - labelsList: [{ name: 'os', value: 'linux' }], - }; - - const props: State = { - server, - logins: ['a', 'test', 'test2', 'test3', 'test4', 'test5'], - connect: () => null, - onClose: () => null, - }; - - return ; -}; diff --git a/packages/teleterm/src/ui/ServerConnect/ServerConnect.tsx b/packages/teleterm/src/ui/ServerConnect/ServerConnect.tsx deleted file mode 100644 index 5d35044ee..000000000 --- a/packages/teleterm/src/ui/ServerConnect/ServerConnect.tsx +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright 2021 Gravitational, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React from 'react'; -import Select, { Option, DarkStyledSelect } from 'shared/components/Select'; -import { Text, ButtonSecondary } from 'design'; -import Dialog, { - DialogHeader, - DialogContent, - DialogFooter, -} from 'design/Dialog'; -import Validation from 'shared/components/Validation'; -import useServerConnect, { State, Props } from './useServerConnect'; - -export default function Container(props: Props) { - const state = useServerConnect(props); - return ; -} - -export function ServerConnect(props: State) { - const { server, logins, onClose, connect } = props; - const loginOptions = logins.map(l => ({ value: l, label: l })); - const handleOnChange = (option: Option) => { - connect(option.value); - }; - - return ( - - ({ - maxWidth: '600px', - width: '100%', - padding: '20px', - height: '260px', - })} - disableEscapeKeyDown={false} - onClose={onClose} - open={true} - > - - - Connect to {server.hostname} - - - - -