diff --git a/packages/build/.babelrc.js b/packages/build/.babelrc.js index 94f48ec19..5db9da5bd 100644 --- a/packages/build/.babelrc.js +++ b/packages/build/.babelrc.js @@ -42,10 +42,13 @@ module.exports = { development: { plugins: [ ...plugins, - 'babel-plugin-styled-components', + ['babel-plugin-styled-components', { displayName: true, ssr: false }], ], }, }, presets: makePresents(), - plugins, + plugins: [ + ...plugins, + ['babel-plugin-styled-components', { displayName: false, ssr: false }], + ], }; diff --git a/packages/build/package.json b/packages/build/package.json index 35a6f78a2..793d7a1f1 100644 --- a/packages/build/package.json +++ b/packages/build/package.json @@ -44,7 +44,7 @@ "cross-env": "5.0.5", "cross-spawn": "6.0.5", "css-loader": "^6.5.1", - "electron-builder": "22.14.13", + "electron-builder": "23.0.3", "eslint": "^8.3.0", "eslint-import-resolver-webpack": "^0.13.2", "eslint-plugin-babel": "^5.3.1", 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/README.md b/packages/teleterm/README.md index 00d0b3892..d1cc0fed5 100644 --- a/packages/teleterm/README.md +++ b/packages/teleterm/README.md @@ -143,6 +143,6 @@ lib/teleterm/api/protogen/ ```sh $ cd teleport -$ rm -rf ./../webapps/packages/teleterm/src/services/tshd/v1/ && cp -R lib/teleterm/api/protogen/js/v1/ ./../webapps/packages/teleterm/src/services/tshd/ +$ rm -rf ./../webapps/packages/teleterm/src/services/tshd/v1/ && cp -R lib/teleterm/api/protogen/js/v1 ./../webapps/packages/teleterm/src/services/tshd/v1 ``` diff --git a/packages/teleterm/src/mainProcess/contextMenus/clusterContextMenu.ts b/packages/teleterm/src/mainProcess/contextMenus/clusterContextMenu.ts deleted file mode 100644 index bc6eda557..000000000 --- a/packages/teleterm/src/mainProcess/contextMenus/clusterContextMenu.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { ipcMain, ipcRenderer, Menu } from 'electron'; -import { - ClusterContextMenuEventChannel, - ClusterContextMenuEventType, - ClusterContextMenuOptions, -} from '../types'; - -type MainClusterContextMenuOptions = Pick< - ClusterContextMenuOptions, - 'isClusterConnected' ->; - -export function subscribeToClusterContextMenuEvent(): void { - ipcMain.handle( - ClusterContextMenuEventChannel, - (event, options: MainClusterContextMenuOptions) => { - return new Promise(resolve => { - Menu.buildFromTemplate([ - { - label: 'Refresh', - enabled: options.isClusterConnected, - click: () => resolve(ClusterContextMenuEventType.Refresh), - }, - { - type: 'separator', - }, - { - label: 'Login', - enabled: !options.isClusterConnected, - click: () => resolve(ClusterContextMenuEventType.Login), - }, - { - label: 'Logout', - enabled: options.isClusterConnected, - click: () => resolve(ClusterContextMenuEventType.Logout), - }, - { - type: 'separator', - }, - { - label: 'Remove', - click: () => resolve(ClusterContextMenuEventType.Remove), - }, - ]).popup({ - callback: () => resolve(undefined), - }); - }); - } - ); -} - -export async function openClusterContextMenu( - options: ClusterContextMenuOptions -): Promise { - const mainOptions: MainClusterContextMenuOptions = { - isClusterConnected: options.isClusterConnected, - }; - const eventType = await ipcRenderer.invoke( - ClusterContextMenuEventChannel, - mainOptions - ); - switch (eventType) { - case ClusterContextMenuEventType.Refresh: - return options.onRefresh(); - case ClusterContextMenuEventType.Login: - return options.onLogin(); - case ClusterContextMenuEventType.Logout: - return options.onLogout(); - case ClusterContextMenuEventType.Remove: - return options.onRemove(); - } -} \ No newline at end of file diff --git a/packages/teleterm/src/mainProcess/mainProcess.ts b/packages/teleterm/src/mainProcess/mainProcess.ts index 2cee49e44..33cc87903 100644 --- a/packages/teleterm/src/mainProcess/mainProcess.ts +++ b/packages/teleterm/src/mainProcess/mainProcess.ts @@ -10,7 +10,6 @@ import { import { ChildProcess, spawn } from 'child_process'; import { Logger, RuntimeSettings } from 'teleterm/types'; import { getAssetPath } from './runtimeSettings'; -import { subscribeToClusterContextMenuEvent } from './contextMenus/clusterContextMenu'; import { subscribeToTerminalContextMenuEvent } from './contextMenus/terminalContextMenu'; import { ConfigService, @@ -103,7 +102,6 @@ export default class MainProcess { }); subscribeToTerminalContextMenuEvent(); - subscribeToClusterContextMenuEvent(); subscribeToTabContextMenuEvent(); subscribeToConfigServiceEvents(this.configService); } diff --git a/packages/teleterm/src/mainProcess/mainProcessClient.ts b/packages/teleterm/src/mainProcess/mainProcessClient.ts index 9e36bcff1..485c9a194 100644 --- a/packages/teleterm/src/mainProcess/mainProcessClient.ts +++ b/packages/teleterm/src/mainProcess/mainProcessClient.ts @@ -1,5 +1,4 @@ import { ipcRenderer } from 'electron'; -import { openClusterContextMenu } from './contextMenus/clusterContextMenu'; import { openTerminalContextMenu } from './contextMenus/terminalContextMenu'; import { MainProcessClient } from './types'; import { createConfigServiceClient } from '../services/config'; @@ -11,7 +10,6 @@ export default function createMainProcessClient(): MainProcessClient { return ipcRenderer.sendSync('main-process-get-runtime-settings'); }, openTerminalContextMenu, - openClusterContextMenu, openTabContextMenu, configService: createConfigServiceClient(), }; diff --git a/packages/teleterm/src/mainProcess/types.ts b/packages/teleterm/src/mainProcess/types.ts index 5336fa7ac..d6ada96c1 100644 --- a/packages/teleterm/src/mainProcess/types.ts +++ b/packages/teleterm/src/mainProcess/types.ts @@ -18,7 +18,6 @@ export type RuntimeSettings = { export type MainProcessClient = { getRuntimeSettings(): RuntimeSettings; openTerminalContextMenu(): void; - openClusterContextMenu(options: ClusterContextMenuOptions): void; openTabContextMenu(options: TabContextMenuOptions): void; configService: ConfigService; }; @@ -41,18 +40,10 @@ export interface TabContextMenuOptions { onDuplicatePty(): void; } -export const ClusterContextMenuEventChannel = 'ClusterContextMenuEventChannel'; export const TerminalContextMenuEventChannel = 'TerminalContextMenuEventChannel'; export const TabContextMenuEventChannel = 'TabContextMenuEventChannel'; export const ConfigServiceEventChannel = 'ConfigServiceEventChannel'; -export enum ClusterContextMenuEventType { - Refresh = 'Refresh', - Login = 'Login', - Logout = 'Logout', - Remove = 'Remove', -} - export enum TabContextMenuEventType { Close = 'Close', CloseOthers = 'CloseOthers', diff --git a/packages/teleterm/src/services/config/providers/keyboardShortcutsConfigProvider.ts b/packages/teleterm/src/services/config/providers/keyboardShortcutsConfigProvider.ts index 4c0878e7e..aeffe787c 100644 --- a/packages/teleterm/src/services/config/providers/keyboardShortcutsConfigProvider.ts +++ b/packages/teleterm/src/services/config/providers/keyboardShortcutsConfigProvider.ts @@ -20,7 +20,7 @@ export type KeyboardShortcutType = | 'tab-new' | 'tab-previous' | 'tab-next' - | 'focus-global-search' + | 'open-quick-input' | 'toggle-connections' | 'toggle-clusters' | 'toggle-identity'; @@ -44,7 +44,7 @@ export const keyboardShortcutsConfigProvider: ConfigServiceProvider { - const req = new api.LoginRequest() - .setClusterUri(params.clusterUri) - .setSso(ssoParams) - .setLocal(localParams); + const req = new api.LoginRequest().setClusterUri(params.clusterUri); + + // LoginRequest has oneof on `Local` and `Sso`, which means that setting one of them clears + // the other. + if (ssoParams) { + req.setSso(ssoParams); + } else { + req.setLocal(localParams); + } return new Promise((resolve, reject) => { callRef.current = tshd.login(req, err => { diff --git a/packages/teleterm/src/services/tshd/types.ts b/packages/teleterm/src/services/tshd/types.ts index 3ddd8d60b..8bb8071c3 100644 --- a/packages/teleterm/src/services/tshd/types.ts +++ b/packages/teleterm/src/services/tshd/types.ts @@ -48,7 +48,7 @@ export type TshAbortSignal = { export type LoginParams = { clusterUri: string; - oss?: { + sso?: { providerType: string; providerName: string; }; diff --git a/packages/teleterm/src/services/tshd/v1/auth_challenge_grpc_pb.js b/packages/teleterm/src/services/tshd/v1/auth_challenge_grpc_pb.js deleted file mode 100644 index 97b3a2461..000000000 --- a/packages/teleterm/src/services/tshd/v1/auth_challenge_grpc_pb.js +++ /dev/null @@ -1 +0,0 @@ -// GENERATED CODE -- NO SERVICES IN PROTO \ No newline at end of file diff --git a/packages/teleterm/src/services/tshd/v1/auth_challenge_pb.d.ts b/packages/teleterm/src/services/tshd/v1/auth_challenge_pb.d.ts deleted file mode 100644 index 9d4decfa4..000000000 --- a/packages/teleterm/src/services/tshd/v1/auth_challenge_pb.d.ts +++ /dev/null @@ -1,108 +0,0 @@ -// package: teleport.terminal.v1 -// file: v1/auth_challenge.proto - -/* tslint:disable */ -/* eslint-disable */ - -import * as jspb from "google-protobuf"; - -export class AuthChallengeU2F extends jspb.Message { - getKeyHandle(): string; - setKeyHandle(value: string): AuthChallengeU2F; - - getChallenge(): string; - setChallenge(value: string): AuthChallengeU2F; - - getAppId(): string; - setAppId(value: string): AuthChallengeU2F; - - getVersion(): string; - setVersion(value: string): AuthChallengeU2F; - - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): AuthChallengeU2F.AsObject; - static toObject(includeInstance: boolean, msg: AuthChallengeU2F): AuthChallengeU2F.AsObject; - static extensions: {[key: number]: jspb.ExtensionFieldInfo}; - static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; - static serializeBinaryToWriter(message: AuthChallengeU2F, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): AuthChallengeU2F; - static deserializeBinaryFromReader(message: AuthChallengeU2F, reader: jspb.BinaryReader): AuthChallengeU2F; -} - -export namespace AuthChallengeU2F { - export type AsObject = { - keyHandle: string, - challenge: string, - appId: string, - version: string, - } -} - -export class ChallengeU2F extends jspb.Message { - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): ChallengeU2F.AsObject; - static toObject(includeInstance: boolean, msg: ChallengeU2F): ChallengeU2F.AsObject; - static extensions: {[key: number]: jspb.ExtensionFieldInfo}; - static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; - static serializeBinaryToWriter(message: ChallengeU2F, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): ChallengeU2F; - static deserializeBinaryFromReader(message: ChallengeU2F, reader: jspb.BinaryReader): ChallengeU2F; -} - -export namespace ChallengeU2F { - export type AsObject = { - } -} - -export class ChallengeTOTP extends jspb.Message { - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): ChallengeTOTP.AsObject; - static toObject(includeInstance: boolean, msg: ChallengeTOTP): ChallengeTOTP.AsObject; - static extensions: {[key: number]: jspb.ExtensionFieldInfo}; - static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; - static serializeBinaryToWriter(message: ChallengeTOTP, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): ChallengeTOTP; - static deserializeBinaryFromReader(message: ChallengeTOTP, reader: jspb.BinaryReader): ChallengeTOTP; -} - -export namespace ChallengeTOTP { - export type AsObject = { - } -} - -export class SolvedChallengeU2F extends jspb.Message { - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): SolvedChallengeU2F.AsObject; - static toObject(includeInstance: boolean, msg: SolvedChallengeU2F): SolvedChallengeU2F.AsObject; - static extensions: {[key: number]: jspb.ExtensionFieldInfo}; - static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; - static serializeBinaryToWriter(message: SolvedChallengeU2F, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): SolvedChallengeU2F; - static deserializeBinaryFromReader(message: SolvedChallengeU2F, reader: jspb.BinaryReader): SolvedChallengeU2F; -} - -export namespace SolvedChallengeU2F { - export type AsObject = { - } -} - -export class SolvedChallengeTOTP extends jspb.Message { - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): SolvedChallengeTOTP.AsObject; - static toObject(includeInstance: boolean, msg: SolvedChallengeTOTP): SolvedChallengeTOTP.AsObject; - static extensions: {[key: number]: jspb.ExtensionFieldInfo}; - static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; - static serializeBinaryToWriter(message: SolvedChallengeTOTP, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): SolvedChallengeTOTP; - static deserializeBinaryFromReader(message: SolvedChallengeTOTP, reader: jspb.BinaryReader): SolvedChallengeTOTP; -} - -export namespace SolvedChallengeTOTP { - export type AsObject = { - } -} diff --git a/packages/teleterm/src/services/tshd/v1/auth_challenge_pb.js b/packages/teleterm/src/services/tshd/v1/auth_challenge_pb.js deleted file mode 100644 index 2005ba5f3..000000000 --- a/packages/teleterm/src/services/tshd/v1/auth_challenge_pb.js +++ /dev/null @@ -1,749 +0,0 @@ -// source: v1/auth_challenge.proto -/** - * @fileoverview - * @enhanceable - * @suppress {messageConventions} JS Compiler reports an error if a variable or - * field starts with 'MSG_' and isn't a translatable message. - * @public - */ -// GENERATED CODE -- DO NOT EDIT! - -var jspb = require('google-protobuf'); -var goog = jspb; -var global = Function('return this')(); - -goog.exportSymbol('proto.teleport.terminal.v1.AuthChallengeU2F', null, global); -goog.exportSymbol('proto.teleport.terminal.v1.ChallengeTOTP', null, global); -goog.exportSymbol('proto.teleport.terminal.v1.ChallengeU2F', null, global); -goog.exportSymbol('proto.teleport.terminal.v1.SolvedChallengeTOTP', null, global); -goog.exportSymbol('proto.teleport.terminal.v1.SolvedChallengeU2F', null, global); -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.teleport.terminal.v1.AuthChallengeU2F = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.teleport.terminal.v1.AuthChallengeU2F, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.teleport.terminal.v1.AuthChallengeU2F.displayName = 'proto.teleport.terminal.v1.AuthChallengeU2F'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.teleport.terminal.v1.ChallengeU2F = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.teleport.terminal.v1.ChallengeU2F, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.teleport.terminal.v1.ChallengeU2F.displayName = 'proto.teleport.terminal.v1.ChallengeU2F'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.teleport.terminal.v1.ChallengeTOTP = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.teleport.terminal.v1.ChallengeTOTP, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.teleport.terminal.v1.ChallengeTOTP.displayName = 'proto.teleport.terminal.v1.ChallengeTOTP'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.teleport.terminal.v1.SolvedChallengeU2F = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.teleport.terminal.v1.SolvedChallengeU2F, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.teleport.terminal.v1.SolvedChallengeU2F.displayName = 'proto.teleport.terminal.v1.SolvedChallengeU2F'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.teleport.terminal.v1.SolvedChallengeTOTP = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.teleport.terminal.v1.SolvedChallengeTOTP, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.teleport.terminal.v1.SolvedChallengeTOTP.displayName = 'proto.teleport.terminal.v1.SolvedChallengeTOTP'; -} - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.teleport.terminal.v1.AuthChallengeU2F.prototype.toObject = function(opt_includeInstance) { - return proto.teleport.terminal.v1.AuthChallengeU2F.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.teleport.terminal.v1.AuthChallengeU2F} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.teleport.terminal.v1.AuthChallengeU2F.toObject = function(includeInstance, msg) { - var f, obj = { - keyHandle: jspb.Message.getFieldWithDefault(msg, 1, ""), - challenge: jspb.Message.getFieldWithDefault(msg, 2, ""), - appId: jspb.Message.getFieldWithDefault(msg, 3, ""), - version: jspb.Message.getFieldWithDefault(msg, 4, "") - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.teleport.terminal.v1.AuthChallengeU2F} - */ -proto.teleport.terminal.v1.AuthChallengeU2F.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.teleport.terminal.v1.AuthChallengeU2F; - return proto.teleport.terminal.v1.AuthChallengeU2F.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.teleport.terminal.v1.AuthChallengeU2F} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.teleport.terminal.v1.AuthChallengeU2F} - */ -proto.teleport.terminal.v1.AuthChallengeU2F.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setKeyHandle(value); - break; - case 2: - var value = /** @type {string} */ (reader.readString()); - msg.setChallenge(value); - break; - case 3: - var value = /** @type {string} */ (reader.readString()); - msg.setAppId(value); - break; - case 4: - var value = /** @type {string} */ (reader.readString()); - msg.setVersion(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.teleport.terminal.v1.AuthChallengeU2F.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.teleport.terminal.v1.AuthChallengeU2F.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.teleport.terminal.v1.AuthChallengeU2F} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.teleport.terminal.v1.AuthChallengeU2F.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getKeyHandle(); - if (f.length > 0) { - writer.writeString( - 1, - f - ); - } - f = message.getChallenge(); - if (f.length > 0) { - writer.writeString( - 2, - f - ); - } - f = message.getAppId(); - if (f.length > 0) { - writer.writeString( - 3, - f - ); - } - f = message.getVersion(); - if (f.length > 0) { - writer.writeString( - 4, - f - ); - } -}; - - -/** - * optional string key_handle = 1; - * @return {string} - */ -proto.teleport.terminal.v1.AuthChallengeU2F.prototype.getKeyHandle = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); -}; - - -/** - * @param {string} value - * @return {!proto.teleport.terminal.v1.AuthChallengeU2F} returns this - */ -proto.teleport.terminal.v1.AuthChallengeU2F.prototype.setKeyHandle = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); -}; - - -/** - * optional string challenge = 2; - * @return {string} - */ -proto.teleport.terminal.v1.AuthChallengeU2F.prototype.getChallenge = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); -}; - - -/** - * @param {string} value - * @return {!proto.teleport.terminal.v1.AuthChallengeU2F} returns this - */ -proto.teleport.terminal.v1.AuthChallengeU2F.prototype.setChallenge = function(value) { - return jspb.Message.setProto3StringField(this, 2, value); -}; - - -/** - * optional string app_id = 3; - * @return {string} - */ -proto.teleport.terminal.v1.AuthChallengeU2F.prototype.getAppId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); -}; - - -/** - * @param {string} value - * @return {!proto.teleport.terminal.v1.AuthChallengeU2F} returns this - */ -proto.teleport.terminal.v1.AuthChallengeU2F.prototype.setAppId = function(value) { - return jspb.Message.setProto3StringField(this, 3, value); -}; - - -/** - * optional string version = 4; - * @return {string} - */ -proto.teleport.terminal.v1.AuthChallengeU2F.prototype.getVersion = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, "")); -}; - - -/** - * @param {string} value - * @return {!proto.teleport.terminal.v1.AuthChallengeU2F} returns this - */ -proto.teleport.terminal.v1.AuthChallengeU2F.prototype.setVersion = function(value) { - return jspb.Message.setProto3StringField(this, 4, value); -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.teleport.terminal.v1.ChallengeU2F.prototype.toObject = function(opt_includeInstance) { - return proto.teleport.terminal.v1.ChallengeU2F.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.teleport.terminal.v1.ChallengeU2F} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.teleport.terminal.v1.ChallengeU2F.toObject = function(includeInstance, msg) { - var f, obj = { - - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.teleport.terminal.v1.ChallengeU2F} - */ -proto.teleport.terminal.v1.ChallengeU2F.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.teleport.terminal.v1.ChallengeU2F; - return proto.teleport.terminal.v1.ChallengeU2F.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.teleport.terminal.v1.ChallengeU2F} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.teleport.terminal.v1.ChallengeU2F} - */ -proto.teleport.terminal.v1.ChallengeU2F.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.teleport.terminal.v1.ChallengeU2F.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.teleport.terminal.v1.ChallengeU2F.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.teleport.terminal.v1.ChallengeU2F} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.teleport.terminal.v1.ChallengeU2F.serializeBinaryToWriter = function(message, writer) { - var f = undefined; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.teleport.terminal.v1.ChallengeTOTP.prototype.toObject = function(opt_includeInstance) { - return proto.teleport.terminal.v1.ChallengeTOTP.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.teleport.terminal.v1.ChallengeTOTP} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.teleport.terminal.v1.ChallengeTOTP.toObject = function(includeInstance, msg) { - var f, obj = { - - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.teleport.terminal.v1.ChallengeTOTP} - */ -proto.teleport.terminal.v1.ChallengeTOTP.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.teleport.terminal.v1.ChallengeTOTP; - return proto.teleport.terminal.v1.ChallengeTOTP.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.teleport.terminal.v1.ChallengeTOTP} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.teleport.terminal.v1.ChallengeTOTP} - */ -proto.teleport.terminal.v1.ChallengeTOTP.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.teleport.terminal.v1.ChallengeTOTP.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.teleport.terminal.v1.ChallengeTOTP.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.teleport.terminal.v1.ChallengeTOTP} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.teleport.terminal.v1.ChallengeTOTP.serializeBinaryToWriter = function(message, writer) { - var f = undefined; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.teleport.terminal.v1.SolvedChallengeU2F.prototype.toObject = function(opt_includeInstance) { - return proto.teleport.terminal.v1.SolvedChallengeU2F.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.teleport.terminal.v1.SolvedChallengeU2F} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.teleport.terminal.v1.SolvedChallengeU2F.toObject = function(includeInstance, msg) { - var f, obj = { - - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.teleport.terminal.v1.SolvedChallengeU2F} - */ -proto.teleport.terminal.v1.SolvedChallengeU2F.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.teleport.terminal.v1.SolvedChallengeU2F; - return proto.teleport.terminal.v1.SolvedChallengeU2F.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.teleport.terminal.v1.SolvedChallengeU2F} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.teleport.terminal.v1.SolvedChallengeU2F} - */ -proto.teleport.terminal.v1.SolvedChallengeU2F.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.teleport.terminal.v1.SolvedChallengeU2F.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.teleport.terminal.v1.SolvedChallengeU2F.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.teleport.terminal.v1.SolvedChallengeU2F} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.teleport.terminal.v1.SolvedChallengeU2F.serializeBinaryToWriter = function(message, writer) { - var f = undefined; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.teleport.terminal.v1.SolvedChallengeTOTP.prototype.toObject = function(opt_includeInstance) { - return proto.teleport.terminal.v1.SolvedChallengeTOTP.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.teleport.terminal.v1.SolvedChallengeTOTP} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.teleport.terminal.v1.SolvedChallengeTOTP.toObject = function(includeInstance, msg) { - var f, obj = { - - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.teleport.terminal.v1.SolvedChallengeTOTP} - */ -proto.teleport.terminal.v1.SolvedChallengeTOTP.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.teleport.terminal.v1.SolvedChallengeTOTP; - return proto.teleport.terminal.v1.SolvedChallengeTOTP.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.teleport.terminal.v1.SolvedChallengeTOTP} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.teleport.terminal.v1.SolvedChallengeTOTP} - */ -proto.teleport.terminal.v1.SolvedChallengeTOTP.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.teleport.terminal.v1.SolvedChallengeTOTP.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.teleport.terminal.v1.SolvedChallengeTOTP.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.teleport.terminal.v1.SolvedChallengeTOTP} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.teleport.terminal.v1.SolvedChallengeTOTP.serializeBinaryToWriter = function(message, writer) { - var f = undefined; -}; - - -goog.object.extend(exports, proto.teleport.terminal.v1); diff --git a/packages/teleterm/src/services/tshd/v1/cluster_pb.js b/packages/teleterm/src/services/tshd/v1/cluster_pb.js index 6fbf12ccf..3e023f7f0 100644 --- a/packages/teleterm/src/services/tshd/v1/cluster_pb.js +++ b/packages/teleterm/src/services/tshd/v1/cluster_pb.js @@ -792,7 +792,7 @@ proto.teleport.terminal.v1.ACL.deserializeBinaryFromReader = function(msg, reade reader.readMessage(value,proto.teleport.terminal.v1.ResourceAccess.deserializeBinaryFromReader); msg.setKubeservers(value); break; - case 13: + case 12: var value = new proto.teleport.terminal.v1.ResourceAccess; reader.readMessage(value,proto.teleport.terminal.v1.ResourceAccess.deserializeBinaryFromReader); msg.setAccessRequests(value); @@ -917,7 +917,7 @@ proto.teleport.terminal.v1.ACL.serializeBinaryToWriter = function(message, write f = message.getAccessRequests(); if (f != null) { writer.writeMessage( - 13, + 12, f, proto.teleport.terminal.v1.ResourceAccess.serializeBinaryToWriter ); @@ -1333,12 +1333,12 @@ proto.teleport.terminal.v1.ACL.prototype.hasKubeservers = function() { /** - * optional ResourceAccess access_requests = 13; + * optional ResourceAccess access_requests = 12; * @return {?proto.teleport.terminal.v1.ResourceAccess} */ proto.teleport.terminal.v1.ACL.prototype.getAccessRequests = function() { return /** @type{?proto.teleport.terminal.v1.ResourceAccess} */ ( - jspb.Message.getWrapperField(this, proto.teleport.terminal.v1.ResourceAccess, 13)); + jspb.Message.getWrapperField(this, proto.teleport.terminal.v1.ResourceAccess, 12)); }; @@ -1347,7 +1347,7 @@ proto.teleport.terminal.v1.ACL.prototype.getAccessRequests = function() { * @return {!proto.teleport.terminal.v1.ACL} returns this */ proto.teleport.terminal.v1.ACL.prototype.setAccessRequests = function(value) { - return jspb.Message.setWrapperField(this, 13, value); + return jspb.Message.setWrapperField(this, 12, value); }; @@ -1365,7 +1365,7 @@ proto.teleport.terminal.v1.ACL.prototype.clearAccessRequests = function() { * @return {boolean} */ proto.teleport.terminal.v1.ACL.prototype.hasAccessRequests = function() { - return jspb.Message.getField(this, 13) != null; + return jspb.Message.getField(this, 12) != null; }; diff --git a/packages/teleterm/src/services/tshd/v1/service_grpc_pb.js b/packages/teleterm/src/services/tshd/v1/service_grpc_pb.js index bad0aa6a8..32469d2d1 100644 --- a/packages/teleterm/src/services/tshd/v1/service_grpc_pb.js +++ b/packages/teleterm/src/services/tshd/v1/service_grpc_pb.js @@ -1,5 +1,20 @@ // GENERATED CODE -- DO NOT EDIT! +// Original file comments: +// 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. +// 'use strict'; var grpc = require('@grpc/grpc-js'); var v1_service_pb = require('../v1/service_pb.js'); diff --git a/packages/teleterm/src/services/tshd/v1/service_pb.d.ts b/packages/teleterm/src/services/tshd/v1/service_pb.d.ts index aa2fc3d51..c5ae913d8 100644 --- a/packages/teleterm/src/services/tshd/v1/service_pb.d.ts +++ b/packages/teleterm/src/services/tshd/v1/service_pb.d.ts @@ -94,6 +94,8 @@ export class LoginRequest extends jspb.Message { setSso(value?: LoginRequest.SsoParams): LoginRequest; + getParamsCase(): LoginRequest.ParamsCase; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): LoginRequest.AsObject; static toObject(includeInstance: boolean, msg: LoginRequest): LoginRequest.AsObject; @@ -166,6 +168,16 @@ export namespace LoginRequest { } } + + export enum ParamsCase { + PARAMS_NOT_SET = 0, + + LOCAL = 2, + + SSO = 3, + + } + } export class AddClusterRequest extends jspb.Message { diff --git a/packages/teleterm/src/services/tshd/v1/service_pb.js b/packages/teleterm/src/services/tshd/v1/service_pb.js index b0486c3c7..04996fb15 100644 --- a/packages/teleterm/src/services/tshd/v1/service_pb.js +++ b/packages/teleterm/src/services/tshd/v1/service_pb.js @@ -48,6 +48,7 @@ goog.exportSymbol('proto.teleport.terminal.v1.ListServersRequest', null, global) goog.exportSymbol('proto.teleport.terminal.v1.ListServersResponse', null, global); goog.exportSymbol('proto.teleport.terminal.v1.LoginRequest', null, global); goog.exportSymbol('proto.teleport.terminal.v1.LoginRequest.LocalParams', null, global); +goog.exportSymbol('proto.teleport.terminal.v1.LoginRequest.ParamsCase', null, global); goog.exportSymbol('proto.teleport.terminal.v1.LoginRequest.SsoParams', null, global); goog.exportSymbol('proto.teleport.terminal.v1.LogoutRequest', null, global); goog.exportSymbol('proto.teleport.terminal.v1.RemoveClusterRequest', null, global); @@ -126,7 +127,7 @@ if (goog.DEBUG && !COMPILED) { * @constructor */ proto.teleport.terminal.v1.LoginRequest = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.teleport.terminal.v1.LoginRequest.oneofGroups_); }; goog.inherits(proto.teleport.terminal.v1.LoginRequest, jspb.Message); if (goog.DEBUG && !COMPILED) { @@ -947,6 +948,32 @@ proto.teleport.terminal.v1.LogoutRequest.prototype.setClusterUri = function(valu +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.teleport.terminal.v1.LoginRequest.oneofGroups_ = [[2,3]]; + +/** + * @enum {number} + */ +proto.teleport.terminal.v1.LoginRequest.ParamsCase = { + PARAMS_NOT_SET: 0, + LOCAL: 2, + SSO: 3 +}; + +/** + * @return {proto.teleport.terminal.v1.LoginRequest.ParamsCase} + */ +proto.teleport.terminal.v1.LoginRequest.prototype.getParamsCase = function() { + return /** @type {proto.teleport.terminal.v1.LoginRequest.ParamsCase} */(jspb.Message.computeOneofCase(this, proto.teleport.terminal.v1.LoginRequest.oneofGroups_[0])); +}; + if (jspb.Message.GENERATE_TO_OBJECT) { @@ -1469,7 +1496,7 @@ proto.teleport.terminal.v1.LoginRequest.prototype.getLocal = function() { * @return {!proto.teleport.terminal.v1.LoginRequest} returns this */ proto.teleport.terminal.v1.LoginRequest.prototype.setLocal = function(value) { - return jspb.Message.setWrapperField(this, 2, value); + return jspb.Message.setOneofWrapperField(this, 2, proto.teleport.terminal.v1.LoginRequest.oneofGroups_[0], value); }; @@ -1506,7 +1533,7 @@ proto.teleport.terminal.v1.LoginRequest.prototype.getSso = function() { * @return {!proto.teleport.terminal.v1.LoginRequest} returns this */ proto.teleport.terminal.v1.LoginRequest.prototype.setSso = function(value) { - return jspb.Message.setWrapperField(this, 3, value); + return jspb.Message.setOneofWrapperField(this, 3, proto.teleport.terminal.v1.LoginRequest.oneofGroups_[0], value); }; diff --git a/packages/teleterm/src/ui/ClusterConnect/ClusterAdd/ClusterAdd.tsx b/packages/teleterm/src/ui/ClusterConnect/ClusterAdd/ClusterAdd.tsx index acc0c8637..2a6d7adc1 100644 --- a/packages/teleterm/src/ui/ClusterConnect/ClusterAdd/ClusterAdd.tsx +++ b/packages/teleterm/src/ui/ClusterConnect/ClusterAdd/ClusterAdd.tsx @@ -53,7 +53,7 @@ export function ClusterAddPresentation({ value={addr} autoFocus onChange={e => setAddr(e.target.value)} - placeholder="https://cluster" + placeholder="teleport.example.com" /> ; + const state = useClusterLogout(props); + return ; } -export function ClusterRemove({ +export function ClusterLogout({ status, onClose, statusText, @@ -41,41 +42,41 @@ export function ClusterRemove({ open={true} onClose={onClose} dialogCss={() => ({ - maxWidth: '380px', + maxWidth: '400px', width: '100%', })} > - - - Remove Cluster {clusterTitle} + + + Log out from cluster {clusterTitle} + + + - - - Are you sure you want to remove cluster? + + + Are you sure you want to log out? {status === 'error' && } { e.preventDefault(); removeCluster(); }} > - Remove + Log out - { - e.preventDefault(); - onClose(); - }} - > - Cancel - ); diff --git a/packages/teleterm/src/ui/ClusterLogout/index.ts b/packages/teleterm/src/ui/ClusterLogout/index.ts new file mode 100644 index 000000000..08670575b --- /dev/null +++ b/packages/teleterm/src/ui/ClusterLogout/index.ts @@ -0,0 +1 @@ +export * from './ClusterLogout'; \ No newline at end of file diff --git a/packages/teleterm/src/ui/ClusterLogout/useClusterLogout.ts b/packages/teleterm/src/ui/ClusterLogout/useClusterLogout.ts new file mode 100644 index 000000000..c0ee5da27 --- /dev/null +++ b/packages/teleterm/src/ui/ClusterLogout/useClusterLogout.ts @@ -0,0 +1,45 @@ +import { useAppContext } from '../appContextProvider'; +import useAsync from '../useAsync'; +import { useEffect } from 'react'; + +export function useClusterLogout({ clusterUri, onClose, clusterTitle }: Props) { + const ctx = useAppContext(); + const [{ status, statusText }, removeCluster] = useAsync(async () => { + // TODO(gzdunek): logout and removeCluster should be combined into a single acton in tshd + await ctx.clustersService.logout(clusterUri); + await ctx.clustersService.removeCluster(clusterUri); + + if (ctx.workspacesService.getRootClusterUri() === clusterUri) { + const [firstConnectedWorkspace] = + ctx.workspacesService.getConnectedWorkspacesClustersUri(); + if (firstConnectedWorkspace) { + await ctx.workspacesService.setActiveWorkspace(firstConnectedWorkspace); + } else { + await ctx.workspacesService.setActiveWorkspace(null); + } + } + }); + + useEffect(() => { + if (status === 'success') { + onClose(); + } + }, [status]); + + return { + status, + statusText, + removeCluster, + onClose, + clusterUri, + clusterTitle, + }; +} + +export type Props = { + onClose(): void; + clusterTitle: string; + clusterUri: string; +}; + +export type State = ReturnType; diff --git a/packages/teleterm/src/ui/ClusterRemove/index.ts b/packages/teleterm/src/ui/ClusterRemove/index.ts deleted file mode 100644 index f6246fb1b..000000000 --- a/packages/teleterm/src/ui/ClusterRemove/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './ClusterRemove'; \ No newline at end of file diff --git a/packages/teleterm/src/ui/ClusterRemove/useClusterRemove.ts b/packages/teleterm/src/ui/ClusterRemove/useClusterRemove.ts deleted file mode 100644 index e1456c129..000000000 --- a/packages/teleterm/src/ui/ClusterRemove/useClusterRemove.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { useAppContext } from '../appContextProvider'; -import useAsync from '../useAsync'; -import { useEffect } from 'react'; - -export function useClusterRemove({ clusterUri, onClose, clusterTitle }: Props) { - const ctx = useAppContext(); - const [{ status, statusText }, removeCluster] = useAsync(() => { - return ctx.clustersService.removeCluster(clusterUri); - }); - - useEffect(() => { - if (status === 'success') { - onClose(); - } - }, [status]); - - return { - status, - statusText, - removeCluster, - onClose, - clusterUri, - clusterTitle, - }; -} - -export type Props = { - onClose(): void; - clusterTitle: string; - clusterUri: string; -}; - -export type State = ReturnType; 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 5e70904d2..11e820cb4 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, Label } 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', + }} + /> + ); }; @@ -88,3 +99,4 @@ const renderAddressCell = ({ addr, tunnel }: types.Server) => ( {!tunnel && addr} ); + 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/ClusterResources/SideNav/SideNav.tsx b/packages/teleterm/src/ui/DocumentCluster/ClusterResources/SideNav/SideNav.tsx index 7e34b3974..984431441 100644 --- a/packages/teleterm/src/ui/DocumentCluster/ClusterResources/SideNav/SideNav.tsx +++ b/packages/teleterm/src/ui/DocumentCluster/ClusterResources/SideNav/SideNav.tsx @@ -60,8 +60,8 @@ const StyledNav = styled(Flex)` function createItems(ctx: ClusterContext): SideNavItem[] { const serverCount = ctx.getServers().length; const dbCount = ctx.getDbs().length; - const kubeCount = ctx.getKubes().length; - const appCount = ctx.getApps().length; + // const kubeCount = ctx.getKubes().length; + // const appCount = ctx.getApps().length; return [ { @@ -72,13 +72,13 @@ function createItems(ctx: ClusterContext): SideNavItem[] { to: '/resources/databases', title: `Databases (${dbCount})`, }, - { - to: '/resources/kubes', - title: `Kubes (${kubeCount})`, - }, - { - to: '/resources/apps', - title: `Apps (${appCount})`, - }, + // { + // to: '/resources/kubes', + // title: `Kubes (${kubeCount})`, + // }, + // { + // to: '/resources/apps', + // title: `Apps (${appCount})`, + // }, ]; } 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/DocumentGateway/useDocumentGateway.ts b/packages/teleterm/src/ui/DocumentGateway/useDocumentGateway.ts index ccda14e61..f35e2192a 100644 --- a/packages/teleterm/src/ui/DocumentGateway/useDocumentGateway.ts +++ b/packages/teleterm/src/ui/DocumentGateway/useDocumentGateway.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, { useEffect } from 'react'; import { useAppContext } from 'teleterm/ui/appContextProvider'; import * as types from 'teleterm/ui/services/workspacesService'; import useAsync from 'teleterm/ui/useAsync'; @@ -25,6 +25,7 @@ export default function useGateway(doc: types.DocumentGateway) { const workspaceDocumentsService = useWorkspaceDocumentsService(); const gateway = ctx.clustersService.findGateway(doc.gatewayUri); const connected = !!gateway; + const cluster = ctx.clustersService.findRootClusterByResource(doc.targetUri); const [connectAttempt, createGateway, setConnectAttempt] = useAsync( async () => { @@ -45,10 +46,7 @@ export default function useGateway(doc: types.DocumentGateway) { }); const reconnect = () => { - const cluster = ctx.clustersService.findRootClusterByResource( - doc.targetUri - ); - if (cluster && cluster.connected) { + if (cluster?.connected) { createGateway(); return; } @@ -75,6 +73,12 @@ export default function useGateway(doc: types.DocumentGateway) { } }, [disconnectAttempt.status]); + useEffect(() => { + if (cluster.connected) { + createGateway(); + } + }, [cluster.connected]); + return { doc, gateway, diff --git a/packages/teleterm/src/ui/DocumentTerminal/useDocumentTerminal.ts b/packages/teleterm/src/ui/DocumentTerminal/useDocumentTerminal.ts index 5be6bb771..9dc13439a 100644 --- a/packages/teleterm/src/ui/DocumentTerminal/useDocumentTerminal.ts +++ b/packages/teleterm/src/ui/DocumentTerminal/useDocumentTerminal.ts @@ -73,8 +73,19 @@ async function initState( removeInitCommand(); }); - ptyProcess.onExit(() => { - docsService.close(doc.uri); + ptyProcess.onExit(event => { + // Not closing the tab on non-zero exit code lets us show the error to the user if, for example, + // tsh ssh cannot connect to the given node. + // + // The downside of this is that if you open a local shell, then execute a command that fails + // (for example, `cd` to a nonexistent directory), and then try to execute `exit` or press + // Ctrl + D, the tab won't automatically close, because the last exit code is not zero. + // + // We can look up how the terminal in vscode handles this problem, since in the scenario + // described above they do close the tab correctly. + if (event.exitCode === 0) { + docsService.close(doc.uri); + } }); return { diff --git a/packages/teleterm/src/ui/DocumentTerminal/useReconnect.ts b/packages/teleterm/src/ui/DocumentTerminal/useReconnect.ts index 1203e6701..841346967 100644 --- a/packages/teleterm/src/ui/DocumentTerminal/useReconnect.ts +++ b/packages/teleterm/src/ui/DocumentTerminal/useReconnect.ts @@ -18,20 +18,25 @@ import { useAppContext } from 'teleterm/ui/appContextProvider'; import * as types from 'teleterm/ui/services/workspacesService'; import useAttempt from 'shared/hooks/useAttemptNext'; import { useWorkspaceDocumentsService } from 'teleterm/ui/Documents'; +import { useEffect } from 'react'; export function useReconnect(doc: types.DocumentTshNode) { const ctx = useAppContext(); const workspaceDocumentsService = useWorkspaceDocumentsService(); const { attempt, setAttempt } = useAttempt(''); + const cluster = ctx.clustersService.findRootClusterByResource(doc.serverUri); - function updateDoc() { + function markDocumentAsConnected() { workspaceDocumentsService.update(doc.uri, { status: 'connected' }); } + useEffect(() => { + if (cluster.connected) { + markDocumentAsConnected(); + } + }, []); + function reconnect() { - const cluster = ctx.clustersService.findRootClusterByResource( - doc.serverUri - ); if (!cluster) { setAttempt({ status: 'failed', @@ -44,13 +49,13 @@ export function useReconnect(doc: types.DocumentTshNode) { if (!cluster.connected) { ctx.commandLauncher.executeCommand('cluster-connect', { clusterUri: cluster.uri, - onSuccess: updateDoc, + onSuccess: markDocumentAsConnected, }); return; } - updateDoc(); + markDocumentAsConnected(); } return { reconnect, attempt }; diff --git a/packages/teleterm/src/ui/ModalsHost/ModalsHost.tsx b/packages/teleterm/src/ui/ModalsHost/ModalsHost.tsx index 7eb80e950..dc282c096 100644 --- a/packages/teleterm/src/ui/ModalsHost/ModalsHost.tsx +++ b/packages/teleterm/src/ui/ModalsHost/ModalsHost.tsx @@ -17,8 +17,7 @@ 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 ClusterLogout from '../ClusterLogout/ClusterLogout'; import { ClusterConnect } from 'teleterm/ui/ClusterConnect'; export default function ModalsHost() { @@ -37,9 +36,9 @@ export default function ModalsHost() { ); } - if (dialog.kind === 'cluster-remove') { + if (dialog.kind === 'cluster-logout') { return ( - ; } - if (dialog.kind === 'server-connect') { - return ; - } - return null; } diff --git a/packages/teleterm/src/ui/Navigator/Expander.tsx b/packages/teleterm/src/ui/Navigator/Expander.tsx deleted file mode 100644 index 2efc35774..000000000 --- a/packages/teleterm/src/ui/Navigator/Expander.tsx +++ /dev/null @@ -1,118 +0,0 @@ -/* -Copyright 2019 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 styled from 'styled-components'; -import { space, color } from 'design/system'; -import * as Icons from 'design/Icon'; -import { Flex } from 'design'; - -const AccordingContext = React.createContext(null); - -const Expander: React.FC = props => { - const [expanded, setExpanded] = React.useState(true); - const [header, ...children] = React.Children.toArray(props.children); - const toggle = () => setExpanded(!expanded); - - return ( - - {header} - {children} - - ); -}; - -export const ExpanderHeader: React.FC = props => { - const { onContextMenu, children, ...styles } = props; - const ctx = React.useContext(AccordingContext); - const ArrowIcon = ctx.expanded ? Icons.CarrotDown : Icons.CarrotRight; - - return ( - - - - {children} - - - ); -}; - -export const ExpanderContent = styled(Flex)(props => { - const ctx = React.useContext(AccordingContext); - return { - display: ctx.expanded ? 'block' : 'none', - color: props.theme.colors.text.secondary, - flexDirection: 'column', - }; -}); - -export default Expander; - -export const StyledHeader = styled(Flex)(props => { - const theme = props.theme; - return { - width: '100%', - margin: '0', - boxSizing: 'border-box', - display: 'flex', - alignItems: 'center', - justifyContent: 'flex-start', - border: 'none', - cursor: 'pointer', - outline: 'none', - textDecoration: 'none', - lineHeight: '24px', - fontSize: '12px', - fontWeight: theme.regular, - fontFamily: theme.font, - paddingLeft: theme.space[2] + 'px', - background: theme.colors.primary.main, - color: theme.colors.text.primary, - '&.active': { - borderLeftColor: theme.colors.accent, - background: theme.colors.primary.lighter, - color: theme.colors.primary.contrastText, - '.marker': { - background: theme.colors.secondary.light, - }, - }, - - '&:hover, &:focus': { - color: theme.colors.primary.contrastText, - background: theme.colors.primary.light, - }, - - height: '36px', - ...space(props), - ...color(props), - }; -}); - -type AccordingContextState = { - expanded: boolean; - toggle(): void; -}; - -type ExpanderHeaderProps = { - onClick?: () => void; - onContextMenu?: () => void; - [key: string]: any; -}; diff --git a/packages/teleterm/src/ui/Navigator/ExpanderClusters/ExpanderClusters.story.tsx b/packages/teleterm/src/ui/Navigator/ExpanderClusters/ExpanderClusters.story.tsx deleted file mode 100644 index 6fe20ecba..000000000 --- a/packages/teleterm/src/ui/Navigator/ExpanderClusters/ExpanderClusters.story.tsx +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Copyright 2022 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 { ExpanderClustersPresentational } from 'teleterm/ui/Navigator/ExpanderClusters/ExpanderClusters'; -import { MockAppContextProvider } from 'teleterm/ui/fixtures/MockAppContextProvider'; -import { ExpanderClusterState } from './types'; - -export default { - title: 'Teleterm/Navigator/ExpanderClusters', -}; - -function getState(): ExpanderClusterState { - return { - onAddCluster() {}, - onSyncClusters() {}, - onOpenContextMenu() {}, - onOpen() {}, - items: [ - { - clusterUri: '/clusters/root1.teleport.sh', - title: 'root1.teleport.sh', - syncing: false, - connected: false, - active: false, - }, - { - clusterUri: '/clusters/root2.teleport.sh', - title: 'root2.teleport.sh', - syncing: false, - connected: true, - active: true, - }, - { - clusterUri: '/clusters/root3.teleport.sh', - title: 'root3.teleport.sh', - connected: true, - syncing: false, - active: false, - leaves: [ - { - clusterUri: - '/clusters/root3.teleport.sh/leaves/internal1.example.com', - title: 'internal1.example.com', - syncing: false, - connected: false, - active: false, - }, - { - clusterUri: - '/clusters/root3.teleport.sh/leaves/internal2.example.com', - title: 'internal2.example.com', - syncing: false, - connected: true, - active: false, - }, - ], - }, - ], - }; -} - -export function Syncing() { - const state = getState(); - state.items.forEach(i => { - i.syncing = true; - }); - return ( - - - - ); -} - -export function ClusterItems() { - const state = getState(); - return ( - - - - ); -} diff --git a/packages/teleterm/src/ui/Navigator/ExpanderClusters/ExpanderClusters.test.tsx b/packages/teleterm/src/ui/Navigator/ExpanderClusters/ExpanderClusters.test.tsx deleted file mode 100644 index fd72cb5bc..000000000 --- a/packages/teleterm/src/ui/Navigator/ExpanderClusters/ExpanderClusters.test.tsx +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Copyright 2022 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. - */ - -/* eslint-disable jest/no-commented-out-tests */ - -import React from 'react'; -import { fireEvent, render } from 'design/utils/testing'; -import { ExpanderClustersPresentational } from './ExpanderClusters'; -import { ExpanderClusterState } from './types'; -import { MockAppContextProvider } from 'teleterm/ui/fixtures/MockAppContextProvider'; - -test.skip('should render simple and trusted clusters', () => { - const state: ExpanderClusterState = { - onAddCluster() {}, - onSyncClusters() {}, - onOpenContextMenu() {}, - onOpen() {}, - items: [ - { - clusterUri: 'test-uri', - title: 'Test title', - connected: false, - syncing: false, - active: false, - leaves: [ - { - clusterUri: 'trusted-cluster-test-uri', - title: 'Trusted cluster', - syncing: false, - connected: false, - active: false, - }, - ], - }, - ], - }; - - const { getByText } = render( - - - - ); - - expect(getByText(state.items[0].title)).toBeInTheDocument(); - expect(getByText(state.items[0].leaves[0].title)).toBeInTheDocument(); -}); - -test.skip('should invoke callback when context menu is clicked', () => { - const state: ExpanderClusterState = { - onAddCluster() {}, - onSyncClusters() {}, - onOpenContextMenu: jest.fn(), - onOpen() {}, - items: [ - { - clusterUri: 'test-uri', - title: 'Test title', - connected: false, - syncing: false, - active: false, - }, - ], - }; - - const { getByText } = render( - - - - ); - - fireEvent.contextMenu(getByText(state.items[0].title)); - expect(state.onOpenContextMenu).toHaveBeenCalledWith(state.items[0]); -}); - -/* -test('should invoke callback when remove button is clicked', () => { - const handleRemove = jest.fn(); - - const items: ClusterNavItem[] = [ - { uri: 'test-uri', title: 'Test title', connected: false, syncing: false }, - ]; - const { getByTitle } = render( - - - - ); - - const removeButton = getByTitle('Remove'); - expect(removeButton).toBeInTheDocument(); - - fireEvent.click(removeButton); - expect(handleRemove).toHaveBeenCalledWith(items[0].uri); -}); - -test('should invoke callback when add button is clicked', () => { - const handleAdd = jest.fn(); - - const { getByTitle } = render( - - - - ); - - const addButton = getByTitle('Add cluster'); - expect(addButton).toBeInTheDocument(); - - fireEvent.click(addButton); - expect(handleAdd).toHaveBeenCalledWith(); -}); - -test('should invoke callback when sync button is clicked', () => { - const handleSync = jest.fn(); - - const { getByTitle } = render( - - - - ); - - const syncButton = getByTitle('Sync clusters'); - expect(syncButton).toBeInTheDocument(); - - fireEvent.click(syncButton); - expect(handleSync).toHaveBeenCalledWith(); -}); -*/ diff --git a/packages/teleterm/src/ui/Navigator/ExpanderClusters/ExpanderClusters.tsx b/packages/teleterm/src/ui/Navigator/ExpanderClusters/ExpanderClusters.tsx deleted file mode 100644 index e14ff3c7c..000000000 --- a/packages/teleterm/src/ui/Navigator/ExpanderClusters/ExpanderClusters.tsx +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright 2019 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 { Flex, Text, ButtonIcon, Box } from 'design'; -import { Restore, Add } from 'design/Icon'; -import Expander, { ExpanderHeader, ExpanderContent } from './../Expander'; -import { useExpanderClusters } from './useExpanderClusters'; -// import { ExpanderClusterItem } from '../../Identity/ExpanderClusterItem'; -import { ExpanderClusterState } from './types'; - -export function ExpanderClusters() { - const state = useExpanderClusters(); - return ; -} - -export function ExpanderClustersPresentational(props: ExpanderClusterState) { - const { items, onSyncClusters, onAddCluster, onOpen, onOpenContextMenu } = - props; - - const handleSyncClick = (e: React.BaseSyntheticEvent) => { - e.stopPropagation(); - onSyncClusters?.(); - }; - - const handleAddClick = (e: React.BaseSyntheticEvent) => { - e.stopPropagation(); - onAddCluster?.(); - }; - - // const $clustersItems = items.map(i => ( - // onOpenContextMenu?.(i)} - // /> - // )); - - return ( - - - - - Clusters - - - - - - - - - - - - - {/*{$clustersItems}*/} - - - ); -} diff --git a/packages/teleterm/src/ui/Navigator/ExpanderClusters/index.ts b/packages/teleterm/src/ui/Navigator/ExpanderClusters/index.ts deleted file mode 100644 index bf33b0fe2..000000000 --- a/packages/teleterm/src/ui/Navigator/ExpanderClusters/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* -Copyright 2019 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. -*/ - -export { ExpanderClusters } from './ExpanderClusters'; diff --git a/packages/teleterm/src/ui/Navigator/ExpanderClusters/types.ts b/packages/teleterm/src/ui/Navigator/ExpanderClusters/types.ts deleted file mode 100644 index 621ccc011..000000000 --- a/packages/teleterm/src/ui/Navigator/ExpanderClusters/types.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright 2022 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 { NavItem } from 'teleterm/ui/Navigator/types'; - -export interface ClusterNavItem extends NavItem { - connected: boolean; - syncing: boolean; - leaves?: ClusterNavItem[]; - clusterUri: string; - active: boolean; -} - -export interface ExpanderClusterState { - items: ClusterNavItem[]; - onAddCluster?(): void; - onSyncClusters?(): void; - onOpenContextMenu?(item: ClusterNavItem): void; - onOpen(clusterUri: string): void; -} diff --git a/packages/teleterm/src/ui/Navigator/ExpanderClusters/useExpanderClusters.ts b/packages/teleterm/src/ui/Navigator/ExpanderClusters/useExpanderClusters.ts deleted file mode 100644 index 97bcee925..000000000 --- a/packages/teleterm/src/ui/Navigator/ExpanderClusters/useExpanderClusters.ts +++ /dev/null @@ -1,113 +0,0 @@ -/* -Copyright 2019 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 { useAppContext } from 'teleterm/ui/appContextProvider'; -import AppContext from 'teleterm/ui/appContext'; -import { ExpanderClusterState, ClusterNavItem } from './types'; - -export function useExpanderClusters(): ExpanderClusterState { - const ctx = useAppContext(); - const items = initItems(ctx); - - // subscribe - ctx.clustersService.useState(); - - function onAddCluster() { - ctx.commandLauncher.executeCommand('cluster-connect', {}); - } - - function onSyncClusters() { - ctx.clustersService.syncRootClusters(); - } - - function onLogin(clusterUri: string) { - ctx.commandLauncher.executeCommand('cluster-connect', { clusterUri }); - } - - function onLogout(clusterUri: string) { - ctx.clustersService.logout(clusterUri); - } - - function onOpen(clusterUri: string) { - ctx.commandLauncher.executeCommand('cluster-open', { clusterUri }); - } - - function onRemove(clusterUri: string) { - ctx.commandLauncher.executeCommand('cluster-remove', { clusterUri }); - } - - function onOpenContextMenu(navItem: ClusterNavItem) { - ctx.mainProcessClient.openClusterContextMenu({ - isClusterConnected: navItem.connected, - onLogin() { - onLogin(navItem.clusterUri); - }, - onLogout() { - onLogout(navItem.clusterUri); - }, - onRemove() { - onRemove(navItem.clusterUri); - }, - onRefresh() { - ctx.clustersService.syncRootCluster(navItem.clusterUri); - }, - }); - } - - return { - items, - onAddCluster, - onOpenContextMenu, - onSyncClusters, - onOpen, - }; -} - -function initItems(ctx: AppContext): ClusterNavItem[] { - function findLeaves(clusterUri: string) { - return ctx.clustersService - .getClusters() - .filter(c => c.leaf && c.uri.startsWith(clusterUri)) - .map(cluster => { - return { - active: ctx.workspacesService - .getActiveWorkspaceDocumentService() - .isClusterDocumentActive(cluster.uri), - clusterUri: cluster.uri, - title: cluster.name, - connected: true, - syncing: false, - }; - }); - } - - return ctx.clustersService - .getClusters() - .filter(c => !c.leaf) - .map(cluster => { - const { syncing } = ctx.clustersService.getClusterSyncStatus(cluster.uri); - return { - active: ctx.workspacesService - .getActiveWorkspaceDocumentService() - .isClusterDocumentActive(cluster.uri), - title: cluster.name, - clusterUri: cluster.uri, - connected: cluster.connected, - syncing: syncing, - leaves: cluster.connected ? findLeaves(cluster.uri) : [], - }; - }); -} diff --git a/packages/teleterm/src/ui/Navigator/Navigator.story.tsx b/packages/teleterm/src/ui/Navigator/Navigator.story.tsx deleted file mode 100644 index 5b85b362b..000000000 --- a/packages/teleterm/src/ui/Navigator/Navigator.story.tsx +++ /dev/null @@ -1,111 +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 AppContextProvider from 'teleterm/ui/appContextProvider'; -import { Navigator } from './Navigator'; -import { MockAppContext } from 'teleterm/ui/fixtures/mocks'; -import { SyncStatus } from 'teleterm/ui/services/clusters/types'; -import styled from 'styled-components'; - -export default { - title: 'Teleterm/Navigator', -}; - -export const Story = () => { - const appContext = new MockAppContext(); - - appContext.statePersistenceService.getConnectionTrackerState = () => { - return { - connections: [ - { - connected: true, - kind: 'connection.server', - title: 'graves', - id: 'morris', - serverUri: 'brock', - login: 'casey', - clusterUri: '', - }, - { - connected: true, - kind: 'connection.gateway', - title: 'graves', - id: 'morris', - targetUri: 'brock', - port: '22', - gatewayUri: 'empty', - clusterUri: '' - }, - ], - }; - }; - - appContext.clustersService.getClusterSyncStatus = () => { - const loading: SyncStatus = { status: 'processing' }; - const error: SyncStatus = { status: 'failed', statusText: 'Server Error' }; - return { - syncing: true, - dbs: error, - servers: loading, - apps: loading, - kubes: loading, - }; - }; - - appContext.clustersService.getClusters = () => [ - { - uri: 'clusters/localhost', - leaf: false, - name: 'localhost', - connected: true, - }, - { - uri: 'clusters/example-host', - leaf: false, - name: 'example-host', - connected: true, - }, - ]; - - return ( - - - - - - ); -}; - -export function NoData() { - const appContext = new MockAppContext(); - appContext.clustersService.getClusters = () => []; - - return ( - - - - - - ); -} - -const Container = styled.div` - background: white; - max-width: 300px; - max-height: 700px; - overflow: auto; -`; diff --git a/packages/teleterm/src/ui/Navigator/Navigator.tsx b/packages/teleterm/src/ui/Navigator/Navigator.tsx deleted file mode 100644 index 1150eb89a..000000000 --- a/packages/teleterm/src/ui/Navigator/Navigator.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* -Copyright 2019 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 styled from 'styled-components'; -import { Box, Text } from 'design'; - -export function Navigator() { - return ( - - ); -} - -const Nav = styled(Box)` - display: flex; - flex-direction: column; - height: 100%; - user-select: none; -`; - -const Scrollable = styled(Box)` - height: 100%; - overflow: auto; -`; - -const Separator = styled.div` - background: ${props => props.theme.colors.primary.lighter}; - height: 1px; -`; diff --git a/packages/teleterm/src/ui/Navigator/index.ts b/packages/teleterm/src/ui/Navigator/index.ts deleted file mode 100644 index d9df71873..000000000 --- a/packages/teleterm/src/ui/Navigator/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* -Copyright 2019 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. -*/ - -export { Navigator } from './Navigator'; diff --git a/packages/teleterm/src/ui/Navigator/types.ts b/packages/teleterm/src/ui/Navigator/types.ts deleted file mode 100644 index c3039c25c..000000000 --- a/packages/teleterm/src/ui/Navigator/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { FC } from 'react'; - -export interface NavItem { - title: string; - uri?: string; - Icon?: FC; -} diff --git a/packages/teleterm/src/ui/QuickInput/QuickInputList/QuickInputList.tsx b/packages/teleterm/src/ui/QuickInput/QuickInputList/QuickInputList.tsx index a2b3c74fb..9d79524fc 100644 --- a/packages/teleterm/src/ui/QuickInput/QuickInputList/QuickInputList.tsx +++ b/packages/teleterm/src/ui/QuickInput/QuickInputList/QuickInputList.tsx @@ -16,10 +16,10 @@ limitations under the License. import React, { useEffect, useRef } from 'react'; import styled from 'styled-components'; -import { Box, Flex, Label } from 'design'; +import { Box, Flex, Label, Text } from 'design'; import { makeLabelTag } from 'teleport/components/formatters'; import * as types from 'teleterm/ui/services/quickInput/types'; -import { Cli, Server, Person } from 'design/Icon'; +import { Cli, Server, Person, Database } from 'design/Icon'; const QuickInputList = React.forwardRef((props, ref) => { const activeItemRef = useRef(); @@ -114,6 +114,34 @@ function ServerItem(props: { item: types.SuggestionServer }) { ); } +function DatabaseItem(props: { item: types.SuggestionDatabase }) { + const db = props.item.data; + const $labels = db.labelsList.map((label, index) => ( + + )); + + return ( + + + + + + + {db.name} + + + {db.type}/{db.protocol} + + + + {$labels} + + + ); +} + function UnknownItem(props: { item: types.Suggestion }) { const { kind } = props.item; return
unknown kind: {kind}
; @@ -163,6 +191,7 @@ const ComponentMap: Record< ['suggestion.cmd']: CmdItem, ['suggestion.ssh-login']: SshLoginItem, ['suggestion.server']: ServerItem, + ['suggestion.database']: DatabaseItem, }; type Props = { diff --git a/packages/teleterm/src/ui/QuickInput/useQuickInput.ts b/packages/teleterm/src/ui/QuickInput/useQuickInput.ts index 5a3319678..7a63ad3de 100644 --- a/packages/teleterm/src/ui/QuickInput/useQuickInput.ts +++ b/packages/teleterm/src/ui/QuickInput/useQuickInput.ts @@ -23,12 +23,8 @@ import { } from 'teleterm/ui/services/quickInput/types'; export default function useQuickInput() { - const { - quickInputService, - workspacesService, - clustersService, - commandLauncher, - } = useAppContext(); + const { quickInputService, workspacesService, commandLauncher } = + useAppContext(); workspacesService.useState(); const documentsService = workspacesService.getActiveWorkspaceDocumentService(); @@ -36,7 +32,9 @@ export default function useQuickInput() { const [activeSuggestion, setActiveSuggestion] = React.useState(0); const autocompleteResult = React.useMemo( () => quickInputService.getAutocompleteResult(inputValue), - [inputValue] + // `localClusterUri` has been added to refresh suggestions from + // `QuickSshLoginPicker` and `QuickServerPicker` when it changes + [inputValue, workspacesService.getActiveWorkspace()?.localClusterUri] ); const hasSuggestions = autocompleteResult.kind === 'autocomplete.partial-match'; @@ -113,7 +111,7 @@ export default function useQuickInput() { }; useKeyboardShortcuts({ - 'focus-global-search': () => { + 'open-quick-input': () => { quickInputService.show(); }, }); 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} - - - - -