diff --git a/src/Explorer/Tabs/CloudShellTab/CloudShellTabComponent.tsx b/src/Explorer/Tabs/CloudShellTab/CloudShellTabComponent.tsx index cae33e705..23979a21f 100644 --- a/src/Explorer/Tabs/CloudShellTab/CloudShellTabComponent.tsx +++ b/src/Explorer/Tabs/CloudShellTab/CloudShellTabComponent.tsx @@ -22,7 +22,7 @@ export const CloudShellTerminalComponent: React.FC = ({ const term = new Terminal({ cursorBlink: true, cursorStyle: 'bar', - fontFamily: 'Courier New, monospace', + fontFamily: 'monospace', fontSize: 14, theme: { background: "#1e1e1e", @@ -38,18 +38,6 @@ export const CloudShellTerminalComponent: React.FC = ({ if (terminalRef.current) { term.open(terminalRef.current); xtermRef.current = term; - - // Ensure the CSS is injected only once - if (!document.getElementById("xterm-custom-style")) { - const style = document.createElement("style"); - style.id = "xterm-custom-style"; // Unique ID to prevent duplicates - style.innerHTML = ` - .xterm-text-layer { - transform: translateX(10px); /* Adds left padding */ - } - `; - document.head.appendChild(style); - } } if (fitAddon) { @@ -76,11 +64,6 @@ export const CloudShellTerminalComponent: React.FC = ({ } window.removeEventListener('resize', handleResize); term.dispose(); // Clean up XTerm instance - - const styleElement = document.getElementById("xterm-custom-style"); - if (styleElement) { - styleElement.remove(); // Clean up CSS on unmount - } }; }, []); diff --git a/src/Explorer/Tabs/CloudShellTab/Commands.tsx b/src/Explorer/Tabs/CloudShellTab/Commands.tsx index 8eb8f913e..85ca83767 100644 --- a/src/Explorer/Tabs/CloudShellTab/Commands.tsx +++ b/src/Explorer/Tabs/CloudShellTab/Commands.tsx @@ -108,8 +108,8 @@ export const commands = (terminalKind: TerminalKind, config?: CommandConfig): st "source ~/.bashrc", // 8. Verify mongosh installation "mongosh --version", - // 9. Login to MongoDBmongosh mongodb+srv://@neesharma-stage-mongo-vcore.mongocluster.cosmos.azure.com/?authMechanism=SCRAM-SHA-256&retrywrites=false&maxIdleTimeMS=120000\u0007 - `mongosh "mongodb+srv://nrj:@${config.endpoint}/?authMechanism=SCRAM-SHA-256&retrywrites=false&maxIdleTimeMS=120000" --tls --tlsAllowInvalidCertificates` + // 10. Login to MongoDBmongosh mongodb+srv://@neesharma-stage-mongo-vcore.mongocluster.cosmos.azure.com/?authMechanism=SCRAM-SHA-256&retrywrites=false&maxIdleTimeMS=120000\u0007 + `read -p "Enter username: " username && mongosh "mongodb+srv://$username:@${config.endpoint}/?authMechanism=SCRAM-SHA-256&retrywrites=false&maxIdleTimeMS=120000" --tls --tlsAllowInvalidCertificates` ]; case TerminalKind.Cassandra: return [ diff --git a/src/Explorer/Tabs/CloudShellTab/Data.tsx b/src/Explorer/Tabs/CloudShellTab/Data.tsx index 5f011735f..25564d034 100644 --- a/src/Explorer/Tabs/CloudShellTab/Data.tsx +++ b/src/Explorer/Tabs/CloudShellTab/Data.tsx @@ -52,7 +52,6 @@ export const getUserSettings = async (): Promise => { apiVersion: "2023-02-01-preview" }); - console.log(resp); return resp; }; @@ -69,16 +68,13 @@ export const putEphemeralUserSettings = async (userSubscriptionId: string, userR } }; - const resp = await armRequest({ + return await armRequest({ host: configContext.ARM_ENDPOINT, path: `/providers/Microsoft.Portal/userSettings/cloudconsole`, method: "PUT", apiVersion: "2023-02-01-preview", body: ephemeralSettings }); - - return resp; - }; export const verifyCloudShellProviderRegistration = async(subscriptionId: string) => { diff --git a/src/Explorer/Tabs/CloudShellTab/DataModels.tsx b/src/Explorer/Tabs/CloudShellTab/DataModels.tsx index 6dffbeaf7..dcf07e91f 100644 --- a/src/Explorer/Tabs/CloudShellTab/DataModels.tsx +++ b/src/Explorer/Tabs/CloudShellTab/DataModels.tsx @@ -23,6 +23,12 @@ export const enum SessionType { Ephemeral = "Ephemeral" } +export const enum UserInputs { + NoReset = "1", + ConfigureVNet = "2", + ResetVNet = "3" +}; + export type Settings = { properties: UserSettingProperties }; diff --git a/src/Explorer/Tabs/CloudShellTab/UseTerminal.tsx b/src/Explorer/Tabs/CloudShellTab/UseTerminal.tsx index b0983ccbc..9135e9f7d 100644 --- a/src/Explorer/Tabs/CloudShellTab/UseTerminal.tsx +++ b/src/Explorer/Tabs/CloudShellTab/UseTerminal.tsx @@ -2,7 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. */ -import { RelayNamespaceResponse, VnetModel, VnetSettings } from "Explorer/Tabs/CloudShellTab/DataModels"; +import { RelayNamespaceResponse, UserInputs, VnetModel, VnetSettings } from "Explorer/Tabs/CloudShellTab/DataModels"; import { listKeys } from "Utils/arm/generatedClients/cosmos/databaseAccounts"; import { Terminal } from "xterm"; import { TerminalKind } from "../../../Contracts/ViewModels"; @@ -16,18 +16,7 @@ export const startCloudShellTerminal = async (terminal: Terminal, shellType: Ter // validate that the subscription id is registered in the CloudShell namespace terminal.writeln(""); - try { - terminal.writeln("\x1B[34mVerifying CloudShell provider registration...\x1B[0m"); - const response: any = await verifyCloudShellProviderRegistration(userContext.subscriptionId); - if (response.registrationState !== "Registered") { - terminal.writeln("\x1B[33mCloudShell provider registration is not found. Registering now...\x1B[0m"); - await registerCloudShellProvider(userContext.subscriptionId); - terminal.writeln("\x1B[32mCloudShell provider registration completed successfully.\x1B[0m"); - } - } catch (err) { - terminal.writeln("\x1B[31mError: Unable to verify CloudShell provider registration.\x1B[0m"); - throw err; - } + await ensureCloudShellRegistration(terminal); terminal.writeln(""); terminal.writeln("\x1B[34mFetching user settings...\x1B[0m"); @@ -68,14 +57,13 @@ export const startCloudShellTerminal = async (terminal: Terminal, shellType: Ter terminal.focus(); - let isDefaultSetting = false; const handleKeyPress = terminal.onKey(async ({ key }: { key: string }) => { terminal.writeln("") - if (key === "1") { + if (key === UserInputs.NoReset) { terminal.writeln("\x1B[34mYou selected option 1: Proceeding with current/default settings.\x1B[0m"); handleKeyPress.dispose(); } - else if (key === "2") { + else if (key === UserInputs.ConfigureVNet) { terminal.writeln("\x1B[34mYou selected option 2: Please provide the following details.\x1B[0m"); handleKeyPress.dispose(); @@ -118,7 +106,7 @@ export const startCloudShellTerminal = async (terminal: Terminal, shellType: Ter location: vNetConfig.location }; } - else if (key === "3") { + else if (key === UserInputs.ResetVNet) { terminal.writeln("\x1B[34mYou selected option 3: Resetting VNet settings to default.\x1B[0m"); vNetSettings = {}; @@ -346,26 +334,38 @@ const provisionCloudShellSession = async( return reject(err); } - // trigger callback to provision console internal let provisionConsoleResponse; - try { - provisionConsoleResponse = await provisionConsole(userContext.subscriptionId, resolvedRegion); - } catch (err) { - terminal.writeln(LogError('Unable to provision console.')); - return reject(err); + const retryCount = 3; + for (let i = 0; i < retryCount; i++) { + terminal.writeln(`\x1B[34mAttempting to provision console (Attempt ${i + 1}/${retryCount})...\x1B[0m`); + // trigger callback to provision console internal + try { + provisionConsoleResponse = await provisionConsole(userContext.subscriptionId, resolvedRegion); + } catch (err) { + terminal.writeln(LogError('Unable to provision console.')); + return reject(err); + } + + // Add check for provisioning state + if (provisionConsoleResponse.properties.provisioningState !== "Succeeded") { + await wait(5000); + } + else { + break; + } } - // Add check for provisioning state + // Add check for provisioning state if (provisionConsoleResponse.properties.provisioningState !== "Succeeded") { - terminal.writeln(LogError("Failed to provision console.")); - return reject(new Error("Failed to provision console.")); + terminal.writeln(`\x1B[1;31mUnable to provision, Provisioning state: ${provisionConsoleResponse.properties.provisioningState}\x1B[0m`); + return reject(new Error("Unable to provision, Provisioning state: ${provisionConsoleResponse.properties.provisioningState}")); } - + terminal.writeln("\x1B[34mConnecting to CloudShell Terminal...\x1B[0m"); // connect the terminal let connectTerminalResponse; try { - connectTerminalResponse = await connectTerminal(provisionConsoleResponse.properties.uri, { rows: terminal.rows, cols: terminal.cols }); + connectTerminalResponse = await connectTerminal(provisionConsoleResponse.properties.uri, { rows: terminal.rows, cols: terminal.cols}); } catch (err) { terminal.writeln(LogError(`Unable to connect terminal. ${err}`)); return reject(err); @@ -394,3 +394,21 @@ const provisionCloudShellSession = async( }); }); }; + +const ensureCloudShellRegistration = async(terminal: Terminal) => { + try { + terminal.writeln("\x1B[34mVerifying CloudShell provider registration...\x1B[0m"); + const response: any = await verifyCloudShellProviderRegistration(userContext.subscriptionId); + if (response.registrationState !== "Registered") { + terminal.writeln("\x1B[33mCloudShell provider registration is not found. Registering now...\x1B[0m"); + await registerCloudShellProvider(userContext.subscriptionId); + terminal.writeln("\x1B[32mCloudShell provider registration completed successfully.\x1B[0m"); + } + } catch (err) { + terminal.writeln("\x1B[31mError: Unable to verify CloudShell provider registration.\x1B[0m"); + throw err; + } +} + +const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); +